This file is a merged representation of a subset of the codebase, containing files not matching ignore patterns, combined into a single document by Repomix.
The content has been processed where comments have been removed, empty lines have been removed, content has been compressed (code blocks are separated by ⋮---- delimiter).

<file_summary>
This section contains a summary of this file.

<purpose>
This file contains a packed representation of a subset of the repository's contents that is considered the most important context.
It is designed to be easily consumable by AI systems for analysis, code review,
or other automated processes.
</purpose>

<file_format>
The content is organized as follows:
1. This summary section
2. Repository information
3. Directory structure
4. Repository files (if enabled)
5. Multiple file entries, each consisting of:
  - File path as an attribute
  - Full contents of the file
</file_format>

<usage_guidelines>
- This file should be treated as read-only. Any changes should be made to the
  original repository files, not this packed version.
- When processing this file, use the file path to distinguish
  between different files in the repository.
- Be aware that this file may contain sensitive information. Handle it with
  the same level of security as you would the original repository.
</usage_guidelines>

<notes>
- Some files may have been excluded based on .gitignore rules and Repomix's configuration
- Binary files are not included in this packed representation. Please refer to the Repository Structure section for a complete list of file paths, including binary files
- Files matching these patterns are excluded: **/.git/**, **/.github/**, **/node_modules/**, **/vendor/**, **/third_party/**, **/external/**, **/libs/**, **/lib/**, **/bin/**, **/obj/**, **/build/**, **/dist/**, **/target/**, **/out/**, **/release/**, **/debug/**, **/wwwroot/**, **/public/**, **/assets/**, **/static/**, **/[tT]est/**, **/[tT]ests/**, **/__tests__/**, **/[lL]ogs/**, **/[mM]igrations/**, **/.vs/**, **/.vscode/**, **/.idea/**, **/.pnpm-store/**, **/.yarn/**, **/.npm/**, **/__pycache__/**, **/.pytest_cache/**, **/.mypy_cache/**, **/.gradle/**, **/.mvn/**, **/coverage/**, **/.coverage/**, **/reports/**, **/report/**, **/TestResults/**, **/tmp/**, **/temp/**, **/.tmp/**, **/.cache/**, **/.history/**, **/.DS_Store, **/Thumbs.db, **/*.log, **/*.out, **/*.err, **/*.trace, **/*.trc, **/*.tmp, **/*.cache, **/*.dmp, **/*.dump, **/*.core, **/*.binlog, **/*.ndjson, **/*.jsonl, **/*.csv, **/*.evtx, **/*.etl, **/*.access, **/*.error, **/*.exe, **/*.dll, **/*.so, **/*.dylib, **/*.bin, **/*.app, **/*.msi, **/*.apk, **/*.ipa, **/*.lib, **/*.a, **/*.o, **/*.obj, **/*.lo, **/*.lai, **/*.class, **/*.jar, **/*.war, **/*.ear, **/*.pdb, **/*.idb, **/*.ilk, **/*.nupkg, **/*.snupkg, **/*.gem, **/*.whl, **/*.egg, **/*.deb, **/*.rpm, **/*.zip, **/*.tar, **/*.gz, **/*.tgz, **/*.rar, **/*.bz2, **/*.xz, **/*.7z, **/*.lz, **/*.lzma, **/*.min.js, **/*.min.css, **/*.map, **/*.css, **/*.scss, **/*.sass, **/*.less, **/*.jpg, **/*.jpeg, **/*.png, **/*.gif, **/*.bmp, **/*.tif, **/*.tiff, **/*.webp, **/*.heif, **/*.heic, **/*.svg, **/*.eps, **/*.ai, **/*.raw, **/*.cr2, **/*.cr3, **/*.nef, **/*.arw, **/*.dng, **/*.orf, **/*.rw2, **/*.avif, **/*.apng, **/*.ico, **/*.psd, **/*.psb, **/*.xcf, **/*.hdr, **/*.exr, **/*.dcm, **/*.dicom, **/*.fits, **/*.ppm, **/*.pgm, **/*.pbm, **/*.j2k, **/*.jp2, **/*.pcx, **/*.tga, **/*.iff, **/*.sgi, **/*.ras, **/*.coverage, **/*.lcov, **/*.gcov, **/*.gcda, **/*.gcno, **/*.generated, **/*.g.cs, **/*.designer.cs, **/*.lock, **/*.lock.json, **/*.eot, **/*.ttf, **/*.woff, **/*.woff2, **/*.pfx, **/*.p12, **/*.cer, **/*.crt, **/*.key, **/*.editorconfig, **/*.tool-versions, **/*.onnx, **/*.pt, **/*.pth, **/*.h5, **/*.ckpt, **/*.sln, **/*.csproj, **/*.config, **/*.user, **/*.vsidx, **/*.v2, **/*.db*, **/.*ignore, **/.git*, **/*.config.*, **/Makefile*, **/*.mk, **/BUILD, **/*.bzl, **/pom.xml, **/build.gradle*, **/gradlew*, **/gradle/**, **/CMakeLists.txt, **/*.cmake, **/.idea/**, **/.vscode/**, **/.eclipse/**, **/.settings/**, **/gen/**, **/generated/**, **/auto/**, **/out/**, **/dist/**, **/.dist/**, **/node_modules/**, **/vendor/**, **/vendor-prefixed/**, **/schemas/**, **/bundles/**, **/configs/**, **/*.lock, **/*.dist, **/*.sample, **/*.patch
- Files matching patterns in .gitignore are excluded
- Files matching default ignore patterns are excluded
- Code comments have been removed from supported file types
- Empty lines have been removed from all files
- Content has been compressed - code blocks are separated by ⋮---- delimiter
- Files are sorted by Git change count (files with more changes are at the bottom)
</notes>

</file_summary>

<directory_structure>
.claude/
  settings.json
.cursor/
  rules/
    avoid-regex.mdc
    code-quality.mdc
    generate-pr-description.mdc
    git.mdc
    woo-build.mdc
    woo-phpunit.mdc
.husky/
  post-checkout
  post-merge
  pre-commit
  pre-push
.linear/
  release-kickoff-beta.md
  release-kickoff-patch.md
  release-kickoff-rc.md
  release-kickoff.md
docs/
  _docu-tools/
    consent-plugin/
      gtag.ts
      index.ts
    llms-txt/
      index.ts
    src/
      components/
        CookieBanner/
          index.tsx
        HomepageFeatures/
          index.tsx
        MarkdownCopy/
          index.tsx
      js/
        sidebar-filters.js
      theme/
        MDXContent/
          index.tsx
        Root.js
    utils/
      docusaurus-faster.deploy.config.js
      docusaurus.deploy.config.js
    docusaurus.config.ts
    package.json
    README.md
    sidebars.ts
    tsconfig.json
  apis/
    dual-api/
      _category_.json
      README.md
    rest-api/
      v1/
        _category_.json
        coupons.mdx
        customers.mdx
        index.mdx
        order-notes.mdx
        order-refunds.mdx
        orders.mdx
        product-attribute-terms.mdx
        product-attributes.mdx
        product-categories.mdx
        product-shipping-classes.mdx
        product-tags.mdx
        products.mdx
        reports.mdx
        tax-classes.mdx
        taxes.mdx
        webhooks.mdx
      v2/
        _category_.json
        coupons.mdx
        customers.mdx
        index.mdx
        order-notes.mdx
        order-refunds.mdx
        orders.mdx
        payment-gateways.mdx
        product-attribute-terms.mdx
        product-attributes.mdx
        product-categories.mdx
        product-shipping-classes.mdx
        product-tags.mdx
        product-variations.mdx
        products.mdx
        reports.mdx
        setting-options.mdx
        settings.mdx
        shipping-methods.mdx
        shipping-zone-locations.mdx
        shipping-zone-methods.mdx
        shipping-zones.mdx
        system-status-tools.mdx
        system-status.mdx
        tax-classes.mdx
        taxes.mdx
        webhooks.mdx
      v3/
        _category_.json
        api-reference.mdx
        coupons.mdx
        customers.mdx
        data.mdx
        index.mdx
        order-actions.mdx
        order-notes.mdx
        order-refunds.mdx
        orders.mdx
        payment-gateways.mdx
        product-attribute-terms.mdx
        product-attributes.mdx
        product-categories.mdx
        product-custom-fields.mdx
        product-reviews.mdx
        product-shipping-classes.mdx
        product-tags.mdx
        product-variations.mdx
        products.mdx
        refunds.mdx
        reports.mdx
        setting-options.mdx
        settings.mdx
        shipping-methods.mdx
        shipping-zone-locations.mdx
        shipping-zone-methods.mdx
        shipping-zones.mdx
        system-status-tools.mdx
        system-status.mdx
        tax-classes.mdx
        taxes.mdx
        webhooks.mdx
      _category_.json
      authentication.mdx
      index.mdx
    store-api/
      extending-store-api/
        available-endpoints-to-extend.md
        extend-store-api-add-custom-fields.md
        extend-store-api-add-data.md
        extend-store-api-formatters.md
        extend-store-api-update-cart.md
        README.md
      resources-endpoints/
        _category_.json
        cart-coupons.md
        cart-items.md
        cart.md
        checkout-order.md
        checkout.md
        order.md
        product-attribute-terms.md
        product-attributes.md
        product-brands.md
        product-categories.md
        product-collection-data.md
        product-reviews.md
        product-tags.md
        products.md
      cart-tokens.md
      guiding-principles.md
      nonce-tokens.md
      rate-limiting.md
      README.md
    _category_.json
    README.md
  best-practices/
    coding-standards/
      coding-standards.md
      css-sass-naming-conventions.md
      grammar-punctuation-capitalization.md
      naming-conventions.md
    data-management/
      _category_.json
      crud-objects.md
      data-storage.md
      data-stores.md
      logging.md
    performance/
      _category_.json
      configuring-caching-plugins.md
      performance-best-practices.md
      performance-optimization.md
    security/
      _category_.json
      prevent-data-leaks.md
      security-best-practices.md
    urls-and-routing/
      _category_.json
      checkout-urls.md
      customizing-endpoint-urls.md
      removing-product-product-category-or-shop-from-the-url.md
      webhooks.md
      woocommerce-endpoints.md
    _category_.json
  block-development/
    extensible-blocks/
      cart-and-checkout-blocks/
        checkout-payment-methods/
          _category_.json
          checkout-flow-and-events.md
          filtering-payment-methods.md
          payment-method-integration.md
        filters-in-cart-and-checkout/
          _category_.json
          additional-cart-checkout-inner-block-types.md
          cart-line-items.md
          checkout-and-place-order-button.md
          coupons.md
          order-summary-items.md
          README.md
          totals-footer-item.md
        _category_.json
        additional-checkout-fields.md
        available-slot-fills.md
        checkout-utilities.md
        dom-events.md
        how-checkout-processes-an-order.md
        README.md
        removing-checkout-fields.md
      product-collection-block/
        _category_.json
        dom-events.md
        README.md
        register-product-collection.md
      product-sale-badge-block/
        _category_.json
        README.md
      _category_.json
    getting-started/
      _category_.json
      extensibility-overview.md
      faq.md
    reference/
      data-store/
        cart.md
        checkout.md
        collections.md
        payment.md
        query-state.md
        README.md
        schema.md
        store-notices.md
        validation.md
      hooks/
        hook-alternatives.md
        migrated-hooks.md
        README.md
      _category_.json
      block-references.md
      integration-interface.md
      overview-of-data-flow.md
      slot-fills.md
    tutorials/
      _category_.json
      how-to-additional-checkout-fields-guide.md
      how-to-conditional-additional-fields.md
      integrating-protection-checkout-block.md
    _category_.json
    README.md
  code-snippets/
    _category_.json
    add-a-country.md
    add-a-currency-symbol.md
    add-or-modify-states.md
    adjust-quantity-input-values.md
    before-login--register-form.md
    change-a-currency-symbol.md
    check_payment_method_support.md
    configuring_special_tax_scenarios.md
    customising-checkout-fields.md
    customize-failed-order-message.md
    disabling_marketplace_suggestions_programmatically.md
    displaying_custom_fields_in_your_theme_or_site.md
    free_shipping_customization.md
    legacy_local_pickup_advanced_settings_and_customization.md
    link-to-logged-data.md
    making_translations_upgrade_safe.md
    number-of-products-per-row.md
    override-loop-template-show-quantities-next-add-cart.md
    prevent-po-box-addresses-in-checkout-block.md
    README.md
    rename-a-country.md
    ssl_and_https_and_woocommerce_websites_behind_load_balanacers_or_reverse_proxies.md
    unhook--remove-woocommerce-emails.md
    uninstall_remove_all_woocommerce_data.md
    useful-functions.md
    using_nginx_server_to_protect_your_uploads_directory.md
  contribution/
    contributing/
      common-issues.md
      community-contributions.md
      CSS-SASS-coding-guidelines-and-naming-conventions.md
      deciding-pr-high-impact.md
      deprecation-in-core.md
      minification-of-SCSS-and-JS.md
      naming-conventions.md
      README.md
      reporting-security-issues.md
      string-localisation-guidelines.md
      version-support-policy.md
      woocommerce-git-flow.md
    contributing-docs/
      contributing-docs.md
      style-guide.md
    releases/
      backporting.md
      building-and-publishing.md
      decision-matrix.md
      monitoring.md
      package-releases.md
      point-releases.md
      prereleases.md
      readiness.md
      README.md
      schedule.md
      security-support.md
      troubleshooting.md
      workflows.md
    testing/
      beta-testing.md
      core-critical-flows.md
      README.md
      writing-high-quality-testing-instructions.md
    _category_.json
  extensions/
    best-practices-extensions/
      _category_.json
      accessibility.md
      compatibility.md
      extension-development-best-practices.md
      gdpr-compliance.md
      privacy-standards.md
      support-and-documentation.md
    core-concepts/
      _category_.json
      adding-actions-and-filters.md
      changelog-txt.md
      check-if-woo-is-active.md
      class-reference.md
      example-header-plugin-comment.md
      handling-deactivation-and-uninstallation.md
      maintainability.md
      README.md
      woocommerce-plugin-api-callback.md
    extension-onboarding/
      _category_.json
      adding-custom-products-to-add-products-onboarding-list.md
      creating-custom-product-tours.md
      handling-merchant-onboarding.md
      integrating-coming-soon-mode.md
    getting-started-extensions/
      _category_.json
      building-your-first-extension.md
      how-to-design-a-simple-extension.md
      README.md
    review-guidelines/
      how-to-request-reviews.md
      misc-guidelines.md
      notifying-users-about-important-events.md
      README.md
      responding-to-negative-reviews.md
      utilizing-feature-requests.md
      utilizing-your-support-team.md
      when-to-request-reviews.md
    settings-and-config/
      _category_.json
      adding-a-section-to-a-settings-tab.md
      extend-wc-settings-page.md
      how-to-add-your-own-store-management-links.md
      implementing-settings.md
      README.md
      registering-settings-ui-components.md
      settings-api.md
      settings-ui.md
      working-with-woocommerce-admin-pages.md
    ux-guidelines-extensions/
      _category_.json
      accessibility.md
      best-practices.md
      colors.md
      navigation.md
      notices.md
      onboarding.md
      README.md
      settings.md
      task-list-and-inbox.md
      testing.md
    _category_.json
  features/
    analytics/
      _category_.json
      adding-columns-to-analytics-reports-and-csv-downloads.md
      extending-woocommerce-admin-reports.md
    email/
      _category_.json
      email-editor-integration.md
      email-editor-logging.md
      email-html-best-practices.md
      email-preview.md
    mcp/
      _category_.json
      README.md
    orders/
      high-performance-order-storage/
        _category_.json
        cli-tools.md
        enable-hpos.md
        guide-large-store.md
        README.md
        recipe-book.md
        wc-order-query-improvements.md
      _category_.json
      wc-get-orders.md
    payments/
      ux-guidelines/
        _category_.json
        payment-button-layout.md
        payment-button-size.md
        payment-button-style.md
        payments-onboarding.md
        README.md
      _category_.json
      payment-gateway-api.md
      payment-gateway-plugin-base.md
      payment-token-api.md
    products/
      _category_.json
      adding-a-custom-field-to-variable-products.md
      wc-get-products.md
    shipping/
      _category_.json
      shipping-method-api.md
    _category_.json
    address-autocomplete.md
  getting-started/
    _category_.json
    ai.md
    debugging.md
    developer-tools.md
    development-environment.md
    project-structure.md
    README.md
    scaffolding.md
    tools-for-low-code-development.md
    version-control-deployment.md
  theming/
    block-theme-development/
      _category_.json
      cart-and-checkout.md
      css-styling.md
      theming-woo-blocks.md
    theme-development/
      _category_.json
      classic-theme-developer-handbook.md
      conditional-tags.md
      fixing-outdated-woocommerce-templates.md
      image-sizes.md
      set-up-a-child-theme.md
      template-structure.md
      theme-design-ux-guidelines.md
      thumbnail-image-regeneration.md
      using-custom-attributes-in-menus.md
    _category_.json
    theme-design.md
  wc-cli/
    wc-cli-commands/
      _category_.json
      README.md
      wc-blueprint.md
      wc-com.md
      wc-customer-download.md
      wc-customer.md
      wc-hpos.md
      wc-order-note.md
      wc-palt.md
      wc-payment-gateway.md
      wc-product-attribute-term.md
      wc-product-attribute.md
      wc-product-cat.md
      wc-product-review.md
      wc-product-shipping-class.md
      wc-product-tag.md
      wc-product-variation.md
      wc-product.md
      wc-setting.md
      wc-shipping-method.md
      wc-shipping-zone-location.md
      wc-shipping-zone-method.md
      wc-shipping-zone.md
      wc-shop-coupon.md
      wc-shop-order-refund.md
      wc-shop-order.md
      wc-tax-class.md
      wc-tax.md
      wc-tool.md
      wc-update.md
      wc-webhook-delivery.md
      wc-webhook.md
    _category_.json
    cli-faq.md
    cli-overview.md
    using-wc-cli.md
    wc-cli-examples.md
  woo-marketplace/
    _category_.json
    billing-api-saas.mdx
    content-style-guide.md
    excellence-verified-badge.md
    getting-started.md
    index.mdx
    managing-products.md
    managing-your-account.mdx
    monetization-expectations.md
    product-page-content-and-assets.mdx
    product-update-guidelines.md
    submitting-your-product.mdx
    support-guidelines.md
packages/
  js/
    admin-layout/
      changelog/
        .gitkeep
        consolidate-eslint-core-modules
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        components/
          LayoutContext/
            index.ts
            layout-context.tsx
          index.ts
        hooks/
          index.ts
          use-admin-sidebar-width.ts
        plugins/
          woo-footer-item/
            index.tsx
          woo-header-item/
            index.tsx
          woo-header-navigation-item/
            index.tsx
          woo-header-page-title/
            index.tsx
          index.ts
        index.ts
      .npmrc
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      package.json
      README.md
      tsconfig.json
      webpack.config.js
    block-templates/
      changelog/
        remove-product-block-editor-reference
    components/
      changelog/
        .gitkeep
        39772-search-wcsettings
        66078-dehoist-react
        66477-sprinkle-filter-picker-colon
        67634-35900-ip-search-bug
        consolidate-eslint-core-modules
        dev-eslint-no-floating-promises
        dev-migrate-advanced-filters-to-ts
        fix-37168-37169-form-state-updates
        fix-53727-rtl-dropdown-arrow
        fix-55817-rtl-pagination-arrows
        fix-form-setvalue-lodash-key-resolution
        fix-form-setvalue-zero-segment-name
        fix-select-control-inline-tag-alignment
        fix-wooplug-1016-ellipsis-menu-labels
        fix-wooplug-1941-tax-rate-filter-options
        woo6-109-storybook-10
        wooa7s-1541-downloads-customer-filter
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
        wooplug-929-settings-alias-docs
      src/
        abbreviated-card/
          stories/
            abbreviated-card.story.js
          index.js
          README.md
        advanced-filters/
          stories/
            advanced-filters.story.tsx
          attribute-filter.tsx
          date-filter.tsx
          index.tsx
          item.tsx
          number-filter.tsx
          README.md
          search-filter.tsx
          select-filter.tsx
          types.ts
          utils.ts
        analytics/
          error/
            stories/
              analytics-error.story.tsx
            index.js
            README.md
          index.js
        animation-slider/
          stories/
            animation-slider.story.js
          index.js
          README.md
        badge/
          stories/
            badge.story.tsx
          index.tsx
        calendar/
          stories/
            date-picker.story.js
            date-range.story.js
          date-picker.js
          date-range.js
          input.js
          phrases.js
          README.md
        chart/
          d3chart/
            d3base/
              index.js
              README.md
            utils/
              axis-x.js
              axis-y.js
              axis.js
              bar-chart.js
              breakpoints.js
              color.js
              index.js
              line-chart.js
              scales.js
              tooltip.js
            chart.js
            example.md
            index.js
            legend.js
          stories/
            chart.story.js
          constants.js
          index.js
          placeholder.js
          README.md
        collapsible-content/
          stories/
            collapsible-content.story.tsx
          collapsible-content.tsx
          index.tsx
        compare-filter/
          stories/
            compare-filter.story.js
          button.js
          index.js
          README.md
        conditional-wrapper/
          conditional-wrapper.tsx
          index.ts
        confetti-animation/
          index.ts
        date/
          stories/
            date.story.js
          index.js
          README.md
        date-range-filter-picker/
          stories/
            date-range-filter-picker.story.js
          compare-periods.js
          content.js
          index.js
          preset-periods.js
          README.md
        date-time-picker-control/
          stories/
            date-time-picker-control.story.tsx
          date-time-picker-control.tsx
          index.tsx
          README.md
        display-state/
          display-state.tsx
          index.ts
        dropdown-button/
          stories/
            index.story.js
          index.js
          README.md
        dynamic-form/
          field-types/
            field-checkbox.tsx
            field-password.tsx
            field-select.tsx
            field-text.tsx
            index.ts
          stories/
            index.story.js
          dynamic-form.tsx
          index.js
          README.md
          types.ts
        ellipsis-menu/
          stories/
            ellipsis-menu.story.js
          index.tsx
          menu-item.tsx
          menu-title.tsx
          README.md
        empty-content/
          stories/
            empty-content.story.js
          index.js
          README.md
        error-boundary/
          stories/
            error-boundary.story.tsx
          constants.ts
          index.tsx
        experimental-select-control/
          hooks/
            use-async-filter.tsx
          stories/
            select-control.story.tsx
          combo-box.tsx
          index.ts
          menu-item.tsx
          menu.tsx
          README.md
          select-control.tsx
          selected-items.tsx
          suffix-icon.tsx
          types.ts
          utils.ts
        experimental-select-tree-control/
          stories/
            select-tree-control.story.tsx
          index.ts
          select-tree-menu.tsx
          select-tree.tsx
        experimental-tree-control/
          hooks/
            use-expander.ts
            use-highlighter.ts
            use-keyboard.ts
            use-selection.ts
            use-tree-item.ts
            use-tree.ts
          stories/
            tree-control.story.tsx
          typings/
            global.d.ts
          index.ts
          linked-tree-utils.ts
          tree-control.tsx
          tree-item.tsx
          tree.tsx
          types.ts
        filter-picker/
          stories/
            filter-picker.story.js
          index.js
          README.md
        filters/
          stories/
            filters.story.js
          index.js
          README.md
        flag/
          stories/
            flag.story.js
          index.js
          README.md
        form/
          stories/
            form.story.js
          form-context.ts
          form.tsx
          index.ts
          README.md
          types.ts
        form-section/
          stories/
            form-section.story.tsx
          form-section.tsx
          index.ts
          README.md
        image-gallery/
          icons/
            cover-image-icon.js
            index.ts
          stories/
            image-gallery.story.tsx
          image-gallery-item.tsx
          image-gallery-toolbar-dropdown.tsx
          image-gallery-toolbar.tsx
          image-gallery-wrapper.tsx
          image-gallery.tsx
          index.tsx
          types.ts
          utils.ts
        image-upload/
          stories/
            image-upload.story.js
          index.js
          README.md
        link/
          stories/
            link.story.tsx
          index.tsx
          README.md
        list/
          stories/
            list.story.js
          index.js
          list-item.js
          README.md
        list-item/
          stories/
            list-item.story.tsx
          index.ts
          list-item.tsx
          README.md
        media-uploader/
          stories/
            media-uploader.story.tsx
            mock-media-uploader.tsx
          index.tsx
          media-uploader.tsx
          README.md
          types.ts
        order-status/
          stories/
            order-status.story.js
          index.js
          README.md
        pagination/
          stories/
            pagination.story.js
          index.ts
          page-arrows-with-picker.tsx
          page-arrows.tsx
          page-picker.tsx
          page-size-picker.tsx
          pagination.tsx
          README.md
          use-pagination.ts
        phone-number-input/
          stories/
            phone-number-input.story.tsx
          data.ts
          defaults.tsx
          index.tsx
          README.md
          types.ts
          utils.ts
          validation.ts
        pill/
          stories/
            pill.story.js
          index.js
          pill.js
          README.md
        plugins/
          index.tsx
          README.md
        product-fields/
          api/
            index.ts
            registration.ts
            render.tsx
          fields/
            basic-select-control/
              index.ts
              render.tsx
            checkbox/
              index.ts
              render.tsx
            radio/
              index.ts
              render.tsx
            text/
              index.ts
              render.tsx
            toggle/
              index.ts
              render.tsx
            index.ts
            types.ts
          store/
            action-types.ts
            actions.ts
            constants.ts
            index.ts
            reducer.ts
            selectors.ts
            types.ts
          stories/
            product-fields.story.tsx
          index.ts
          README.md
        product-image/
          stories/
            product-image.story.tsx
          index.tsx
          placeholder.tsx
          README.md
        progress-bar/
          stories/
            progress-bar.story.tsx
          index.tsx
        rating/
          stories/
            rating.story.tsx
          index.tsx
          product.tsx
          README.md
          review.tsx
        scroll-to/
          stories/
            scroll-to.story.js
          index.js
          README.md
        search/
          autocompleters/
            attributes.tsx
            categories.tsx
            countries.tsx
            coupons.tsx
            customer-names.tsx
            customers.tsx
            download-ips.tsx
            emails.tsx
            index.ts
            orders.tsx
            product.tsx
            registered-customers.tsx
            taxes.tsx
            types.ts
            usernames.tsx
            utils.ts
            variable-product.tsx
            variations.tsx
          stories/
            search.story.js
          index.tsx
          README.md
          search.tsx
          types.ts
        search-list-control/
          stories/
            search-list-control.story.js
          hierarchy.js
          index.js
          item.js
          README.md
        section/
          stories/
            section.story.tsx
          context.tsx
          header.tsx
          index.tsx
          README.md
          section.tsx
        section-header/
          stories/
            section-header.story.js
          index.js
          README.md
        segmented-selection/
          stories/
            segmented-selection.story.js
          index.js
          README.md
        select-control/
          stories/
            select-control.story.tsx
          control.tsx
          index.tsx
          list.tsx
          README.md
          tags.tsx
          types.ts
        slot-context/
          index.ts
          slot-context.tsx
        sortable/
          stories/
            sortable.story.tsx
          draggable-icon.tsx
          index.ts
          non-sortable-item.tsx
          README.md
          sortable-handle.tsx
          sortable-item.tsx
          sortable.tsx
          types.ts
          utils.ts
        spinner/
          stories/
            spinner.story.js
          index.js
          README.md
        stepper/
          stories/
            stepper.story.js
          check-icon.tsx
          index.tsx
          README.md
        summary/
          stories/
            summary.story.js
          index.js
          menu.js
          number.js
          placeholder.js
          README.md
          utils.js
        table/
          stories/
            empty-table.story.tsx
            index.ts
            table-card.story.tsx
            table-placeholder.story.tsx
            table-summary-placeholder.story.tsx
            table-summary.story.jsx
            table.story.tsx
          empty.tsx
          index.tsx
          placeholder.tsx
          README.md
          summary.tsx
          table.tsx
          types.ts
        tag/
          stories/
            tag.story.tsx
          index.tsx
          README.md
        text-control/
          stories/
            text-control.story.js
          index.js
          README.md
        text-control-with-affixes/
          stories/
            text-control-with-affixes.story.js
          index.js
          README.md
        timeline/
          stories/
            timeline.story.js
          index.js
          README.md
          timeline-group.js
          timeline-item.js
          util.js
        tooltip/
          stories/
            tooltip.story.tsx
          index.ts
          tooltip.tsx
        tour-kit/
          components/
            step-controls.tsx
            step-navigation.tsx
            step.tsx
          stories/
            tour-kit.story.tsx
          index.tsx
          README.md
          types.ts
        tree-select-control/
          stories/
            tree-select-control.story.js
          checkbox.js
          constants.js
          control.js
          index.js
          options.js
          README.md
          tags.js
          useIsEqualRefValue.js
        view-more-list/
          stories/
            view-more-list.story.js
          index.js
          README.md
        web-preview/
          stories/
            web-preview.story.js
          index.js
          README.md
        experimental.js
        index.ts
        utils.tsx
      typings/
        global.d.ts
        index.d.ts
        monorepo-enhancements.d.ts
      .npmrc
      babel.config.js
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
      tsconfig.json
      webpack.config.js
    create-woo-extension/
      changelog/
        .gitkeep
        64838-dev-esbuild-package-builds
        66078-fix-scaffold-lint-clean
        66078-fix-scaffold-npm-install
        66078-fix-scaffold-prettier-resolution
        66078-update-scaffold-flat-config
        update-php-dev-dependency-security-patches
      variants/
        add-report/
          includes/
            Admin/
              Setup.php.mustache
          languages/
            woo-plugin-setup.pot.mustache
          src/
            index.js.mustache
          .editorconfig.mustache
          .gitignore.mustache
          .prettierrc.json.mustache
          .wp-env.json.mustache
          $slug.php.mustache
          composer.json.mustache
          eslint.config.mjs.mustache
          README.md.mustache
          webpack.config.js.mustache
        add-task/
          includes/
            Admin/
              Setup.php.mustache
            Task.php.mustache
          languages/
            woo-plugin-setup.pot.mustache
          src/
            index.js.mustache
          .editorconfig.mustache
          .gitignore.mustache
          .prettierrc.json.mustache
          .wp-env.json.mustache
          $slug.php.mustache
          composer.json.mustache
          eslint.config.mjs.mustache
          README.md.mustache
          webpack.config.js.mustache
        dashboard-section/
          includes/
            Admin/
              Setup.php.mustache
          languages/
            woo-plugin-setup.pot.mustache
          src/
            components/
              GlobalPrices.js.mustache
              UpcomingEvents.js.mustache
            index.js.mustache
          .editorconfig.mustache
          .gitignore.mustache
          .prettierrc.json.mustache
          .wp-env.json.mustache
          $slug.php.mustache
          composer.json.mustache
          eslint.config.mjs.mustache
          README.md.mustache
          webpack.config.js.mustache
        default/
          includes/
            Admin/
              Setup.php.mustache
          languages/
            woo-plugin-setup.pot.mustache
          src/
            index.js.mustache
            index.scss.mustache
          .editorconfig.mustache
          .gitignore.mustache
          .prettierrc.json.mustache
          .wp-env.json.mustache
          $slug.php.mustache
          composer.json.mustache
          eslint.config.mjs.mustache
          README.md.mustache
          webpack.config.js.mustache
        sql-modification/
          includes/
            Admin/
              Setup.php.mustache
          languages/
            woo-plugin-setup.pot.mustache
          src/
            index.js.mustache
            index.scss.mustache
          .editorconfig.mustache
          .gitignore.mustache
          .prettierrc.json.mustache
          .wp-env.json.mustache
          $slug.php.mustache
          composer.json.mustache
          eslint.config.mjs.mustache
          README.md.mustache
          webpack.config.js.mustache
        table-column/
          includes/
            Admin/
              Setup.php.mustache
          languages/
            woo-plugin-setup.pot.mustache
          src/
            index.js.mustache
          .editorconfig.mustache
          .gitignore.mustache
          .prettierrc.json.mustache
          .wp-env.json.mustache
          $slug.php.mustache
          composer.json.mustache
          eslint.config.mjs.mustache
          README.md.mustache
          webpack.config.js.mustache
      CHANGELOG.md
      composer.json
      index.js
      package.json
      README.md
    csv-export/
      changelog/
        .gitkeep
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        index.ts
      typings/
        index.d.ts
      .npmrc
      .prettierrc.js
      babel.config.js
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
      tsconfig.json
    currency/
      changelog/
        .gitkeep
        consolidate-eslint-core-modules
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        currency-context.js
        index.ts
        utils.tsx
      .npmrc
      babel.config.js
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
      tsconfig.json
    customer-effort-score/
      changelog/
        .gitkeep
        66078-dehoist-react
        consolidate-eslint-core-modules
        dev-eslint-no-floating-promises
        fix-39052-normalize-submit-label
        fix-wooairr-204-ces-container-createelement-import
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        components/
          customer-effort-score/
            index.tsx
          customer-effort-score-modal-container/
            index.tsx
          customer-effort-score-tracks/
            index.js
          customer-effort-score-tracks-container/
            index.js
          customer-feedback-modal/
            index.tsx
          customer-feedback-simple/
            customer-feedback-simple.tsx
            index.ts
          feedback-modal/
            feedback-modal.tsx
            index.ts
          index.ts
        hooks/
          use-customer-effort-score-exit-page-tracker/
            index.ts
          use-customer-effort-score-modal/
            index.ts
          index.ts
        store/
          action-types.js
          actions.js
          constants.js
          get-on-submit-label.js
          index.js
          reducer.js
          resolvers.js
          selectors.js
        utils/
          customer-effort-score-exit-page.ts
          get-store-age-in-weeks.ts
          index.ts
        constants.js
        index.ts
      typings/
        index.d.ts
        monorepo-enhancements.d.ts
      .npmrc
      babel.config.js
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
      tsconfig.json
      webpack.config.js
    data/
      changelog/
        .gitkeep
        33593-isolate-leaderboard-queries
        50786-add-server-side-search-opt-out
        50786-fix-analytics-products-search-limit
        63697-analytics-taxes-taxable-amount
        65662-dev-65627-postrelease-cleanup
        66078-dehoist-react
        add-60393-activity-panel-store
        add-onboarding-task-image-metadata
        consolidate-eslint-core-modules
        dev-eslint-no-floating-promises
        fix-68084-plugin-install-error-message
        fix-analytics-settings-report-cache
        fix-dismiss-task-list-scope
        fix-wooairr-102-settings-stale-error
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
        wooplug-929-settings-alias-docs
      src/
        activity-panel/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
        countries/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
        crud/
          action-types.ts
          actions.ts
          crud-actions.ts
          index.ts
          README.md
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
          utils.ts
        export/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          selectors.ts
          types.ts
          utils.ts
        import/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
        items/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          store-aware-utils.ts
          types.ts
          utils.ts
        navigation/
          action-types.ts
          actions.ts
          constants.ts
          dispatchers.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
          with-navigation-hydration.tsx
        notes/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
        onboarding/
          action-types.ts
          actions.ts
          constants.ts
          deprecated-tasks.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
          utils.ts
          with-onboarding-hydration.tsx
        options/
          action-types.ts
          actions.ts
          constants.ts
          controls.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
          utils.ts
          with-options-hydration.tsx
        orders/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
          utils.ts
        payment-gateways/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
        payment-settings/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
          utils.ts
        plugins/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
          with-plugins-hydration.tsx
        product-attribute-terms/
          constants.ts
          index.ts
          types.ts
        product-attributes/
          constants.ts
          index.ts
          types.ts
        product-categories/
          constants.ts
          index.ts
          README.md
          types.ts
        product-form/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
        product-shipping-classes/
          constants.ts
          index.ts
          README.md
          types.ts
        product-tags/
          constants.ts
          index.ts
          types.ts
        product-variations/
          action-types.ts
          actions.ts
          constants.ts
          crud-actions.ts
          index.ts
          reducer.ts
          selectors.ts
          types.ts
        products/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
          utils.ts
        reviews/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
        setting-options/
          action-types.ts
          actions.ts
          index.ts
          README.md
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
        settings/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
          use-settings.ts
          with-settings-hydration.tsx
        shipping-methods/
          action-types.ts
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
        shipping-zones/
          constants.ts
          index.ts
          README.md
          types.ts
        tax-classes/
          constants.ts
          index.ts
          resolvers.ts
          types.ts
        types/
          api.ts
          index.ts
          promiseify-selectors.ts
          query-params.ts
          rule-processor.ts
          wp-data.ts
        user/
          constants.ts
          index.ts
          types.ts
          use-user-preferences.ts
          use-user.ts
          with-current-user-hydration.tsx
        woopayments-onboarding/
          actions.ts
          constants.ts
          index.ts
          reducer.ts
          resolvers.ts
          selectors.ts
          types.ts
        constants.ts
        controls.ts
        index.ts
        use-select-with-refresh.ts
        utils.ts
      typings/
        index.d.ts
        monorepo-enhancements.d.ts
      .npmrc
      babel.config.js
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
      tsconfig.json
    date/
      changelog/
        .gitkeep
        fix-53303-day-range-in-localized-format
        fix-64020-moment-tz-clobber
        fix-week-start-setting
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        index.ts
      typings/
        global.d.ts
      .npmrc
      babel.config.js
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
      tsconfig.json
    dependency-extraction-webpack-plugin/
      changelog/
        .gitkeep
        remove-experimental-products-app
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
        wooplug-929-settings-alias-docs
      src/
        index.js
      .npmrc
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
    e2e-utils-playwright/
      changelog/
        .gitkeep
        woo6-108-resolve-high-npm-alerts
      src/
        api-client.ts
        cart.ts
        checkout.ts
        editor.ts
        index.ts
        order.ts
        types.ts
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      README.md
      tsconfig.json
    email-editor/
      changelog/
        .gitkeep
        testops-288-email-editor-loads
        update-wooplug-7698-rich-text-comment-styles
        wooplug-7713-template-selector-layout-breaks-with-gutenberg-239
      src/
        blocks/
          core/
            block-edit.tsx
            buttons.ts
            columns.tsx
            embed.tsx
            full-width.tsx
            general-block-support.ts
            group.tsx
            image.tsx
            post-content.tsx
            quote.ts
            rich-text.tsx
            site-logo.ts
            social-links.tsx
          woocommerce/
            product-image.ts
          index.ts
          utils.ts
        components/
          block-editor/
            editor.tsx
            index.ts
          header/
            back-button-content.tsx
            send-button.tsx
            trash-email-post.tsx
          more-menu/
            index.ts
            more-menu.tsx
          notices/
            index.ts
            notices.tsx
            sent-email-notice.tsx
            snackbars.tsx
            validation-notices.tsx
          personalization-tags/
            category-menu.tsx
            category-section.tsx
            link-modal.tsx
            personalization-tags-link-popover.tsx
            personalization-tags-modal.tsx
            personalization-tags-popover.tsx
            rich-text-utils.ts
            rich-text-with-button.tsx
          preview/
            index.ts
            preview-save-guard.ts
            send-preview-email.tsx
            send-preview.tsx
          sidebar/
            block-compatibility-warnings.tsx
            edit-template-modal.tsx
            index.ts
            reset-email-template.tsx
            settings-panel.tsx
            template-selection.tsx
            template-settings-panel.tsx
          styles-sidebar/
            panels/
              color-dropdown-item.tsx
              dimensions-panel.tsx
              typography-element-panel.tsx
              typography-panel.tsx
            previews/
              typography-preview.tsx
            screens/
              index.ts
              preview.tsx
              screen-background.tsx
              screen-colors.tsx
              screen-header.tsx
              screen-layout.tsx
              screen-root.tsx
              screen-typography-element.tsx
              screen-typography.tsx
            hooks.ts
            index.ts
            navigator.ts
            styles-sidebar.tsx
            utils.ts
          template-canvas-affordance/
            index.ts
            template-canvas-affordance.tsx
          template-select/
            async.ts
            index.ts
            select-modal.tsx
            template-categories-list-sidebar.tsx
            template-list.tsx
            template-selection.tsx
        config-tools/
          block-config.ts
          block-style.ts
          block-variations.ts
          filters.ts
          formats.ts
          index.ts
        events/
          dom-tracking.ts
          event-collector.ts
          event-pipeline.ts
          index.ts
          store-tracking.ts
        hacks/
          index.ts
          modify-template-actions.tsx
          move-to-trash.tsx
          notices-slot.tsx
          publish-save.tsx
          README.md
        hooks/
          index.ts
          use-content-validation.ts
          use-editor-mode.ts
          use-email-css.ts
          use-email-styles.ts
          use-filter-editor-content-stylesheets.ts
          use-global-styles-output.ts
          use-is-email-editor.ts
          use-navigate-to-entity-record.js
          use-notice-overrides.ts
          use-preview-templates.ts
          use-remove-saving-failed-notices.ts
          use-shallow-equal.ts
          use-user-theme.ts
          use-validation-notices.ts
        layouts/
          flex-email.tsx
        middleware/
          content-validation.ts
        private-apis/
          index.ts
          README.md
        store/
          actions.ts
          constants.ts
          index.ts
          initial-state.ts
          personalization-tags-query.ts
          reducer.ts
          selectors.ts
          settings.ts
          store.ts
          types.ts
        types/
          index.ts
        editor.tsx
        global.d.ts
        index.ts
        style-variables.ts
        telemetry-tracking.md
        text-hooks.ts
      typings/
        monorepo-enhancements.d.ts
        wordpress-modules.d.ts
      .npmrc
      .prettierrc.js
      .stylelintrc
      blueprint.json
      build.mjs
      CHANGELOG.md
      composer.json
      development.md
      eslint.config.mjs
      jest.config.json
      jest.setup.ts
      package.json
      README.md
      tsconfig.json
      webpack.config.js
      writing-e2e-tests.md
    eslint-plugin/
      changelog/
        .gitkeep
        wooplug-7554-add-tooling-catalog
      .npmrc
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      index.js
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
    experimental/
      changelog/
        .gitkeep
        66078-dehoist-react
        add-dismiss-whats-next-tasks
        consolidate-eslint-core-modules
        tweak-woo-home-dashboard-task-styles
        woo6-109-storybook-10
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        experimental-list/
          collapsible-list/
            index.tsx
          stories/
            experimental-list.story.tsx
          task-item/
            index.tsx
            README.md
          experimental-list-item.tsx
          experimental-list.tsx
        inbox-note/
          action.tsx
          inbox-dismiss-confirmation-modal.tsx
          inbox-note.tsx
          index.ts
          placeholder.tsx
          use-callback-on-link-click.ts
        vertical-css-transition/
          stories/
            vertical-css-transition.story.tsx
          index.ts
          README.md
          vertical-css-transition.tsx
        index.js
        text.ts
      typings/
        global.d.ts
        index.d.ts
        jest-dom.d.ts
      .npmrc
      babel.config.js
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
      tsconfig.json
      webpack.config.js
    explat/
      changelog/
        .gitkeep
        dev-update-cookie-security
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        anon.ts
        assignment.ts
        error.ts
        index.ts
        utils.ts
      .npmrc
      babel.config.js
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
      tsconfig.json
    expression-evaluation/
      changelog/
        .gitkeep
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        index.ts
        parser.ts
      .npmrc
      babel.config.js
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      README.md
      tsconfig.json
    extend-cart-checkout-block/
      changelog/
        .gitkeep
        64838-dev-esbuild-package-builds
        66078-update-scaffold-flat-config
        dev-gitignore-glob-parsing
        update-php-dev-dependency-security-patches
      src/
        css/
          _colors.scss.mustache
        js/
          checkout-newsletter-subscription-block/
            block.js.mustache
            block.json.mustache
            edit.js.mustache
            frontend.js.mustache
            index.js.mustache
            style.scss.mustache
          ExampleComponent.js.mustache
          filters.js.mustache
          index.js.mustache
          style.scss.mustache
        index.js.mustache
      .editorconfig.mustache
      .gitignore.mustache
      .nvmrc.mustache
      .wp-env.json.mustache
      $slug-blocks-integration.php.mustache
      $slug.php.mustache
      CHANGELOG.md
      composer.json
      eslint.config.mjs.mustache
      index.js
      package.json
      README.md
      README.md.mustache
      webpack.config.js.mustache
    internal-build/
      scripts/
        generate-types.mjs
      src/
        composer/
          index.ts
        esbuild/
          args.ts
          assets.ts
          index.ts
          options.ts
        style-build/
          index.cjs
          style-asset-plugin.cjs
          webpack-rtl-plugin.cjs
        utils/
          logger.ts
        index.ts
        tsconfig.json
      eslint.config.mjs
      package.json
    internal-js-tests/
      changelog/
        42860-update-pnpm
        43532-add-cli-to-ci-workflow
        43595-update-wireit-0.14.3
        45148-poc-request-reviews
        46278-fix-43889-43901-43944
        47156-dev-fix-build-error-build-style
        47385-dev-update-pnpm9-1
        50828-dev-constrain-pnpm-version
        52815-dev-lock-dependencies
        53165-dev-ts-5-7-2
        53531-dev-react-18-ghidorah
        53865-dev-pnpm-9-15-0
        54996-chore-update-wireit
        55095-dev-rewrite-wireit-deps-update
        56246-update-settings-router-calypso-package
        56575-dev-bump-babel-deps
        57299-fix-wireit-in-ci
        58941-dev-consolidate-packages-license-version
        59001-dev-build-ram-usage-batch-3
        63483-add-62921-shared-monorepo-ts-config
        64111-dev-fix-admin-webpack-cache-misses
        64838-dev-esbuild-package-builds
        65662-dev-65627-postrelease-cleanup
        66078-dehoist-react
        add-bump-stats-error
        add-settings-option-store
        add-tracks-unit-tests-improvements-product-editor
        dev-64837-type-check-only-on-lint
        dev-babel-loader-jest-caching
        dev-build-profiling-tweaks-take-1
        dev-ci-lint-monorepo-job-update
        dev-cjs-prepack-only
        dev-consolidate-syncpack-config
        dev-merge-admin
        dev-monorepo-caching-deps-per-target-package
        fix-domain-substitution
        fix-experimental_role_warning
        update-59804
        update-pnpm-10-upgrade
        update-settings-router-calypso-package
        update-wp-68-packages
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        mocks/
          api-request.js
          static.js
          style-mock.js
          tinymce.js
          woocommerce-settings.js
          woocommerce-tracks.js
        util/
          index.js
        setup-globals.js
        setup-react-testing-library.js
        setup-window-globals.js
      typings/
        monorepo-enhancements.d.ts
      .npmrc
      babel.config.js
      build.mjs
      composer.json
      eslint.config.mjs
      jest-preset.js
      package.json
      tsconfig-jest.json
      tsconfig.json
    navigation/
      changelog/
        .gitkeep
        65662-dev-65627-postrelease-cleanup
        66078-dehoist-react
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        hooks/
          use-confirm-unsaved-changes.ts
        filters.js
        history.ts
        index.js
        url.js
      .npmrc
      babel.config.js
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
      tsconfig.json
    notices/
      changelog/
        42860-update-pnpm
        43532-add-cli-to-ci-workflow
        43595-update-wireit-0.14.3
        44566-fix-44565-fix-gutenberg-links-pointing-to-the-wrong-branch-in-the-docs
        45148-poc-request-reviews
        46278-fix-43889-43901-43944
        47156-dev-fix-build-error-build-style
        47385-dev-update-pnpm9-1
        50828-dev-constrain-pnpm-version
        52815-dev-lock-dependencies
        53165-dev-ts-5-7-2
        53531-dev-react-18-ghidorah
        53865-dev-pnpm-9-15-0
        54996-chore-update-wireit
        55095-dev-rewrite-wireit-deps-update
        56575-dev-bump-babel-deps
        57299-fix-wireit-in-ci
        58765-dev-deps-cleanup-concurrently
        58941-dev-consolidate-packages-license-version
        59001-dev-build-ram-usage-batch-3
        63483-add-62921-shared-monorepo-ts-config
        64838-dev-esbuild-package-builds
        65662-dev-65627-postrelease-cleanup
        66078-dehoist-react
        dev-64837-type-check-only-on-lint
        dev-build-profiling-tweaks-take-1
        dev-ci-lint-monorepo-job-update
        dev-cjs-prepack-only
        dev-consolidate-syncpack-config
        dev-updates-to-packages-for-dependencies
        fix-arialive-type
        fix-domain-substitution
        fix-misspelling-in-inline-doc-packages-js
        update-59804
        update-pnpm-10-upgrade
        update-wp-68-packages
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        store/
          utils/
            on-sub-key.ts
          actions.ts
          constants.ts
          controls.ts
          index.ts
          reducer.ts
          selectors.ts
          types.ts
        index.ts
      typings/
        monorepo-enhancements.d.ts
      .npmrc
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      package.json
      README.md
      tsconfig.json
    number/
      changelog/
        .gitkeep
        wooplug-2965-negative-baseline-delta
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        index.ts
      typings/
        index.d.ts
      .npmrc
      babel.config.js
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
      tsconfig.json
    onboarding/
      changelog/
        .gitkeep
        consolidate-eslint-core-modules
        dev-eslint-no-floating-promises
        fix-dz-states-test-fixture
        fix-payment-methods-count-theme-colors
        performance-woopayments-onboarding-svg-assets
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        components/
          Loader/
            stories/
              loader.story.tsx
            index.ts
            Loader.tsx
            ProgressBar.tsx
          RecommendedRibbon/
            index.ts
            RecommendedRibbon.tsx
          WCPayBanner/
            index.ts
            WCPayBanner.tsx
            WCPayBannerImage.tsx
            WCPayBannerImageCut.tsx
          WCPayBenefits/
            icons/
              earn-manage.js
              index.ts
              International-market.js
              payment-card.js
              woopay.js
            index.ts
            WCPayBenefits.tsx
          WooOnboardingTask/
            index.ts
            WooOnboardingTask.tsx
          WooOnboardingTaskListHeader/
            index.ts
            WooOnboardingTaskListHeader.tsx
          WooOnboardingTaskListItem/
            index.ts
            WooOnboardingTaskListItem.tsx
          WooOnboardingTaskReferral/
            index.ts
          WooPaymentGatewayConfigure/
            index.ts
            README.md
            WooPaymentGatewayConfigure.tsx
          WooPaymentGatewaySetup/
            index.ts
            README.md
            WooPaymentGatewaySetup.tsx
          WooPaymentsMethodsLogos/
            index.tsx
          SetupRequired.tsx
        utils/
          countries/
            index.ts
            location-mapping.ts
        index.ts
      typings/
        custom.d.ts
        global.d.ts
        index.d.ts
        monorepo-enhancements.d.ts
      .npmrc
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
      tsconfig.json
      webpack.config.js
    remote-logging/
      changelog/
        .gitkeep
        consolidate-eslint-core-modules
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        index.ts
        remote-logger.ts
        types.ts
        utils.ts
      typings/
        global.d.ts
        index.d.ts
      .npmrc
      babel.config.js
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
      tsconfig.json
    sanitize/
      changelog/
        .gitkeep
        63483-add-62921-shared-monorepo-ts-config
        64838-dev-esbuild-package-builds
        65662-dev-65627-postrelease-cleanup
        chore-remove-unused-wp-scripts-deps
        dev-64837-type-check-only-on-lint
        dev-cjs-prepack-only
        dev-update-dompurify-security
        wooplug-7554-add-tooling-catalog
      src/
        index.ts
        noop-trusted-types-policy.ts
        sanitize.ts
        trusted-types-policy.ts
      build.mjs
      CHANGELOG.md
      composer.json
      jest.config.json
      package.json
      README.md
      tsconfig.json
    settings-ui/
      changelog/
        add-settings-ui
        add-shell-header-fields
        add-wooprd-3595-dataform-adapter
        add-wpds-shell-components
        dev-mark-package-experimental
        fix-dataviews-17-wordpress-69-compatibility
        fix-form-submit-navigation-guard
        fix-preserve-download-links
        fix-preserve-wordpress-settings-behaviour
        fix-save-and-continue-navigation
        fix-wooprd-3593-missing-components
        fix-wooprd-3594-settings-value-boundary
        refactor-bounded-settings-ui-cleanup
        refactor-settings-navigation-internals
        tweak-settings-ui-card-design
        update-adopt-wpds-components
        update-remove-group-actions
        update-remove-woo-field-renderers
        update-rename-settings-ui-package
        update-section-scope-semantics
        update-shell-header-top-level-pages
        update-wooprd-3596-dataform-renderer
        update-wordpress-admin-ui
        wooplug-7554-add-tooling-catalog
      src/
        dataform-adapter.tsx
        dataform-runtime.ts
        dataviews-wp.d.ts
        diagnostics.ts
        hidden-inputs.tsx
        html.ts
        index.ts
        registry.ts
        settings-ui-page.tsx
        types.ts
        values.ts
      build.mjs
      jest.config.js
      package.json
      README.md
      tsconfig.json
    tracks/
      changelog/
        .gitkeep
        wooplug-6930-eslint-v10-flat-config
        wooplug-7554-add-tooling-catalog
      src/
        index.ts
        stats.ts
        utils.js
      typings/
        global.d.ts
      .npmrc
      build.mjs
      CHANGELOG.md
      composer.json
      eslint.config.mjs
      jest.config.json
      package.json
      PREVIOUS_CHANGELOG.md
      README.md
      tsconfig.json
    CLAUDE.md
    README.md
    tsconfig-cjs.json
    tsconfig.json
  php/
    blueprint/
      changelog/
        57219-update-remove-zip-feature-from-blueprint
        57294-wooplug-2482-feature-blueprint-require-permission-based-on-the-steps
        57299-fix-wireit-in-ci
        57842-dev-blueprint-install-path
        57935-update-blueprint-docs
        58755-dev-53714
        58792-update-blueprint-doc-exporter-ui
        58941-dev-consolidate-packages-license-version
        59411-add-57846
        61753-fix-support-composer-update
        66097-bump-wp-env-and-playwright
        dev-fix-blueprint-package-setup
        fix-blueprint-autoload
        fix-blueprint-setup-tests
        fix-wooplug-6319-blueprint-import-table-prefix
        improve-blueprint-validation
        remove-unused-blueprint-steps
        resync-composer-locks
        update-blueprint-require-permission-exporters-api
        update-php-dev-dependency-security-patches
        update-wpcs-3-4-1
        woo6-10-blueprints-security-audit-determine-the-scope-of-allowed-sql
        woo6-96-fix-restricted-options-case-bypass
        woo6-97-update-runsql-trust-boundary-docs
        wooplug-3933-fix-blueprint-type-warnings-and-improve-error-handling
        wooplug-3946-blueprint-centralized-audit-logging
        wooplug-3964-blueprint-protect-critical-options
      src/
        Cli/
          ExportCli.php
          ImportCli.php
        docs/
          json-examples/
            activatePlugin.json
            installPlugin.json
            installTheme.json
            setSiteOptions.json
        Exporters/
          ExportInstallPluginSteps.php
          ExportInstallThemeSteps.php
          HasAlias.php
          StepExporter.php
        Importers/
          ImportActivatePlugin.php
          ImportActivateTheme.php
          ImportInstallPlugin.php
          ImportInstallTheme.php
          ImportRunSql.php
          ImportSetSiteOptions.php
        ResourceStorages/
          LocalPluginResourceStorage.php
          LocalThemeResourceStorage.php
          OrgPluginResourceStorage.php
          OrgThemeResourceStorage.php
          ResourceStorage.php
        ResultFormatters/
          CliResultFormatter.php
          JsonResultFormatter.php
        Schemas/
          JsonSchema.php
        Steps/
          ActivatePlugin.php
          ActivateTheme.php
          InstallPlugin.php
          InstallTheme.php
          RunSql.php
          SetSiteOptions.php
          Step.php
        BuiltInExporters.php
        BuiltInStepProcessors.php
        ClassExtractor.php
        Cli.php
        ExportSchema.php
        ImportSchema.php
        ImportStep.php
        Logger.php
        ResourceStorages.php
        StepProcessor.php
        StepProcessorResult.php
        UsePluginHelpers.php
        UsePubSub.php
        UseWPFunctions.php
        Util.php
      .gitattributes
      .wp-env.json
      blueprint.php
      composer.json
      development.md
      package.json
      phpcs.xml
      README.md
    email-editor/
      changelog/
        .gitkeep
        testops-288-email-editor-loads
        update-wooplug-7698-rich-text-comment-styles
      docs/
        block-registration.md
        personalization-tags.md
        README.md
        rendering.md
        site-style-sync-hooks.md
      src/
        Engine/
          Logger/
            class-default-email-editor-logger.php
            class-email-editor-logger-interface.php
            class-email-editor-logger.php
          Patterns/
            class-abstract-pattern.php
            class-patterns.php
          PersonalizationTags/
            class-html-tag-processor.php
            class-personalization-tag.php
            class-personalization-tags-registry.php
          Renderer/
            ContentRenderer/
              Layout/
                class-flex-layout-renderer.php
              Postprocessors/
                class-border-style-postprocessor.php
                class-highlighting-postprocessor.php
                class-variables-postprocessor.php
                interface-postprocessor.php
              Preprocessors/
                class-blocks-width-preprocessor.php
                class-cleanup-preprocessor.php
                class-quote-preprocessor.php
                class-spacing-preprocessor.php
                class-typography-preprocessor.php
                interface-context-aware-preprocessor.php
                interface-preprocessor.php
              class-block-renderer.php
              class-blocks-parser.php
              class-content-renderer.php
              class-preset-variable-resolver.php
              class-process-manager.php
              class-rendering-context.php
            class-html2text-exception.php
            class-html2text.php
            class-renderer.php
            interface-css-inliner.php
            readme.md
            template-canvas.php
          Templates/
            class-template.php
            class-templates-registry.php
            class-templates.php
            email-general.html
            single-email-post-template.php
          class-assets-manager.php
          class-dependency-check.php
          class-email-api-controller.php
          class-email-editor.php
          class-email-styles-schema.php
          class-personalizer.php
          class-send-preview-email.php
          class-settings-controller.php
          class-site-style-sync-controller.php
          class-theme-controller.php
          class-user-theme.php
          theme.json
          theme.md
        Integrations/
          Core/
            Renderer/
              Blocks/
                class-abstract-block-renderer.php
                class-audio.php
                class-button.php
                class-buttons.php
                class-column.php
                class-columns.php
                class-cover.php
                class-embed.php
                class-fallback.php
                class-gallery.php
                class-group.php
                class-image.php
                class-list-block.php
                class-list-item.php
                class-media-text.php
                class-post-content.php
                class-post-template.php
                class-quote.php
                class-social-link.php
                class-social-links.php
                class-table.php
                class-text.php
                class-video.php
            class-initializer.php
            theme.json
          Utils/
            class-dom-document-helper.php
            class-html-processing-helper.php
            class-social-links-helper.php
            class-styles-helper.php
            class-table-wrapper-helper.php
          WooCommerce/
            Renderer/
              Blocks/
                class-abstract-product-block-renderer.php
                class-coupon-code.php
                class-product-button.php
                class-product-collection.php
                class-product-image.php
                class-product-price.php
                class-product-sale-badge.php
            class-coupon-code-generator.php
            class-initializer.php
        Validator/
          Schema/
            class-any-of-schema.php
            class-array-schema.php
            class-boolean-schema.php
            class-integer-schema.php
            class-null-schema.php
            class-number-schema.php
            class-object-schema.php
            class-one-of-schema.php
            class-string-schema.php
          class-builder.php
          class-schema.php
          class-validation-exception.php
          class-validator.php
        class-bootstrap.php
        class-container.php
        class-email-css-inliner.php
        class-email-editor-container.php
        class-package.php
        exceptions.php
      tasks/
        phpstan/
          composer.json
          phpstan-7.neon
          phpstan.neon
          run-phpstan.sh
        build-package.sh
        mirror-readme.md
      .lintstagedrc.json
      .wp-env.json
      changelog.md
      composer.json
      development.md
      email-editor.php
      license.txt
      package.json
      phpcs.xml
      README.md
      SECURITY.md
      writing-tests.md
    monorepo-plugin/
      src/
        JetpackManifestEditor.php
        Plugin.php
      autoload-dev.php
      composer.json
      phpcs.xml
    remote-specs-validation/
      changelog/
        .gitkeep
        56384-fix-total-payments-volume-processor
        58941-dev-consolidate-packages-license-version
        dev-ci-lint-monorepo-job-update
        remove-sendcloud-shipping-partner
        resync-composer-locks
        woo6-108-resolve-high-npm-alerts
      src/
        .gitkeep
        RemoteSpecValidationResult.php
        RemoteSpecValidator.php
      changelog.md
      composer.json
      package.json
      phpunit.xml
      README.md
    woocommerce-analytics/
      changelog/
        .gitkeep
        fix-dotcom-18362-search-event-name
        wooa7s-1803-tracking-proxy-hardening
        wooa7s-2042-config-global-hardening
        wooa7s-client-input-bounds
        wooa7s-proxy-route-lifecycle
      src/
        API/
          class-wc-analytics-tracking-proxy.php
        client/
          listeners/
            account.ts
          types/
            global.d.ts
            shared.ts
          analytics.ts
          api-client.ts
          consent.ts
          constants.ts
          index.ts
          init.ts
          public-path.ts
          session-manager.ts
          utils.ts
        mu-plugin/
          woocommerce-analytics-proxy-speed-module-template.php
        class-consent-manager.php
        class-features.php
        class-my-account.php
        class-pixel-builder.php
        class-universal.php
        class-wc-analytics-tracking.php
        class-woo-analytics-trait.php
        class-woocommerce-analytics.php
      tasks/
        mirror-github/
          workflows/
            autotagger.yml
            readonly.yml
        build-package.sh
      .gitattributes
      CHANGELOG.md
      composer.json
      LICENSE.txt
      package.json
      phpcs.xml
      README.md
      SECURITY.md
      tsconfig.json
      webpack.config.js
    woocommerce-subscriptions-engine/
      changelog/
        .gitkeep
        66097-bump-wp-env-and-playwright
        add-admin-list-queries
        add-basic-ci-config-for-woocommerce-subscriptions-engine
        add-bogo-pricing-policy-type
        add-phpcs-sniff-to-require-const-visibility
        add-phpstan-validation-for-woocommerce-subscriptions-engine
        add-rest-api-for-subscriptions-engine-plans
        add-selling-plans-catalog-read-facade
        add-subscriptions-engine-boundary-guards
        add-subscriptions-engine-customer-portal
        add-subscriptions-engine-cycle-chain-schema
        add-subscriptions-engine-psr4-conversion
        add-subscriptions-engine-renewal-advancement
        add-subscriptions-engine-renewal-dispatch
        add-subscriptions-engine-renewal-money-path
        add-subscriptions-engine-status-machine-capabilities
        dev-refactor-subscriptions-engine-support-helpers
        fix-billing-policy-core-zone-purity
        fix-double-escaping-in-plan-repository
        fix-linting-issues-in-core-entities
        fix-subscriptions-engine-phpstan-findings
        flatten-selling-plans-catalog
        resync-composer-locks
        update-php-dev-dependency-security-patches
        update-woosubs-engine-make-phpstan-ci-required
        update-wpcs-3-4-1
      phpstan-stubs/
        stubs.php
      src/
        Api/
          Rest/
            ContractsController.php
            PlansController.php
          SellingPlans.php
          Subscriptions.php
        Core/
          Entity/
            Contract.php
            ContractStatus.php
            Cycle.php
            CycleStatus.php
            Plan.php
          Gateway/
            GatewayCapabilities.php
          Renewal/
            RenewalCalculator.php
          Support/
            MoneyScale.php
            ScalarCoercion.php
          ValueObject/
            BillingPolicy.php
            DeliveryPolicy.php
            InstrumentRef.php
            ItemsSnapshot.php
            OrderRef.php
            PlanSnapshot.php
            PricingPolicy.php
        Integration/
          Checkout/
            ContractFactory.php
            OrderLinkage.php
            RelatedOrders.php
          Contracts/
            Cancellation.php
            Hold.php
            Reactivation.php
          Gateway/
            CapabilityRegistry.php
          Ownership/
            ConsumerRegistry.php
          Renewal/
            RenewalDispatcher.php
            RenewalEngine.php
            RenewalIntent.php
            RenewalNotProcessable.php
            RenewalSelector.php
          Storage/
            ContractRepository.php
            DuplicateCycleException.php
            PlanRepository.php
            RenewalCandidate.php
            SchemaInstaller.php
            SnapshotStore.php
          Support/
            RESTPermissions.php
          Bootstrap.php
        Package.php
      tasks/
        phpstan/
          composer.json
          phpstan-7.neon
          phpstan.neon
          run-phpstan.sh
      .wp-env.json
      composer.json
      license.txt
      package.json
      phpcs.xml
      README.md
      woocommerce-subscriptions-engine.php
    .gitkeep
plugins/
  woocommerce/
    changelog/
      .gitkeep
      29386-product-name-css-class
      29906-fix-rest-review-rating-recompute
      30964-support-array-structured-data-types
      30996-focus-product-search
      31339-payment-method-all-methods-label
      32209-add-phone-to-customer-reports
      33410-fix-refund-customer-type-analytics
      36329-fix-refund-attributed-to-user-1
      36538-selected-any-variation-names
      36758-product-category-list-order
      38347-fix-tax-lookup-grain
      38347-tax-lookup-failed-import-retry
      38347-tax-lookup-grain-schema
      41225-performance-skip-review-lookup-updates
      42348-batch-shipping-rate-selection
      42469-keep-incompatible-notice-dismissed
      42492-product-collection-sort-fixtures
      42662-product-categories-inspector-controls-unit-tests
      44157-fix-paypal-api-credentials-link
      44613-fix-inconsistent-checkout-error-handling
      45168-product-image-id-casts
      49059-include-dates-in-emailed-analytics-exports
      49368-add-webpack-chunk-names
      50786-add-server-side-search-opt-out
      50786-fix-analytics-products-search-limit
      51426-fix-prices-include-tax-on-order-create
      51602-fix-order-attribution-origin-overflow
      52517-failed-order-text-filter
      53136-platform-selector-mobile-keyboard
      57940-checkout-country-change-shipping-rates
      60577-featured-image-metadata-loss
      60577-fix-attachment-metadata-loss
      63303-admin-price-wrapping
      63697-analytics-taxes-taxable-amount
      64439-fix-stock-notifications-cancel-page
      64439-my-account-stock-notifications
      65412-fix-hidden-required-fields
      65484-fix-cart-item-data-non-scalar
      65764-checkout-order-summary-breakpoint
      66072-perf-v4-customer-schema-gate-aggregates
      66317-perf-memoize-country-extensions
      66520-fix-revenue-table-stale-rows
      66953-unify-postcode-validation
      67124-fix-store-api-cart-session-error-boundary
      67323-fix-product-permalink-radio-checked-state
      67354-fix-own-stock-reservation-lockout
      67459-lv-postcode-validation
      67496-fix-sale-price-dates-help-tip-position
      67644-variation-price-filter-docs
      67709-invalidate-product-term-cache
      67711-fix-order-attribution-form-dedup
      67855-hook-docs-generator-guards
      67855-hook-docs-product-add-to-cart
      67855-hook-docs-storeapi-shipping
      67931-revert-67751-fix-67354-own-reserved-stock-grace-window
      67978-add-localized-thousands-separators-to-legacy-report-counts
      68009-order-count-cache-late-registered-status
      68064-add-bis-e2e-variation-coverage
      68079-add-bis-e2e-signup-and-email-branch-coverage
      68101-grant-access-search-exclude
      68165-65956-mini-cart
      68168-order-fieldset-not-tied-to-order-notes
      68292-my-account-pending-stock-notifications
      68368-fix-receipt-deleted-variation-parent
      68515-fix-bis-new-install-allow-signups
      68530-order-summary-collapsible-bar-keyboard-defaults
      68530-order-summary-collapsible-bar-operable
      68xxx-fix-stock-notifications-endpoint-slug-sanitize
      add-35684-chw-currency
      add-cart-item-data-raw-key
      add-dismiss-whats-next-tasks
      add-filter-chips-styles
      add-helper-api-rate-limit-backoff
      add-identifier-placeholder-sniff
      add-order-withdrawal-emails
      add-payment-placement-contract-tests
      add-phpcs-inline-lint-annotations
      add-product-filter-overlay-controls
      add-quantity-selector-background-color
      add-quantity-selector-border-radius
      add-role-to-customers-report
      add-store-api-cart-item-quantity-validation-filter
      add-tax-rate-modal-search-pagination
      add-wccom-2873-auto-update-status
      bis-features-screen-toggle
      blocks-e2e-seed-idempotency
      codex-fix-product-filters-zero-block-gap
      codex-woothme-502-product-filters-sticky-support
      core-e2e-remove-redundant-tests
      deprecate-brand-recount-methods
      dev-66603-folloup-deprecate-cycle-start
      dev-ci-jobs-job-level-ignore
      dev-clean-settings-ui-styles
      dev-fix-classic-assets-stylelint-scss-syntax
      dev-markup-contract-suppressions
      dev-phpcs-test-hook-sniff-exclusions
      dev-remove-autoprefixer-legacy-css
      dev-remove-ie8-leftovers
      dev-remove-settings-ui-group-actions
      dev-remove-unused-grunt-phpcs-clean
      dev-report-header-advanced-filters-type
      dev-resolve-more-npm-alerts
      dev-revert-classic-assets-node-build
      dev-settings-registration-admin-init-priority
      dev-settings-request-boundary-suppressions
      dev-test-bootstrap-disable-code-hacker
      docs-analytics-customer-hook-timing
      docs-enum-get-all-scope
      enhancement-53323-analytics-default-status-filters
      fix-28591-coupon-discount-on-edited-order-totals
      fix-29727-csv-importer-plus-in-path
      fix-31068-order-item-qty-validation
      fix-31637-rtl-currency-symbol-bidi
      fix-31656-order-item-cache-shape
      fix-32113-short-description-pagehide
      fix-33344-unnamed-product-save
      fix-35607-product-search-order
      fix-35635-account-orders-column-filter
      fix-36937-installing-rewrite-flush
      fix-37121-sequential-coupon-order
      fix-37789-exact-attribute-term-search
      fix-38574-tracker-retry-snapshots
      fix-38919-unregister-deleted-attribute-taxonomy
      fix-39052-normalize-ces-submit-label
      fix-39112-api-tests-tracking-enabled
      fix-39462-date-paid-filter-timezone
      fix-39652-samesite-password-reset
      fix-40443-checkout-notice-validation
      fix-40683
      fix-40791-checkout-apostrophe-encoding
      fix-40831-stock-report-export-post-status
      fix-41318-hpos-orders-date-filter
      fix-41577-nbsp-separator-entities
      fix-44554-analytics-excluded-long-custom-statuses
      fix-45521-attribute-term-id-order
      fix-45770-order-status-translator-context
      fix-46459-core-deprecation-versions
      fix-47008-disabled-button-state
      fix-48583-cart-empty-message-translation
      fix-51088-analytics-translations-combined-file
      fix-51209-rest-uncaught-invalid-product
      fix-52385-core-profiler-mobile-button-spacing
      fix-53234-repair-corrupted-dashboard-sections
      fix-53303-day-range-in-localized-format
      fix-53766-fee-tax_status-non-taxable
      fix-55817-rtl-pagination-arrows
      fix-56112-product-task-menu
      fix-58000-strip-invisible-chars-phone
      fix-58084-checkout-unavailable-country-select
      fix-60415-uninstall-unschedule-actions
      fix-62151-refund-fix-tool-notice
      fix-62620-hpos-order-notes-orphaned
      fix-64557-transient-version-precision
      fix-66720-scheduled-sales-churn
      fix-66943-additional-fields-empty-document-object
      fix-67169-historical-data-description-copy
      fix-67170-historical-data-actions-alignment
      fix-67697-customer-history-excluded-long-statuses
      fix-67704-normalize-coupon-spend-amounts
      fix-67862-woocommerce-template-parts-leaking-on-creation
      fix-67886-product-meta-lookup-join-guard
      fix-68028-deleted-product-lookup
      fix-68084-plugin-install-error-message
      fix-68092-error-notices-from-plugin-error
      fix-68145-skip-themes-rewrite-flush
      fix-68177-hpos-order-notes-hidden-after-untrash
      fix-68294-default-category-tooltip-wipes-name-column
      fix-68306-free-shipping-label-in-order-emails
      fix-7579-installing-rewrite-call-sites
      fix-add-extra-test-68477
      fix-admin-dataviews-uuid-dependency
      fix-analytics-customer-type-import-order
      fix-analytics-disjoint-category-product-filters
      fix-analytics-export-email-never-arrives
      fix-analytics-settings-report-cache
      fix-bis-duplicate-signup-cross-state
      fix-bis-email-cta-drops-attribute
      fix-bis-form-add-to-cart-with-options-legacy-mode
      fix-blocks-e2e-template-revert-action
      fix-blocks-hook-docs-pipeline
      fix-blocks-interactivity-entries-path-substring
      fix-blueprint-exclude-payment-settings
      fix-cancel-order-redirect-callback
      fix-cancel-order-refresh-error
      fix-canonical-product-pagination
      fix-catalog-sorting-label-alignment
      fix-checkbox-description-markup
      fix-checkout-autofill-section-prefix
      fix-consistent-stock-threshold-sanitization
      fix-coupon-minimum-amount-validation
      fix-current-user-data-rest-fields
      fix-dk-postcode-separator
      fix-duplicate-shopify-variant-sku-mapping
      fix-e2e-wp-env-cli-cache-race
      fix-email-listing-dataviews-styles
      fix-external-product-category-count
      fix-featured-items-image-editor-natural-size
      fix-features-controller-reentrancy
      fix-hydration-restore-cart-context
      fix-idempotent-settings-registration
      fix-identifier-placeholders-orders
      fix-identifier-placeholders-sessions
      fix-last-quarter-end-date-rollover
      fix-locale-aware-geographical-cache
      fix-lv-postcode-separator
      fix-marketplace-missing-rating-guard
      fix-marketplace-theme-directory-copy-spacing
      fix-mastercard-branding
      fix-mini-cart-pattern-wrappers
      fix-order-attribution-form-dedup
      fix-order-withdrawal-feature-hooks
      fix-orders-report-export-customer-name-guard
      fix-orders-stats-refund-fixture-hour-boundary
      fix-orders-stats-report-test-hour-boundary
      fix-outofstock-update-since
      fix-password-protected-products-patterns
      fix-password-reset-preserve-login
      fix-phpcs-relative-sniff-path
      fix-phpstan-baseline-transient-files
      fix-pos-catalog-response-url
      fix-price-html-sanitizer-dir-attr
      fix-product-category-display-type-normalization
      fix-product-description-recursion-guard
      fix-product-import-stale-original-id-markers
      fix-product-widget-slowdbquery-suppressions
      fix-protected-product-descriptions
      fix-receipt-payment-method-non-string
      fix-recently-viewed-widget-query-cap
      fix-refund-marker-migration-docblock
      fix-refund-returning-customer-clobbered-on-first-order-recalc
      fix-remove-dead-slowdbquery-suppression
      fix-review-avatar-spacing
      fix-settings-ui-dataviews-17-compatibility
      fix-settings-ui-shell-tab-focus-ring
      fix-stale-task-redirect-scope
      fix-store-api-item-data-hidden-type
      fix-store-api-item-schema-extensions
      fix-store-api-order-awaiting-payment
      fix-store-api-order-item-data-hidden-meta-id
      fix-store-api-order-item-data-schema
      fix-store-api-rate-limit-status
      fix-structured-data-falsy-types
      fix-style-attributes-utils-optimizations
      fix-tests-base-teardown-singleton-cleanup
      fix-timeframe-dates-site-timezone
      fix-toggle-bubble-cleanup
      fix-tracker-unbuildable-snapshot-retries
      fix-update-antom-icon
      fix-variation-attribute-header-width
      fix-variation-bulk-save-race
      fix-variation-password-protection-flag
      fix-variation-report-order-pluralization
      fix-variation-selector-custom-attribute-identity
      fix-variation-selector-placeholder-terms
      fix-verbose-page-rule-detection
      fix-wc-get-orders-day-precision-timezone
      fix-wccom-2840-surface-subscriptions-api-errors
      fix-week-start-setting
      fix-woo6-113-auth-callback-suppressions
      fix-woo6-114-download-authorization-suppressions
      fix-woo6-115-public-interaction-suppressions
      fix-woo6-116-mixed-request-validation-suppressions
      fix-woo6-117-extensible-sql-contract-suppressions
      fix-woo6-119-context-specific-output-escaping
      fix-woo6-120-mis-scoped-output-suppressions
      fix-woo6-121-hook-docs-and-output-suppressions
      fix-woo6-122-download-read-failure
      fix-woo6-124-widget-html-rendering-suppressions
      fix-woo6-126-template-markup-suppressions
      fix-woo6-146-qr-login-session-handling
      fix-WOO6-151-exclude-password-protected-product-reviews-from-rest-api
      fix-WOO6-159-shared-cached-product-reviews
      fix-wooairr-102-settings-stale-error
      fix-wooairr-128-editor-scoped-subtotal-sync
      fix-wooairr-218-report-export-filename
      fix-wooairr-248-locale-filter-recursion
      fix-wooairr-273-stale-attribute-readers
      fix-WOOAIRR-283-missing-spacing-mini-cart-header-editor
      fix-wooairr-31-stale-combined-translations
      fix-wooairr-48-taxes-report-columns-bc
      fix-wooairr-97-restore-recently-viewed-query-ids
      fix-wooplug-1113-revenue-tax-refunded-orders
      fix-wooplug-3391-stale-task-redirect
      fix-wooplug-4518-duplicate-manual-order-customers
      fix-wooplug-529-refunded-order-count
      fix-wooplug-6420-taxes-report-date-type
      fix-wooplug-7556-rest-product-query-suppressions
      fix-wooplug-7557-report-aggregation-queries
      fix-wooplug-7558-original-id-cache
      fix-wooplug-7559-product-widget-sorting
      fix-wooplug-7653-variation-inherited-image
      fix-wooplug-7659-order-key-array-guards
      fix-wooplug-7691-stock-notifications-rest-settings
      fix-wooplug-791-separator-numeric-validation
      fix-wooprd-3593-settings-ui-components
      fix-wooprd-3594-settings-value-boundary
      fix-wooprd-3596-settings-ui-save-button
      fix-WOOTHME-462-make-mini-cart-header-smaller
      fix-WOOTHME-492-product-quantity-extra-style
      fix-WOOTHME-504-product-image-border-style
      fix-yoast-replace-editor-reentry
      fix-zero-variation-sale-adjustment
      flush-product-count-cache-on-plugin-activation
      move-customers-csv-role-column-to-end
      optimize-template-customization-e2e-rest
      patch-2
      perf-58284-purchasable-variations-candidate-scan
      performance-67913-cap-prices-transient-size
      performance-admin-ajax-inbox-note-cleanup
      performance-products-reordering-ajax
      performance-scope-product-import-cleanup
      performance-tuneup-product-caches-invalidation
      pr-37557
      pr-402-users-endpoint-field-permissions
      pr-64361
      prepare-order-item-deletion-query
      qatar-postcode-not-required
      ralucaStan-saved-for-later-cart-template
      refactor-bounded-settings-ui-cleanup
      refactor-wooplug-656-split-orders-stats-tests
      remove-abandoned-cart-recovery-feature
      remove-agentic-checkout-api
      remove-obsolete-block-patterns
      remove-old-blocks-release-testing
      remove-orphaned-reviews-stylesheet
      revert-pr-68036
      role-column-last-in-customers-table
      rsm-437-bis-notification-image-overflow
      rsm-437-bis-playwright-coverage
      test-add-csv-upload-helper-unit-tests
      test-rest-api-orders-refunds
      test-rest-api-shipping-reports-webhooks-customers
      test-rest-api-taxes
      test-shop-page-trash-rewrite-guard
      testops-234-add-to-cart-form
      testops-234-add-to-cart-with-options
      testops-234-blocks-acceptance-fixture-stabilization
      testops-234-blocks-seed-convergence
      testops-234-cart-checkout-extensibility
      testops-234-cart-checkout-notices
      testops-234-cart-checkout-shopper-journeys
      testops-234-catalog-sorting
      testops-234-checkout-block-fields
      testops-234-checkout-block-shopper
      testops-234-classic-style-loading-cache
      testops-234-customer-account-block
      testops-234-delete-redundant-blocks-e2e-tests
      testops-234-on-sale-badge
      testops-234-order-confirmation-blocks
      testops-234-patterns-editor
      testops-234-product-button
      testops-234-product-collection-compatibility
      testops-234-product-collection-frontend
      testops-234-product-collection-registration
      testops-234-product-filters-block
      testops-234-product-gallery
      testops-234-product-results-count
      testops-234-refresh-block-manifest-copies
      testops-234-remove-duplicate-register-product-collection-tests
      testops-234-remove-role-smoke-duplicate
      testops-234-single-product-server-render
      testops-234-unregister-block-types
      testops-288-block-email-rendering-source
      testops-288-checkout-link
      testops-288-checkout-shortcode-flows
      testops-288-colour-picker
      testops-288-customer-payment-page
      testops-288-email-editor-loads
      testops-288-linked-products
      testops-288-orders-admin
      testops-288-paypal-standard
      testops-288-post-comments-fixture
      testops-288-product-images
      testops-288-products-admin-export
      update-action-scheduler-via-automation
      update-catalog-sorting-content-width
      update-extract-dual-api-to-plugin
      update-mini-cart-default-labels
      update-patterns-category-name
      update-php-dev-dependency-security-patches
      update-plugin-directory-screenshots
      update-react-number-format-5
      update-SingleProductTemplateTests-utils
      update-vendored-graphql-php-security
      wc-36802-assigned-issue
      wc-67498-front-page-filters-design
      wc-product-filter-inline-style-enqueue
      wccom-2879-forced-autoupdate-passthrough
      wccom-2879-update-check-installed-version
      wccom-2882-marketplace-tab-focus-ring
      wccom-2892-quality-badge-compact-card-placement
      woo6-108-resolve-high-npm-alerts
      woo6-109-npm-security-tooling
      woo6-109-storybook-10
      wooa7s-1541-customer-filter-tag-label
      wooa7s-1541-downloads-customer-filter
      wooa7s-1857-repeatable-report-downloads
      wooairr-126-product-filters-block-gap-guard
      wooairr-278-rest-endpoint-slug-sanitize-test
      WOOMKT-825-846-849
      WOOMKT-848-850-859
      WOOMKT-851
      wooplug-1772-per-order-guest-names
      wooplug-2191-post-action-webhook-validation
      wooplug-4996-stock-notifications-signup-rate-limiter
      wooplug-59489-coupon-error-event
      wooplug-6456-add-date-field-type
      wooplug-6456-checkout-field-types
      wooplug-6456-date-field-min-max
      wooplug-7407-non-sticky-admin-header
      wooplug-7407-white-classic-editor-tools
      wooplug-7525-track-product-sorting-usage
      wooplug-7542-match-global-unique-id
      wooplug-7554-add-tooling-catalog
      wooplug-7656-configurable-endpoint-slug
      wooplug-7663-bis-normalize-customer-emails
      wooplug-7667-bis-my-account-template-no-internals
      wooplug-7704-stock-notifications-tests-off-by-default
      wooprd-3662-remove-activity-panel
      wpcs-replacement
    client/
      admin/
        client/
          activity-panel/
            activity-card/
              index.js
              placeholder.js
              README.md
            activity-header/
              index.js
              README.md
            display-options/
              icons/
                display.js
                single-column.js
                two-columns.js
              index.js
            highlight-tooltip/
              index.js
            panels/
              setup-tasks/
                setup-tasks-panel.tsx
              help.js
            tab/
              index.js
            tabs/
              index.js
            activity-panel.js
            index.js
            panel.js
            README.md
          analytics/
            components/
              import-status-bar/
                import-status-bar.tsx
                index.ts
                types.ts
                use-import-status.ts
              leaderboard/
                data/
                  top-selling-products-mock-data.js
                index.js
              report-chart/
                index.js
                utils.js
              report-filters/
                index.js
              report-header/
                index.ts
                report-header.tsx
              report-summary/
                index.js
              report-table/
                download-icon.js
                index.js
                utils.js
              scheduled-updates-promotion-notice/
                index.tsx
              index.js
              utils.js
            settings/
              historical-data/
                actions.js
                failed-orders-notice.tsx
                index.js
                layout.js
                period-selector.js
                progress.js
                skip-checkbox.js
                status.js
                utils.js
              config.js
              default-date.js
              import-mode-confirmation-modal.tsx
              index.js
              README.md
              setting.js
          blueprint/
            components/
              BlueprintUploadDropzone.tsx
              get-option-groups.ts
              get-step-actions.ts
              types.ts
            settings/
              overwrite-confirmation-modal.tsx
              slotfill.js
            index.js
          components/
            tracked-link/
              tracked-link.tsx
          core-profiler/
            actions/
              tracks.tsx
            components/
              choice/
                choice.tsx
              geolocation-country-select/
                geolocation-country-select.tsx
              heading/
                heading.tsx
              loader/
                Loader.tsx
              multiple-selector/
                multiple-selector.tsx
                render-menu.tsx
              navigation/
                navigation.tsx
                woologo.tsx
              profile-spinner/
                profile-spinner.tsx
              progress-bar/
                progress-bar.tsx
            pages/
              Plugins/
                components/
                  plugin-card/
                    plugin-card.tsx
                  plugin-error-banner/
                    PluginErrorBanner.tsx
                  plugin-terms-of-service/
                    PluginsTermsOfService.tsx
                NoPermissions.tsx
                Plugins.tsx
              BusinessInfo.tsx
              BusinessLocation.tsx
              IntroOptIn.tsx
              UserProfile.tsx
            services/
              country.ts
              installAndActivatePlugins.ts
            stories/
              BusinessInfo.story.tsx
              BusinessLocation.story.tsx
              IntroOptIn.story.tsx
              Loader.story.tsx
              Plugins.story.tsx
              UserProfile.story.tsx
              WithSetupWizardLayout.tsx
            utils/
              get-loader-stage-meta.tsx
            events.tsx
            index.tsx
            types.tsx
          customize-store/
            site-hub/
              entrepreneur-flow.ts
              index.tsx
            index.tsx
          dashboard/
            components/
              connect/
                index.js
              settings/
                general/
                  store-address.tsx
              cart-modal.js
            dashboard-charts/
              block.js
              config.js
              index.js
            leaderboards/
              index.js
            store-performance/
              index.js
              utils.js
            customizable.js
            default-sections.js
            index.js
            README.md
            section-controls.js
            section.js
            utils.ts
          embedded-body-layout/
            embedded-body-layout.tsx
            embedded-body-props.ts
            index.ts
            render-embedded-layout.tsx
          error-boundary/
            index.tsx
          guided-tours/
            add-product-tour/
              index.tsx
              use-active-editor-type.ts
              use-product-step-change.ts
              use-tmce-iframe-focus-style.ts
              use-track-publish-button.ts
            variable-product-tour/
              index.tsx
            wc-addons-tour/
              get-config.ts
              get-steps.ts
              index.tsx
              utils.ts
            report-date-tour.tsx
            shipping-tour.tsx
            utils.ts
          header/
            embed.tsx
            index.tsx
            README.md
            shared.tsx
            use-wp-admin-chrome.ts
          homescreen/
            activity-panel/
              orders/
                index.js
                utils.js
              reviews/
                checkmark-circle-icon.js
                index.js
                utils.js
              stock/
                card.js
                index.js
              index.js
              panels.js
            email-improvements-modal/
              index.tsx
            header-banner-slot/
              header-banner-slot.tsx
              index.ts
              utils.tsx
            mobile-app-modal/
              components/
                index.tsx
                MobileAppInstallationInfo.tsx
                MobileAppLoginInfo.tsx
                MobileAppLoginStepper.tsx
                QRDirectLoginCode.tsx
                QRLoginConsumedPanel.tsx
                qrLoginDeviceCopy.ts
                QRLoginNumberMatchStep.tsx
                QRLoginRevokedPanel.tsx
                QRLoginSuccessStep.tsx
                QRLoginUnavailableCard.tsx
                SendMagicLinkButton.tsx
                useJetpackPluginState.tsx
                useQRLoginAvailability.ts
                useQRLoginToken.tsx
                useRevokeQRLoginAccess.ts
                useSendMagicLink.tsx
              layouts/
                ModalContentLayoutWithTitle.tsx
                ModalIllustrationLayout.tsx
              pages/
                EmailSentPage.tsx
                index.tsx
                MobileAppLoginStepperPage.tsx
              declaration.d.ts
              index.tsx
            stats-overview/
              defaults.js
              index.js
              install-jetpack-cta.js
              stats-list.js
            wcpay-feature-slot/
              index.ts
              utils.tsx
              wcpay-feature-slot.tsx
            column.js
            index.tsx
            layout.js
            utils.tsx
          hooks/
            use-endpoint-dismiss.ts
            use-option-dismiss.ts
            use-tasklists-state.ts
            useFocusOnMount.js
            useFocusOutside.js
            useIsScrolled.js
          inbox-panel/
            dismiss-all-modal.js
            index.js
            utils.js
          launch-your-store/
            data/
              setup-payments-context.tsx
            hooks/
              use-launch-your-store.tsx
            hub/
              main-content/
                components/
                  resizable-frame.jsx
                pages/
                  launch-store-success/
                    actions.tsx
                    index.tsx
                    services.tsx
                    Survey.tsx
                    WhatsNext.tsx
                  loading.tsx
                  payments-content.tsx
                  site-preview.tsx
                xstate.tsx
              sidebar/
                components/
                  mobile-toggle/
                    index.tsx
                  payments-icons/
                    active-step.jsx
                    completed-step.jsx
                  step-placeholder/
                    index.ts
                    step-placeholder.tsx
                  icons.tsx
                  launch-store-hub.tsx
                  mobile-header.tsx
                  payments-mobile-header.tsx
                  payments-sidebar.tsx
                  sidebar-container.tsx
                tasklist.tsx
                xstate.tsx
              index.tsx
            settings/
              components/
                confirmation-modal.jsx
              slotfill.js
            status/
              index.tsx
            tour/
              index.tsx
              use-site-visibility-tour.tsx
            constants.ts
            index.js
          layout/
            footer/
              footer.tsx
              index.ts
            hooks/
              use-page-classes.ts
            store-alerts/
              index.js
              placeholder.js
            transient-notices/
              snackbar/
                index.js
                list.js
              index.js
            controller.js
            embed.tsx
            index.tsx
            NoMatch.tsx
            notices.js
            shared.tsx
          marketing/
            components/
              CardHeaderDescription/
                CardHeaderDescription.tsx
                index.ts
              CardHeaderTitle/
                CardHeaderTitle.tsx
                index.ts
              CenteredSpinner/
                CenteredSpinner.tsx
                index.ts
              CollapsibleCard/
                CollapsibleCard.tsx
                index.tsx
              CreateNewCampaignModal/
                CreateNewCampaignModal.tsx
                index.ts
              PluginCardBody/
                index.ts
                PluginCardBody.tsx
                SmartPluginCardBody.tsx
              product-icon/
                icons/
                  library/
                    amazon-ebay.js
                    automatewoo-alt.js
                    automatewoo.js
                    blank.js
                    creative-mail.js
                    currency-dollar.js
                    facebook.js
                    gift.js
                    google.js
                    hubspot.js
                    jetpack-crm.js
                    klaviyo.js
                    link.js
                    mailchimp.js
                    mailpoet.js
                    people.js
                    pinterest.js
                    salesforce.js
                    tiktok.js
                    tip.js
                    trustpilot.js
                    vimeo.js
                    zapier.js
                  index.js
                index.js
                README.md
              index.js
              ReadBlogMessage.js
            coupons/
              card/
                index.js
                README.md
              knowledge-base/
                index.js
                placeholder.js
              recommended-extensions/
                index.js
                item.js
                placeholder.js
              slider/
                index.js
              index.js
            data/
              action-types.js
              actions.js
              constants.js
              index.js
              reducer.js
              resolvers.js
              selectors.js
            data-multichannel/
              action-types.ts
              actions.ts
              constants.ts
              controls.ts
              guards.ts
              index.ts
              reducer.ts
              resolvers.ts
              selectors.ts
              types.ts
            hooks/
              index.ts
              useCampaigns.ts
              useCampaignTypes.ts
              useInstalledPluginsWithoutChannels.ts
              useIntroductionBanner.ts
              useRecommendedChannels.ts
              useRegisteredChannels.ts
            overview-multichannel/
              Campaigns/
                Campaigns.tsx
                index.ts
              Channels/
                Channels.tsx
                iconSize.ts
                index.ts
                IssueStatus.tsx
                RegisteredChannelCardBody.tsx
                SyncStatus.tsx
              DiscoverTools/
                DiscoverTools.tsx
                index.ts
                PluginsTabPanel.tsx
                useRecommendedPluginsWithoutChannels.ts
              InstalledExtensions/
                index.ts
                InstalledExtensions.tsx
              IntroductionBanner/
                index.ts
                IntroductionBanner.tsx
              LearnMarketing/
                index.ts
                LearnMarketing.tsx
                PlaceholderPostTile.tsx
                PostTile.tsx
                types.ts
                useBlogPosts.ts
              index.ts
              MarketingOverviewMultichannel.tsx
            types/
              Campaign.ts
              CampaignType.ts
              index.ts
              InstalledPlugin.ts
              RecommendedPlugin.ts
              RegisteredChannel.ts
            utils/
              getRecommendationSource.ts
              index.ts
            README.md
          marketplace/
            components/
              banner/
                banner.tsx
              category-selector/
                category-dropdown.tsx
                category-link.tsx
                category-selector.tsx
                types.ts
              connect-notice/
                connect-notice.tsx
              content/
                content.tsx
              discover/
                discover.tsx
              footer/
                footer.tsx
              header/
                header.tsx
              header-account/
                header-account-modal.tsx
                header-account.tsx
              header-title/
                header-title.tsx
              icon-with-text/
                icon-with-text.tsx
              install-flow/
                create-order.tsx
                install-new-product-modal.tsx
              likert-scale/
                likert-scale.tsx
              load-more-button/
                load-more-button.tsx
              my-subscriptions/
                table/
                  actions/
                    auto-renew-button.tsx
                    connect-account-button.tsx
                    connect-button.tsx
                    connect-modal.tsx
                    install-modal.tsx
                    install.tsx
                    refresh-button.tsx
                    renew-button.tsx
                    renew-modal.tsx
                    subscribe-button.tsx
                    subscribe-modal.tsx
                    update.tsx
                  rows/
                    actions-dropdown-menu.tsx
                    auto-update-status.tsx
                    functions.tsx
                    status-popover.tsx
                    version.tsx
                  table-rows.tsx
                  table.tsx
                constants.ts
                error-utils.ts
                my-subscriptions-account.tsx
                my-subscriptions.tsx
                notices.tsx
                subscriptions-expired-expiring-notice.tsx
                types.ts
              notice/
                notice.tsx
                README.md
              product-card/
                product-card-footer.tsx
                product-card.tsx
              product-list/
                product-list.tsx
                types.ts
              product-list-content/
                no-results.tsx
                product-list-content.tsx
              product-list-header/
                product-list-header.tsx
              product-loader/
                product-loader.tsx
              product-preview-modal/
                product-preview-modal.tsx
                product-preview-sanitize-html-config.tsx
              products/
                products.tsx
              promo-card/
                images/
                  percent.tsx
                promo-card.tsx
              promotions/
                promotions.tsx
                types.ts
              quality-badge/
                quality-badge-filter.tsx
                quality-badge.tsx
              search/
                search.tsx
              tabs/
                tabs.tsx
              woo-update-manager-plugin/
                install-woo-connect-modal.tsx
                plugin-install-notice.tsx
              constants.ts
            contexts/
              install-store.tsx
              marketplace-context.tsx
              notice-store.tsx
              subscriptions-context.tsx
              types.ts
            utils/
              functions.tsx
              tracking.ts
            index.tsx
            README.md
          mobile-app-login/
            index.tsx
            README.md
          mobile-banner/
            app-icon.js
            banner.js
            constants.js
            index.js
          order-attribution-install-banner/
            order-editor/
              slot.js
            constants.js
            index.js
            order-attribution-install-banner-image.js
            order-attribution-install-banner.js
            use-order-attribution-install-banner.js
          payments/
            index.ts
            payment-recommendations-wrapper.tsx
            payment-recommendations.tsx
            payment-settings-banner.tsx
            payments-settings-banner-slotfill.js
            use-payments-banner.ts
            utils.ts
          payments-welcome/
            apms.tsx
            banner.tsx
            exit-survey-modal.tsx
            faq-simple.tsx
            index.tsx
            strings.tsx
          settings/
            conflict-error-slotfill.js
            settings-slots.js
            settings-ui-registry.tsx
          settings-email/
            build-email-editor-review-url.ts
            icon-feedback.tsx
            settings-email-ces-feedback.tsx
            settings-email-color-palette-control.tsx
            settings-email-color-palette-functions.tsx
            settings-email-color-palette-slotfill.tsx
            settings-email-feedback-slotfill.tsx
            settings-email-image-url-existing-image.tsx
            settings-email-image-url-handlers.tsx
            settings-email-image-url-new-image.tsx
            settings-email-image-url-slotfill.tsx
            settings-email-listing-data.ts
            settings-email-listing-listview.tsx
            settings-email-listing-recipients.tsx
            settings-email-listing-slotfill.tsx
            settings-email-listing-status.tsx
            settings-email-listing-update-cell.story.tsx
            settings-email-listing-update-cell.tsx
            settings-email-listing-update-state.ts
            settings-email-preview-device-type.tsx
            settings-email-preview-header.tsx
            settings-email-preview-iframe.tsx
            settings-email-preview-nonce.tsx
            settings-email-preview-send.tsx
            settings-email-preview-slotfill.tsx
            settings-email-preview-type.tsx
            settings-email-send-test.tsx
          settings-payments/
            components/
              bank-accounts-list/
                bank-account-modal.tsx
                bank-accounts-list.tsx
                index.ts
                types.ts
                utils.ts
                validation.ts
              buttons/
                activate-payments-button.tsx
                back-button.tsx
                complete-setup-button.tsx
                enable-gateway-button.tsx
                index.ts
                reactivate-live-payments-button.tsx
                settings-button.tsx
              country-selector/
                country-selector.tsx
                index.ts
                types.ts
              ellipsis-menu-content/
                ellipsis-menu-content.tsx
                ellipsis-menu.tsx
                index.ts
              field-placeholder/
                field-placeholder.tsx
                index.ts
              grid-item-placeholder/
                grid-item-placeholder.tsx
                index.ts
              header/
                header.tsx
              incentive-banner/
                incentive-banner.tsx
                index.ts
              incentive-modal/
                incentive-modal.tsx
                index.ts
              incentive-status-badge/
                incentive-status-badge.tsx
                index.ts
              list-placeholder/
                index.ts
                list-placeholder.tsx
              modals/
                index.ts
                woo-payments-post-sandbox-account-setup-modal.tsx
                woo-payments-reset-account-modal.tsx
                woo-payments-update-required-modal.tsx
              official-badge/
                index.ts
                official-badge.tsx
              offline-payment-gateway-list/
                index.ts
                offline-payment-gateway-list.tsx
              other-payment-gateways/
                index.ts
                other-payment-gateways.tsx
              payment-extension-suggestion-list-item/
                index.ts
                payment-extension-suggestion-list-item.tsx
              payment-gateway-list/
                index.ts
                payment-gateway-list.tsx
              payment-gateway-list-item/
                index.ts
                payment-gateway-list-item.tsx
              payment-gateways/
                index.ts
                payment-gateways.tsx
              settings/
                index.tsx
              sortable/
                index.tsx
                sortable-container.tsx
                sortable-drag-handle.tsx
                sortable-item.tsx
              status-badge/
                index.ts
                status-badge.tsx
            offline/
              dataform-controls.tsx
              settings-payments-bacs.tsx
              settings-payments-cheque.tsx
              settings-payments-cod.tsx
              utils.ts
            onboarding/
              components/
                modal/
                  index.tsx
                stepper/
                  index.tsx
                  sidebar-item.tsx
              providers/
                woopayments/
                  components/
                    banner-notice/
                      index.tsx
                    custom-select-control/
                      index.tsx
                    grouped-select-control/
                      index.tsx
                    header/
                      index.tsx
                    onboarding/
                      index.tsx
                    snackbar/
                      index.tsx
                    stripe-spinner/
                      index.tsx
                  data/
                    onboarding-context.tsx
                  steps/
                    business-verification/
                      components/
                        embedded/
                          appearance.ts
                          index.tsx
                        form/
                          fields.tsx
                          index.tsx
                        step/
                          index.tsx
                        stepper/
                          index.tsx
                      data/
                        business-verification-context.tsx
                      sections/
                        activate-payments.tsx
                        business-details.tsx
                        embedded-kyc.tsx
                      translations/
                        descriptions.tsx
                      utils/
                        actions.ts
                        index.ts
                        validation.ts
                      index.tsx
                      strings.tsx
                      types.ts
                    finish/
                      index.tsx
                    payment-methods-selection/
                      index.tsx
                      list-item.tsx
                    test-account/
                      index.tsx
                    test-or-live-account/
                      index.tsx
                    wpcom-connection/
                      index.tsx
                    index.tsx
                  index.tsx
              types.ts
            CLAUDE.md
            constants.ts
            index.tsx
            settings-payments-main.tsx
            settings-payments-offline.tsx
            settings-payments-woopayments.tsx
            utils.ts
          settings-recommendations/
            dismissable-list.tsx
            recommendations-eligibility-wrapper.tsx
          shipping/
            index.ts
            packlink-item.tsx
            shipping-recommendations-utils.tsx
            shipping-recommendations-wrapper.tsx
            shipping-recommendations.tsx
            shipstation-item.tsx
            woocommerce-shipping-item.tsx
          store-management-links/
            quick-link/
              index.js
            quick-link-category/
              index.js
            index.js
          task-lists/
            components/
              progress-header/
                default-progress-header.tsx
                index.ts
                progress-header.tsx
                utils.tsx
              back-button.tsx
              placeholder.tsx
              task-list-item.tsx
              task-list-menu.tsx
              task-list.tsx
              task.tsx
              terms-of-service.js
            fills/
              components/
                load-sample-product-confirm-modal.tsx
                load-sample-product-modal.tsx
                use-load-sample-products.ts
              import-products/
                CardList.tsx
                importTypes.tsx
                index.tsx
              Marketing/
                index.tsx
                Plugin.tsx
                PluginList.tsx
                TaskPromo.tsx
              PaymentGatewaySuggestions/
                components/
                  List/
                    index.js
                    Item.js
                    List.js
                    Placeholder.js
                  Setup/
                    Configure.js
                    index.js
                    Placeholder.js
                    Setup.js
                  Toggle/
                    index.js
                    Toggle.js
                  WCPay/
                    index.js
                    Suggestion.tsx
                    UsageModal.js
                    utils.js
                  WCPayBNPL/
                    index.js
                    Suggestion.js
                  Action.js
                plugins/
                  Bacs.js
                index.js
                utils.js
              products/
                icon/
                  lightbulb_24px.js
                  link_24px.js
                  upload_40px.js
                  widgets_24px.js
                constants.tsx
                index.tsx
                stack.tsx
                use-create-product-by-type.ts
                use-product-types-list-items.tsx
                utils.tsx
              shipping/
                shipping-providers/
                  partners.tsx
                index.js
                rates.js
                single-partner-features.ts
              shipping-recommendation/
                components/
                  connect.tsx
                  plugin-banner.tsx
                  plugins.tsx
                  store-location.tsx
                  wcs-banner.tsx
                index.tsx
                shipping-recommendation.tsx
                types.ts
                utils.ts
              steps/
                location.tsx
              tax/
                components/
                  bullet.tsx
                  partner-card.tsx
                  partners.tsx
                  store-location.tsx
                manual-configuration/
                  configure.tsx
                  index.tsx
                stripe-tax/
                  card.tsx
                woocommerce-tax/
                  automated-taxes.tsx
                  card.tsx
                  connect.tsx
                  index.tsx
                  plugins.tsx
                  setup.tsx
                index.tsx
                utils.ts
              appearance.js
              deprecated-tasks.tsx
              index.ts
              launch-your-store.tsx
              purchase.tsx
              use-record-completion-time.ts
              utils.js
              woocommerce-payments.tsx
            progress-title/
              default-progress-title.tsx
              index.ts
              progress-title.tsx
              utils.tsx
            setup-task-list/
              components/
                task-headers/
                  appearance.js
                  customize-store.tsx
                  default.tsx
                  index.ts
                  launch-your-store.tsx
                  marketing.js
                  payments.js
                  products.js
                  purchase.js
                  shipping.js
                  store-details.js
                  tax.js
                  woocommerce-payments.js
                dismiss-modal.tsx
                task-list-completed-header.tsx
                task-list-completed.tsx
                task-list-item.tsx
                task-list-placeholder.tsx
              footer-slot/
                footer-slot.tsx
                index.ts
                utils.tsx
              task-list-completion-slot/
                index.ts
                task-list-completion-slot.tsx
                utils.tsx
              index.ts
              setup-task-list.tsx
            index.ts
            task-lists.tsx
          tax/
            index.ts
            tax-recommendations-wrapper.tsx
            tax-recommendations.tsx
          typings/
            global.d.ts
            index.d.ts
            monorepo-enhancements.d.ts
          utils/
            features/
              features.ts
              index.ts
              retired-feature-flags.ts
              types.ts
            react-hooks/
              use-network-status.tsx
            xstate/
              find-component.tsx
              url-handling.ts
              useComponentFromService.tsx
              useMobileHeaderFromService.tsx
            admin-settings.js
            derive-wp-admin-background-colours.ts
            enqueue-script.js
            index.js
            is-woo-express.ts
            localStorage.ts
            plugins.ts
            README.md
            static-form-helper.ts
            url-helpers.ts
            use-filter-hook.ts
          wp-admin-scripts/
            add-term-tracking/
              index.js
            attributes-tracking/
              index.js
            category-tracking/
              index.js
            command-palette/
              index.js
              register-command-with-tracking.js
            command-palette-analytics/
              index.js
            email-editor-integration/
              hooks/
                use-apply-update.ts
                use-change-summary.ts
                use-update-banner.ts
              templates/
                index.tsx
                template_sender_panel.tsx
              tracks/
                build-shared-payload.ts
              constants.ts
              email-status.tsx
              email-validation.ts
              global.d.ts
              index.ts
              reset-notification-email-content.tsx
              review-drawer.tsx
              review-update-plugin.tsx
              save-button.tsx
              sidebar_settings.tsx
              store.ts
              update-banner-plugin.tsx
              update-banner.tsx
            fulfillments/
              components/
                action-buttons/
                  cancel-link.tsx
                  edit-fulfillment-button.tsx
                  fulfill-items-button.tsx
                  remove-button.tsx
                  save-draft-button.tsx
                  update-button.tsx
                customer-notification-form/
                  index.tsx
                fulfillments/
                  fulfillment-editor.tsx
                  fulfillment-line-item.tsx
                  fulfillment-status-badge.tsx
                  fulfillments-list.tsx
                  item-selector.tsx
                  new-fulfillment-form.tsx
                metadata-viewer/
                  index.tsx
                shipment-form/
                  index.tsx
                  shipment-manual-entry-form.tsx
                  shipment-tracking-number-form.tsx
                  shipment-viewer.tsx
                user-interface/
                  fulfillment-drawer/
                    fulfillment-drawer-body.tsx
                    fulfillment-drawer-header.tsx
                    fulfillment-drawer.tsx
                  fulfillments-card/
                    card.tsx
                  meta-list/
                    meta-list.tsx
                  error-label.tsx
                  lock-label.tsx
              context/
                drawer-context.tsx
                fulfillment-context.tsx
                shipment-form-context.tsx
              data/
                constants.ts
                shipment-providers.tsx
                store.ts
                types.ts
              test-helper/
                global-mock.ts
              utils/
                fulfillment-utils.ts
                icons.tsx
                order-utils.ts
              global.d.ts
              index.tsx
            marketing-coupons/
              index.js
            marketplace-orders-promo/
              index.tsx
            onboarding-homepage-notice/
              index.js
            onboarding-load-sample-products-notice/
              index.ts
            onboarding-product-import-notice/
              index.js
            onboarding-tax-notice/
              index.js
            order-milestone-easter-egg/
              index.js
            order-tracking/
              exit-order-page.ts
              index.ts
            payment-method-promotions/
              index.tsx
              payment-promotion-row.tsx
            print-shipping-label-banner/
              dismiss-modal/
                index.js
              setup-notice/
                index.js
              shipping-banner/
                index.js
              index.js
              wcs-api.js
            product-import-tracking/
              index.ts
              product-import-tracking.ts
            product-tour/
              index.tsx
            product-tracking/
              global.d.ts
              index.ts
              product-edit.ts
              product-new.ts
              products-list.ts
              shared.ts
              utils.ts
            settings-embed/
              index.tsx
            settings-tracking/
              exit-setting-page.ts
              index.ts
              marketplace-link-tracking.ts
            shipping-settings-region-picker/
              currency-context.js
              index.js
              region-picker.js
              utils.js
            tags-tracking/
              index.js
            variable-product-tour/
              index.tsx
            visual-attribute-picker/
              image-field.tsx
              index.tsx
              type-switcher.tsx
              utils.ts
            wc-addons-tour/
              index.tsx
            wcsettings-deprecation/
              index.js
            woo-connect-notice/
              index.js
            woo-enable-autorenew/
              index.js
            woo-plugin-update-connect-notice/
              index.js
            woo-product-usage-notice/
              actions.js
              index.js
              modal.js
            woo-purchase-subscription/
              index.js
            woo-renew-subscription/
              index.js
            woo-subscriptions-notice/
              index.js
            README.md
          embed.tsx
          index.tsx
          jest.config.js
          shared.tsx
          xstate.js
        config/
          core.json
          development.json
        docs/
          examples/
            extensions/
              add-abbreviated-notification/
                js/
                  index.js
                woocommerce-admin-add-abbreviated-notification-example.php
              important-admin-notice/
                js/
                  index.js
                woocommerce-admin-important-admin-notice-example.php
              simple-inbox-note/
                js/
                  index.js
                class-simpleinboxnote.php
                woocommerce-admin-simple-inbox-note-example.php
              examples.config.js
              README.md
            activity-panel-inbox.md
            README.md
          features/
            core-profiler.md
            feature-flags.md
            fulfillments-hooks.md
            fulfillments-rest-api.md
            onboarding-tasks.md
            onboarding.md
            payment-gateway-suggestions.md
            README.md
            transient-notices.md
          woocommerce.com/
            activity-panels.md
            analytics-basics.md
            analytics-categories-report.md
            analytics-coupons-report.md
            analytics-customers-report.md
            analytics-dashboard.md
            analytics-downloads-report.md
            analytics-historical-data-import.md
            analytics-orders-report.md
            analytics-products-report.md
            analytics-revenue-report.md
            analytics-settings.md
            analytics-stock-report.md
            analytics-taxes-report.md
            analytics-variations-report.md
            README.md
          data.md
          layout.md
          page-controller.md
          README.md
          stylesheets.md
          xstate.md
        .browserslistrc
        .gitattributes
        .prettierrc.js
        babel.config.js
        CLAUDE.md
        composer.json
        eslint.config.mjs
        package.json
        README.md
        stylelint.config.js
        tsconfig.json
        webpack.config.js
      blocks/
        changelog/
          65429-fix-rtl-settings-modal-buttons
          66286-add-review-block-offset
          add-cart-item-data-raw-key
          clarify-blocks-package-api-boundaries
          dev-deprecate-wc-entities-global
          dev-remove-unused-markdown-it
          remove-old-blocks-release-testing
          testops-234-add-to-cart-form
          testops-234-add-to-cart-with-options
          testops-234-cart-checkout-extensibility
          testops-234-cart-checkout-shopper-journeys
          testops-234-catalog-sorting
          testops-234-checkout-block-shopper
          testops-234-customer-account-block
          testops-234-fix-js-ci-changes-globs
          testops-234-name-slugs-in-unregister-block-types-test
          testops-234-product-collection-frontend
          testops-234-product-collection-registration
          testops-234-product-filters-block
          testops-234-product-gallery
          testops-234-product-results-count
          testops-234-refresh-block-manifest-copies
          testops-234-unregister-block-types
        docs/
          contributors/
            block-assets.md
            coding-guidelines.md
            components.md
            css-build-system.md
            documentation-guidelines.md
            e2e-guidelines.md
            folder-structure.md
            getting-started.md
            javascript-build-system.md
            javascript-testing.md
            README.md
            storybook-and-components.md
          designers/
            theming/
              class-names-update-280.md
              class-names-update-330.md
              class-names-update-340.md
              class-names-update-460.md
              filter-blocks.md
              product-grid-270.md
          examples/
            checkout-order-processed.md
            payment-gateways-features-list.md
            validate-cart.md
          internal-developers/
            automations/
              dependabot.md
              README.md
            block-client-apis/
              checkout/
                checkout-api.md
              notices.md
              README.md
            blockified-templates/
              compatibility-layer.md
            blocks/
              feature-flags-and-experimental-interfaces.md
              inner-block-protocols.md
              README.md
              stock-reservation.md
            data-store/
              checkout.md
              README.md
              validation.md
            enqueueable-packages/
              README.md
            rest-api/
              extend-rest-api-new-endpoint.md
              README.md
            templates/
              block-template-controller.md
              classic-template.md
              individual-template-classes.md
              README.md
            testing/
              cart-checkout/
                compatibility.md
                coupons.md
                cross-browser.md
                data-stores.md
                editor.md
                general-flow.md
                items.md
                local-pickup.md
                payment.md
                README.md
                shipping.md
                taxes.md
              README.md
              smoke-testing.md
              when-to-employ-e2e-testing.md
            translations/
              README.md
              translation-basics.md
              translation-loading.md
              translation-management.md
              translations-for-lazy-loaded-components.md
              translations-in-FSE-templates.md
              translations-in-JS-TS-files.md
              translations-in-PHP-files.md
          third-party-developers/
            extensibility/
              data-store/
                cart.md
                checkout.md
                collections.md
                payment.md
                query-state.md
                README.md
                schema.md
                store-notices.md
                validation.md
              hooks/
                actions.md
                filters.md
                hook-alternatives.md
                migrated-hooks.md
                README.md
              rest-api/
                available-endpoints-to-extend.md
                extend-rest-api-add-custom-fields.md
                extend-rest-api-add-data.md
                extend-rest-api-formatters.md
                extend-rest-api-update-cart.md
                README.md
          README.md
        packages/
          internal/
            entities/
              product/
                constants.ts
                guards.ts
                hooks.ts
                index.ts
                types.ts
              settings/
                constants.ts
                index.ts
                types.ts
              index.ts
              README.md
              register-entities.ts
              types.ts
            README.md
          public-api/
            block-data/
              cart/
                action-types.ts
                actions.ts
                constants.ts
                default-state.ts
                index.ts
                notify-errors.ts
                notify-quantity-changes.ts
                persistence-layer.ts
                push-changes.ts
                README.md
                reducers.ts
                resolvers.ts
                selectors.ts
                thunks.ts
                update-payment-methods.ts
                utils.ts
              checkout/
                action-types.ts
                actions.ts
                constants.ts
                default-state.ts
                index.ts
                push-changes.ts
                README.md
                reducers.ts
                selectors.ts
                thunks.ts
                types.ts
                utils.ts
              collections/
                action-types.js
                actions.js
                constants.js
                index.js
                README.md
                reducers.js
                resolvers.js
                selectors.js
              payment/
                utils/
                  check-payment-methods.ts
                  filter-active-saved-payment-methods.ts
                  set-default-payment-method.ts
                action-types.ts
                actions.ts
                constants.ts
                default-state.ts
                index.ts
                README.md
                reducers.ts
                selectors.ts
                store-config.ts
                thunks.ts
                types.ts
              query-state/
                action-types.js
                actions.js
                constants.js
                index.js
                README.md
                reducers.js
                selectors.js
                utils.js
              schema/
                action-types.js
                actions.js
                constants.js
                index.js
                README.md
                reducers.js
                resolvers.js
                selectors.js
                utils.js
              store-notices/
                action-types.ts
                actions.ts
                default-state.ts
                index.ts
                README.md
                reducers.ts
                selectors.ts
              utils/
                clear-put-requests.ts
                has-in-state.ts
                index.js
                is-editor.ts
                process-error-response.ts
                update-state.ts
              validation/
                action-types.ts
                actions.ts
                constants.ts
                index.ts
                README.md
                reducers.ts
                selectors.ts
              constants.ts
              index.ts
              README.md
              shared-controls.ts
            blocks-checkout/
              blocks-registry/
                get-registered-blocks.ts
                index.ts
                README.md
                register-checkout-block.ts
                registered-blocks.ts
                types.ts
                utils.ts
              components/
                checkbox-control/
                  index.tsx
                discounts-meta/
                  index.js
                error-boundary/
                  index.js
                label/
                  index.ts
                order-local-pickup-packages/
                  index.tsx
                order-meta/
                  index.js
                order-shipping-packages/
                  index.js
                text-input/
                  index.tsx
                validation-input-error/
                  index.tsx
                index.ts
                README.md
              filter-registry/
                index.ts
                README.md
              hooks/
                index.ts
                README.md
                use-validate-checkout.ts
              slot/
                index.tsx
                README.md
                test-utils.tsx
              utils/
                validation/
                  get-validity-message-for-input.ts
                  index.ts
                  is-postcode.ts
                  must-contain.ts
                  validate-filter.ts
                extension-cart-update.ts
                index.js
                README.md
              index.js
              README.md
            blocks-checkout-events/
              checkout-events.ts
              event-emitter.ts
              index.ts
            blocks-components/
              button/
                index.ts
              checkbox-control/
                stories/
                  index.stories.tsx
                index.tsx
                validated-checkbox-control.tsx
              checkbox-list/
                stories/
                  index.stories.tsx
                checkbox-list-option-control.tsx
                index.tsx
                types.ts
              chip/
                stories/
                  chip.stories.tsx
                  removable-chip.stories.tsx
                chip.tsx
                index.ts
                removable-chip.tsx
              form-step/
                stories/
                  index.stories.tsx
                index.tsx
              formatted-monetary-amount/
                stories/
                  index.stories.tsx
                index.tsx
              label/
                stories/
                  index.stories.tsx
                index.tsx
              panel/
                stories/
                  index.stories.tsx
                index.tsx
              radio-control/
                stories/
                  index.stories.tsx
                index.tsx
                option-layout.tsx
                option.tsx
                types.ts
              radio-control-accordion/
                stories/
                  index.stories.tsx
                index.tsx
              sort-select/
                stories/
                  index.stories.tsx
                index.tsx
              spinner/
                stories/
                  index.stories.tsx
                index.tsx
              store-notice/
                stories/
                  index.stories.tsx
                index.tsx
              store-notices-container/
                index.tsx
                snackbar-notices.tsx
                store-notices.tsx
                types.ts
              text-input/
                stories/
                  text-input.stories.tsx
                  validated-text-input.stories.tsx
                text-input.tsx
                types.ts
                validated-text-input.tsx
              textarea/
                stories/
                  index.stories.tsx
                index.tsx
              title/
                stories/
                  index.stories.tsx
                index.tsx
              totals/
                fees/
                  stories/
                    index.stories.tsx
                  index.tsx
                item/
                  stories/
                    index.stories.tsx
                  index.tsx
                subtotal/
                  stories/
                    index.stories.tsx
                  index.tsx
                taxes/
                  stories/
                    index.stories.tsx
                  index.tsx
                index.js
              totals-wrapper/
                docs/
                  docs.mdx
                stories/
                  index.stories.tsx
                index.tsx
              validation-input-error/
                stories/
                  index.stories.tsx
                index.tsx
              index.ts
            blocks-registry/
              block-components/
                get-registered-block-components.ts
                index.js
                register-block-component.js
                registered-block-components-init.ts
              payment-methods/
                assertions.ts
                express-payment-method-config.ts
                extensions-config.ts
                index.ts
                payment-method-config-helper.ts
                payment-method-config.tsx
                registry.ts
              product-collection/
                register-product-collection.tsx
              index.js
            entity-registration/
              deprecated-exports.ts
              index.ts
              README.md
              register-entities.ts
            price-format/
              utils/
                currency.ts
                index.js
                price.ts
              index.js
            settings/
              default-constants.ts
              default-fields.ts
              index.ts
              settings-init.ts
              utils.ts
            shared-context/
              custom-data-context.tsx
              index.js
              inner-block-layout-context.tsx
              product-data-context.tsx
            shared-hocs/
              index.js
              with-filtered-attributes.js
              with-product-data-context.js
            types/
              type-defs/
                add-to-cart-form.js
                address-autocomplete.ts
                address-fields.js
                api-error-response.ts
                api-response.ts
                attributes.ts
                billing.js
                blocks.ts
                cart-response.ts
                cart.js
                cart.ts
                checkout.ts
                contexts.js
                contexts.ts
                countries.ts
                currency.ts
                events.ts
                hocs.ts
                hooks.js
                hooks.ts
                index.ts
                notices.ts
                objects.ts
                payment-method-interface.ts
                payments.ts
                product-category-response.ts
                product-response.ts
                range-input.ts
                removable-items.ts
                selectable-items.ts
                settings.js
                shipping.js
                shipping.ts
                stock-status.ts
                taxes.ts
                trim-html.d.ts
                utils.ts
                validation.ts
              type-guards/
                address.ts
                api-error-response.ts
                attributes.ts
                boolean.ts
                cart-response-totals.ts
                empty.ts
                error.ts
                form-fields.ts
                function.ts
                index.ts
                null.ts
                number.ts
                object.ts
                observers.ts
                ratings.ts
                stock-status.ts
                string.ts
                validation.ts
              index.ts
            AGENTS.md
            README.md
        storybook/
          __mocks__/
            woocommerce-base-hooks.js
            woocommerce-block-settings.js
          custom-controls/
            currency.ts
            index.ts
          main.mjs
          preview.js
          README.md
          webpack.config.js
        typings/
          monorepo-enhancements.d.ts
        .browserslistrc
        .gitattributes
        .markdownlint.json
        .prettierrc.js
        .stylelintrc.json
        babel.config.js
        blocks.ini
        CLAUDE.md
        composer.json
        docker-compose.yml
        eslint.config.mjs
        global.d.ts
        LICENSE
        package.json
        postcss.config.js
        README.md
        readme.txt
        tsconfig.base.json
        tsconfig.json
        webpack.config.js
        wp-cli.yml
      legacy/
        js/
          accounting/
            accounting.js
          admin/
            utils/
              maybe-modify-decimal.js
              number-validation.js
            api-keys.js
            backbone-modal.js
            marketplace-suggestions.js
            meta-boxes-coupon.js
            meta-boxes-order.js
            meta-boxes-product-variation.js
            meta-boxes-product.js
            meta-boxes.js
            network-orders.js
            order-attribution-admin.js
            product-editor.js
            product-ordering.js
            quick-edit.js
            reports.js
            settings-views-html-settings-tax.js
            settings.js
            system-status.js
            term-ordering.js
            users.js
            variation-gallery.js
            wc-admin-notices.js
            wc-brands-enhanced-select.js
            wc-clipboard.js
            wc-customer-stock-notifications.js
            wc-enhanced-select.js
            wc-orders.js
            wc-product-export.js
            wc-product-import.js
            wc-recent-reviews-widget-async.js
            wc-setup.js
            wc-shipping-classes.js
            wc-shipping-providers.js
            wc-shipping-zone-methods.js
            wc-shipping-zones.js
            wc-status-widget-async.js
            wc-status-widget.js
            woocommerce_admin.js
          dompurify/
            purify.js
          flexslider/
            jquery.flexslider.js
          frontend/
            utils/
              address-autocomplete-common.js
              custom-place-order-button.js
            a8c-address-autocomplete-service.js
            account-i18n.js
            add-payment-method.js
            add-to-cart-variation.js
            add-to-cart.js
            address-autocomplete.js
            address-i18n.js
            back-in-stock-form.js
            cart-fragments.js
            cart.js
            checkout.js
            country-select.js
            credit-card-form.js
            geolocation.js
            lost-password.js
            order-attribution.js
            order-review.js
            password-strength-meter.js
            price-slider.js
            single-product.js
            tokenization-form.js
            woocommerce.js
            wp-consent-api-integration.js
          gateways/
            paypal.js
          jquery-blockui/
            jquery.blockUI.js
          jquery-cookie/
            jquery.cookie.js
          jquery-flot/
            jquery.flot.js
            jquery.flot.pie.js
            jquery.flot.resize.js
            jquery.flot.stack.js
            jquery.flot.time.js
          jquery-payment/
            jquery.payment.js
          jquery-qrcode/
            jquery.qrcode.js
          jquery-serializejson/
            jquery.serializejson.js
          jquery-tiptip/
            jquery.tipTip.js
          jquery-ui-touch-punch/
            jquery-ui-touch-punch.js
          js-cookie/
            js.cookie.js
          photoswipe/
            photoswipe-ui-default.js
            photoswipe.js
          prettyPhoto/
            jquery.prettyPhoto.init.js
            jquery.prettyPhoto.js
          round/
            round.js
          select2/
            select2.full.js
            select2.js
          selectWoo/
            selectWoo.full.js
            selectWoo.js
          stupidtable/
            stupidtable.js
          zoom/
            jquery.zoom.js
        .browserslistrc
        .stylelintrc
        babel-transformer.js
        eslint.config.mjs
        Gruntfile.js
        jest.config.json
        package.json
    i18n/
      languages/
        README.md
      continents.php
      countries.php
      currencies.php
      currency-info.php
      locale-info.php
      phone.php
      postcode-validation-rules.json
      README.md
      states.php
      units.php
    includes/
      abstracts/
        abstract-wc-address-provider.php
        abstract-wc-data.php
        abstract-wc-deprecated-hooks.php
        abstract-wc-integration.php
        abstract-wc-log-handler.php
        abstract-wc-object-query.php
        abstract-wc-order.php
        abstract-wc-payment-gateway.php
        abstract-wc-payment-token.php
        abstract-wc-privacy.php
        abstract-wc-product.php
        abstract-wc-session.php
        abstract-wc-settings-api.php
        abstract-wc-shipping-method.php
        abstract-wc-widget.php
        class-wc-background-process.php
      admin/
        helper/
          views/
            html-helper-compat.php
            html-main.php
            html-notice-woo-updater-not-activated.php
            html-notice-woo-updater-not-installed.php
            html-oauth-start.php
            html-section-account.php
            html-section-nav.php
            html-section-notices.php
          class-wc-helper-admin.php
          class-wc-helper-api-backoff.php
          class-wc-helper-api.php
          class-wc-helper-compat.php
          class-wc-helper-options.php
          class-wc-helper-orders-api.php
          class-wc-helper-sanitization.php
          class-wc-helper-subscriptions-api.php
          class-wc-helper-updater.php
          class-wc-helper.php
          class-wc-plugin-api-updater.php
          class-wc-product-usage-notice.php
          class-wc-woo-helper-connection.php
          class-wc-woo-update-manager-plugin.php
        importers/
          mappings/
            default.php
            generic.php
            mappings.php
            shopify.php
            wordpress.php
          views/
            html-csv-import-done.php
            html-csv-import-footer.php
            html-csv-import-header.php
            html-csv-import-mapping.php
            html-csv-import-progress.php
            html-csv-import-steps.php
            html-product-csv-import-form.php
          class-wc-product-csv-importer-controller.php
          class-wc-tax-rate-importer.php
        list-tables/
          abstract-class-wc-admin-list-table.php
          class-wc-admin-list-table-coupons.php
          class-wc-admin-list-table-orders.php
          class-wc-admin-list-table-products.php
        marketplace-suggestions/
          templates/
            html-product-data-extensions.php
          views/
            container.php
          class-wc-marketplace-suggestions.php
          class-wc-marketplace-updater.php
        meta-boxes/
          views/
            html-order-download-permission.php
            html-order-fee.php
            html-order-item-meta.php
            html-order-item.php
            html-order-items.php
            html-order-notes.php
            html-order-refund.php
            html-order-shipping.php
            html-product-attribute-inner.php
            html-product-attribute.php
            html-product-data-advanced.php
            html-product-data-attributes.php
            html-product-data-general.php
            html-product-data-inventory.php
            html-product-data-linked-products.php
            html-product-data-panel.php
            html-product-data-shipping.php
            html-product-data-variations.php
            html-product-download.php
            html-product-variation-download.php
            html-variation-admin.php
          class-wc-meta-box-coupon-data.php
          class-wc-meta-box-order-actions.php
          class-wc-meta-box-order-data.php
          class-wc-meta-box-order-downloads.php
          class-wc-meta-box-order-items.php
          class-wc-meta-box-order-notes.php
          class-wc-meta-box-product-categories.php
          class-wc-meta-box-product-data.php
          class-wc-meta-box-product-images.php
          class-wc-meta-box-product-reviews.php
          class-wc-meta-box-product-short-description.php
        notes/
          class-wc-notes-refund-returns.php
          class-wc-notes-run-db-update.php
        plugin-updates/
          views/
            html-notice-untested-extensions-inline.php
            html-notice-untested-extensions-modal.php
          class-wc-plugin-updates.php
          class-wc-plugins-screen-updates.php
          class-wc-updates-screen-updates.php
        settings/
          views/
            class-wc-settings-rest-api.php
            html-admin-page-shipping-classes.php
            html-admin-page-shipping-providers.php
            html-admin-page-shipping-zone-methods.php
            html-admin-page-shipping-zones-instance.php
            html-admin-page-shipping-zones.php
            html-keys-edit.php
            html-settings-tax.php
            html-webhooks-edit.php
            settings-tax.php
          class-wc-settings-accounts.php
          class-wc-settings-advanced.php
          class-wc-settings-checkout.php
          class-wc-settings-emails.php
          class-wc-settings-general.php
          class-wc-settings-integrations.php
          class-wc-settings-page.php
          class-wc-settings-payment-gateways.php
          class-wc-settings-point-of-sale.php
          class-wc-settings-products.php
          class-wc-settings-shipping.php
          class-wc-settings-site-visibility.php
          class-wc-settings-tax.php
        views/
          html-admin-dashboard-setup.php
          html-admin-page-addons-category-nav.php
          html-admin-page-product-export.php
          html-admin-page-reports.php
          html-admin-page-status-logs-db.php
          html-admin-page-status-logs.php
          html-admin-page-status-report.php
          html-admin-page-status-tools.php
          html-admin-page-status.php
          html-admin-settings.php
          html-bulk-edit-product.php
          html-email-template-preview.php
          html-notice-custom.php
          html-notice-update.php
          html-notice-updated.php
          html-notice-updating.php
          html-quick-edit-product.php
          html-report-by-date.php
        class-wc-admin-addons.php
        class-wc-admin-api-keys-table-list.php
        class-wc-admin-api-keys.php
        class-wc-admin-assets.php
        class-wc-admin-attributes.php
        class-wc-admin-brands.php
        class-wc-admin-customize.php
        class-wc-admin-dashboard-setup.php
        class-wc-admin-dashboard.php
        class-wc-admin-duplicate-product.php
        class-wc-admin-exporters.php
        class-wc-admin-help.php
        class-wc-admin-importers.php
        class-wc-admin-log-table-list.php
        class-wc-admin-marketplace-promotions.php
        class-wc-admin-menus.php
        class-wc-admin-meta-boxes.php
        class-wc-admin-notices.php
        class-wc-admin-permalink-settings.php
        class-wc-admin-pointers.php
        class-wc-admin-post-types.php
        class-wc-admin-profile.php
        class-wc-admin-reports.php
        class-wc-admin-settings.php
        class-wc-admin-setup-wizard.php
        class-wc-admin-status.php
        class-wc-admin-taxonomies.php
        class-wc-admin-upload-downloadable-product.php
        class-wc-admin-webhooks-table-list.php
        class-wc-admin-webhooks.php
        class-wc-admin.php
        wc-admin-functions.php
        wc-meta-box-functions.php
        woocommerce-legacy-reports.php
      blocks/
        class-wc-blocks-utils.php
      cli/
        class-wc-cli-com-command.php
        class-wc-cli-com-extension-command.php
        class-wc-cli-rest-command.php
        class-wc-cli-runner.php
        class-wc-cli-tool-command.php
        class-wc-cli-tracker-command.php
        class-wc-cli-update-command.php
      customizer/
        class-wc-customizer-control-cropping.php
        class-wc-shop-customizer.php
      data-stores/
        abstract-wc-order-data-store-cpt.php
        abstract-wc-order-item-type-data-store.php
        class-wc-coupon-data-store-cpt.php
        class-wc-customer-data-store-session.php
        class-wc-customer-data-store.php
        class-wc-customer-download-data-store.php
        class-wc-customer-download-log-data-store.php
        class-wc-data-store-wp.php
        class-wc-order-data-store-cpt.php
        class-wc-order-item-coupon-data-store.php
        class-wc-order-item-data-store.php
        class-wc-order-item-fee-data-store.php
        class-wc-order-item-product-data-store.php
        class-wc-order-item-shipping-data-store.php
        class-wc-order-item-tax-data-store.php
        class-wc-order-refund-data-store-cpt.php
        class-wc-payment-token-data-store.php
        class-wc-product-data-store-cpt.php
        class-wc-product-grouped-data-store-cpt.php
        class-wc-product-variable-data-store-cpt.php
        class-wc-product-variation-data-store-cpt.php
        class-wc-shipping-zone-data-store.php
        class-wc-webhook-data-store.php
      emails/
        class-wc-email-admin-payment-gateway-enabled.php
        class-wc-email-cancelled-order.php
        class-wc-email-customer-cancelled-order.php
        class-wc-email-customer-completed-order.php
        class-wc-email-customer-failed-order.php
        class-wc-email-customer-fulfillment-created.php
        class-wc-email-customer-fulfillment-deleted.php
        class-wc-email-customer-fulfillment-updated.php
        class-wc-email-customer-invoice.php
        class-wc-email-customer-new-account.php
        class-wc-email-customer-note.php
        class-wc-email-customer-on-hold-order.php
        class-wc-email-customer-order-withdrawal-requested.php
        class-wc-email-customer-partially-refunded-order.php
        class-wc-email-customer-pos-completed-order.php
        class-wc-email-customer-pos-refunded-order.php
        class-wc-email-customer-processing-order.php
        class-wc-email-customer-refunded-order.php
        class-wc-email-customer-reset-password.php
        class-wc-email-customer-review-request.php
        class-wc-email-failed-order.php
        class-wc-email-new-order.php
        class-wc-email-order-withdrawal-requested.php
        class-wc-email.php
      export/
        abstract-wc-csv-batch-exporter.php
        abstract-wc-csv-exporter.php
        class-wc-product-csv-exporter.php
      gateways/
        bacs/
          class-wc-gateway-bacs.php
        cheque/
          class-wc-gateway-cheque.php
        cod/
          class-wc-gateway-cod.php
        paypal/
          includes/
            class-wc-gateway-paypal-api-handler.php
            class-wc-gateway-paypal-constants.php
            class-wc-gateway-paypal-helper.php
            class-wc-gateway-paypal-ipn-handler.php
            class-wc-gateway-paypal-notices.php
            class-wc-gateway-paypal-pdt-handler.php
            class-wc-gateway-paypal-request.php
            class-wc-gateway-paypal-response.php
            class-wc-gateway-paypal-transact-account-manager.php
            class-wc-gateway-paypal-webhook-handler.php
            settings-paypal.php
          class-wc-gateway-paypal-buttons.php
          class-wc-gateway-paypal.php
        class-wc-payment-gateway-cc.php
        class-wc-payment-gateway-echeck.php
      import/
        abstract-wc-product-importer.php
        class-wc-product-csv-importer.php
      integrations/
        maxmind-geolocation/
          views/
            html-admin-options.php
          class-wc-integration-maxmind-database-service.php
          class-wc-integration-maxmind-geolocation.php
      interfaces/
        class-wc-abstract-order-data-store-interface.php
        class-wc-coupon-data-store-interface.php
        class-wc-customer-data-store-interface.php
        class-wc-customer-download-data-store-interface.php
        class-wc-customer-download-log-data-store-interface.php
        class-wc-importer-interface.php
        class-wc-log-handler-interface.php
        class-wc-logger-interface.php
        class-wc-object-data-store-interface.php
        class-wc-order-data-store-interface.php
        class-wc-order-item-data-store-interface.php
        class-wc-order-item-product-data-store-interface.php
        class-wc-order-item-type-data-store-interface.php
        class-wc-order-refund-data-store-interface.php
        class-wc-payment-token-data-store-interface.php
        class-wc-product-data-store-interface.php
        class-wc-product-variable-data-store-interface.php
        class-wc-queue-interface.php
        class-wc-shipping-zone-data-store-interface.php
        class-wc-webhooks-data-store-interface.php
      legacy/
        abstract-wc-legacy-order.php
        abstract-wc-legacy-payment-token.php
        abstract-wc-legacy-product.php
        class-wc-legacy-cart.php
        class-wc-legacy-coupon.php
        class-wc-legacy-customer.php
        class-wc-legacy-shipping-zone.php
        class-wc-legacy-webhook.php
      libraries/
        class-wc-eval-math.php
        wp-async-request.php
        wp-background-process.php
      log-handlers/
        class-wc-log-handler-db.php
        class-wc-log-handler-email.php
        class-wc-log-handler-file.php
      payment-tokens/
        class-wc-payment-token-cc.php
        class-wc-payment-token-echeck.php
      product-usage/
        class-wc-product-usage-rule-set.php
        class-wc-product-usage.php
      queue/
        class-wc-action-queue.php
        class-wc-queue.php
      react-admin/
        emails/
          html-admin-report-export-download.php
          plain-admin-report-export-download.php
        class-experimental-abtest.php
        connect-existing-pages.php
        core-functions.php
        page-controller-functions.php
        wc-admin-update-functions.php
      rest-api/
        Controllers/
          Telemetry/
            class-wc-rest-telemetry-controller.php
          Version1/
            class-wc-rest-coupons-v1-controller.php
            class-wc-rest-customer-downloads-v1-controller.php
            class-wc-rest-customers-v1-controller.php
            class-wc-rest-order-notes-v1-controller.php
            class-wc-rest-order-refunds-v1-controller.php
            class-wc-rest-orders-v1-controller.php
            class-wc-rest-product-attribute-terms-v1-controller.php
            class-wc-rest-product-attributes-v1-controller.php
            class-wc-rest-product-categories-v1-controller.php
            class-wc-rest-product-reviews-v1-controller.php
            class-wc-rest-product-shipping-classes-v1-controller.php
            class-wc-rest-product-tags-v1-controller.php
            class-wc-rest-products-v1-controller.php
            class-wc-rest-report-sales-v1-controller.php
            class-wc-rest-report-top-sellers-v1-controller.php
            class-wc-rest-reports-v1-controller.php
            class-wc-rest-tax-classes-v1-controller.php
            class-wc-rest-taxes-v1-controller.php
            class-wc-rest-webhook-deliveries-v1-controller.php
            class-wc-rest-webhooks-v1-controller.php
          Version2/
            class-wc-rest-coupons-v2-controller.php
            class-wc-rest-customer-downloads-v2-controller.php
            class-wc-rest-customers-v2-controller.php
            class-wc-rest-network-orders-v2-controller.php
            class-wc-rest-order-notes-v2-controller.php
            class-wc-rest-order-refunds-v2-controller.php
            class-wc-rest-orders-v2-controller.php
            class-wc-rest-payment-gateways-v2-controller.php
            class-wc-rest-product-attribute-terms-v2-controller.php
            class-wc-rest-product-attributes-v2-controller.php
            class-wc-rest-product-brands-v2-controller.php
            class-wc-rest-product-categories-v2-controller.php
            class-wc-rest-product-reviews-v2-controller.php
            class-wc-rest-product-shipping-classes-v2-controller.php
            class-wc-rest-product-tags-v2-controller.php
            class-wc-rest-product-variations-v2-controller.php
            class-wc-rest-products-v2-controller.php
            class-wc-rest-report-sales-v2-controller.php
            class-wc-rest-report-top-sellers-v2-controller.php
            class-wc-rest-reports-v2-controller.php
            class-wc-rest-setting-options-v2-controller.php
            class-wc-rest-settings-v2-controller.php
            class-wc-rest-shipping-methods-v2-controller.php
            class-wc-rest-shipping-zone-locations-v2-controller.php
            class-wc-rest-shipping-zone-methods-v2-controller.php
            class-wc-rest-shipping-zones-v2-controller.php
            class-wc-rest-system-status-tools-v2-controller.php
            class-wc-rest-system-status-v2-controller.php
            class-wc-rest-tax-classes-v2-controller.php
            class-wc-rest-taxes-v2-controller.php
            class-wc-rest-webhook-deliveries-v2-controller.php
            class-wc-rest-webhooks-v2-controller.php
          Version3/
            class-wc-rest-controller.php
            class-wc-rest-coupons-controller.php
            class-wc-rest-crud-controller.php
            class-wc-rest-customer-downloads-controller.php
            class-wc-rest-customers-controller.php
            class-wc-rest-data-continents-controller.php
            class-wc-rest-data-controller.php
            class-wc-rest-data-countries-controller.php
            class-wc-rest-data-currencies-controller.php
            class-wc-rest-layout-templates-controller.php
            class-wc-rest-network-orders-controller.php
            class-wc-rest-order-notes-controller.php
            class-wc-rest-order-refunds-controller.php
            class-wc-rest-orders-controller.php
            class-wc-rest-payment-gateways-controller.php
            class-wc-rest-paypal-buttons-controller.php
            class-wc-rest-paypal-standard-controller.php
            class-wc-rest-paypal-webhooks-controller.php
            class-wc-rest-posts-controller.php
            class-wc-rest-product-attribute-terms-controller.php
            class-wc-rest-product-attributes-controller.php
            class-wc-rest-product-brands-controller.php
            class-wc-rest-product-categories-controller.php
            class-wc-rest-product-custom-fields-controller.php
            class-wc-rest-product-reviews-controller.php
            class-wc-rest-product-shipping-classes-controller.php
            class-wc-rest-product-tags-controller.php
            class-wc-rest-product-variations-controller.php
            class-wc-rest-products-catalog-controller.php
            class-wc-rest-products-controller.php
            class-wc-rest-refunds-controller.php
            class-wc-rest-report-coupons-totals-controller.php
            class-wc-rest-report-customers-totals-controller.php
            class-wc-rest-report-orders-totals-controller.php
            class-wc-rest-report-products-totals-controller.php
            class-wc-rest-report-reviews-totals-controller.php
            class-wc-rest-report-sales-controller.php
            class-wc-rest-report-top-sellers-controller.php
            class-wc-rest-reports-controller.php
            class-wc-rest-setting-options-controller.php
            class-wc-rest-settings-controller.php
            class-wc-rest-shipping-methods-controller.php
            class-wc-rest-shipping-zone-locations-controller.php
            class-wc-rest-shipping-zone-methods-controller.php
            class-wc-rest-shipping-zones-controller-base.php
            class-wc-rest-shipping-zones-controller.php
            class-wc-rest-system-status-controller.php
            class-wc-rest-system-status-tools-controller.php
            class-wc-rest-tax-classes-controller.php
            class-wc-rest-taxes-controller.php
            class-wc-rest-terms-controller.php
            class-wc-rest-variations-controller.php
            class-wc-rest-webhooks-controller.php
          Version4/
            class-wc-rest-settings-v4-controller.php
            class-wc-rest-v4-controller.php
        Utilities/
          ImageAttachment.php
          SingletonTrait.php
        Package.php
        Server.php
      shipping/
        flat-rate/
          includes/
            settings-flat-rate.php
          class-wc-shipping-flat-rate.php
        free-shipping/
          class-wc-shipping-free-shipping.php
        legacy-flat-rate/
          includes/
            settings-flat-rate.php
          class-wc-shipping-legacy-flat-rate.php
        legacy-free-shipping/
          class-wc-shipping-legacy-free-shipping.php
        legacy-international-delivery/
          class-wc-shipping-legacy-international-delivery.php
        legacy-local-delivery/
          class-wc-shipping-legacy-local-delivery.php
        legacy-local-pickup/
          class-wc-shipping-legacy-local-pickup.php
        local-pickup/
          class-wc-shipping-local-pickup.php
      shortcodes/
        class-wc-shortcode-cart.php
        class-wc-shortcode-checkout.php
        class-wc-shortcode-my-account.php
        class-wc-shortcode-order-tracking.php
        class-wc-shortcode-products.php
      theme-support/
        class-wc-twenty-eleven.php
        class-wc-twenty-fifteen.php
        class-wc-twenty-fourteen.php
        class-wc-twenty-nineteen.php
        class-wc-twenty-seventeen.php
        class-wc-twenty-sixteen.php
        class-wc-twenty-ten.php
        class-wc-twenty-thirteen.php
        class-wc-twenty-twelve.php
        class-wc-twenty-twenty-one.php
        class-wc-twenty-twenty-three.php
        class-wc-twenty-twenty-two.php
        class-wc-twenty-twenty.php
      tracks/
        events/
          class-wc-admin-setup-wizard-tracking.php
          class-wc-coupon-tracking.php
          class-wc-coupons-tracking.php
          class-wc-extensions-tracking.php
          class-wc-importer-tracking.php
          class-wc-order-tracking.php
          class-wc-orders-tracking.php
          class-wc-product-collection-block-tracking.php
          class-wc-products-tracking.php
          class-wc-settings-tracking.php
          class-wc-status-tracking.php
          class-wc-theme-tracking.php
        class-wc-site-tracking.php
        class-wc-tracks-client.php
        class-wc-tracks-event.php
        class-wc-tracks-footer-pixel.php
        class-wc-tracks.php
      traits/
        trait-wc-item-totals.php
      walkers/
        class-product-cat-dropdown-walker.php
        class-product-cat-list-walker.php
        class-wc-product-cat-dropdown-walker.php
        class-wc-product-cat-list-walker.php
      wccom-site/
        installation/
          installation-steps/
            class-wc-wccom-site-installation-step-activate-product.php
            class-wc-wccom-site-installation-step-download-product.php
            class-wc-wccom-site-installation-step-get-product-info.php
            class-wc-wccom-site-installation-step-move-product.php
            class-wc-wccom-site-installation-step-unpack-product.php
            interface-installaton-step.php
          class-wc-wccom-site-installation-manager.php
          class-wc-wccom-site-installation-state-storage.php
          class-wc-wccom-site-installation-state.php
        rest-api/
          endpoints/
            abstract-wc-rest-wccom-site-controller.php
            class-wc-rest-wccom-site-connection-controller.php
            class-wc-rest-wccom-site-installer-controller.php
            class-wc-rest-wccom-site-ssr-controller.php
            class-wc-rest-wccom-site-status-controller.php
          class-wc-rest-wccom-site-installer-error-codes.php
          class-wc-rest-wccom-site-installer-error.php
        class-wc-wccom-site-installer.php
        class-wc-wccom-site.php
      widgets/
        class-wc-widget-brand-description.php
        class-wc-widget-brand-nav.php
        class-wc-widget-brand-thumbnails.php
        class-wc-widget-cart.php
        class-wc-widget-layered-nav-filters.php
        class-wc-widget-layered-nav.php
        class-wc-widget-price-filter.php
        class-wc-widget-product-categories.php
        class-wc-widget-product-search.php
        class-wc-widget-product-tag-cloud.php
        class-wc-widget-products.php
        class-wc-widget-rating-filter.php
        class-wc-widget-recent-reviews.php
        class-wc-widget-recently-viewed.php
        class-wc-widget-top-rated-products.php
      class-wc-ajax.php
      class-wc-auth.php
      class-wc-autoloader.php
      class-wc-background-emailer.php
      class-wc-background-updater.php
      class-wc-brands-brand-settings-manager.php
      class-wc-brands-coupons.php
      class-wc-brands.php
      class-wc-breadcrumb.php
      class-wc-cache-helper.php
      class-wc-cart-fees.php
      class-wc-cart-session.php
      class-wc-cart-totals.php
      class-wc-cart.php
      class-wc-checkout.php
      class-wc-cli.php
      class-wc-comments.php
      class-wc-countries.php
      class-wc-coupon.php
      class-wc-customer-download-log.php
      class-wc-customer-download.php
      class-wc-customer.php
      class-wc-data-exception.php
      class-wc-data-store.php
      class-wc-datetime.php
      class-wc-deprecated-action-hooks.php
      class-wc-deprecated-filter-hooks.php
      class-wc-discounts.php
      class-wc-download-handler.php
      class-wc-emails.php
      class-wc-embed.php
      class-wc-form-handler.php
      class-wc-frontend-scripts.php
      class-wc-geo-ip.php
      class-wc-geolite-integration.php
      class-wc-geolocation.php
      class-wc-https.php
      class-wc-install.php
      class-wc-integrations.php
      class-wc-log-levels.php
      class-wc-logger.php
      class-wc-meta-data.php
      class-wc-order-factory.php
      class-wc-order-item-coupon.php
      class-wc-order-item-fee.php
      class-wc-order-item-meta.php
      class-wc-order-item-product.php
      class-wc-order-item-shipping.php
      class-wc-order-item-tax.php
      class-wc-order-item.php
      class-wc-order-query.php
      class-wc-order-refund.php
      class-wc-order.php
      class-wc-payment-gateways.php
      class-wc-payment-tokens.php
      class-wc-post-data.php
      class-wc-post-types.php
      class-wc-privacy-background-process.php
      class-wc-privacy-erasers.php
      class-wc-privacy-exporters.php
      class-wc-privacy.php
      class-wc-product-attribute.php
      class-wc-product-download.php
      class-wc-product-external.php
      class-wc-product-factory.php
      class-wc-product-grouped.php
      class-wc-product-query.php
      class-wc-product-simple.php
      class-wc-product-variable.php
      class-wc-product-variation.php
      class-wc-query.php
      class-wc-rate-limiter.php
      class-wc-regenerate-images-request.php
      class-wc-regenerate-images.php
      class-wc-register-wp-admin-settings.php
      class-wc-rest-authentication.php
      class-wc-rest-exception.php
      class-wc-session-handler.php
      class-wc-shipping-rate.php
      class-wc-shipping-zone.php
      class-wc-shipping-zones.php
      class-wc-shipping.php
      class-wc-shortcodes.php
      class-wc-structured-data.php
      class-wc-tax.php
      class-wc-template-loader.php
      class-wc-tracker.php
      class-wc-validation.php
      class-wc-webhook.php
      class-woocommerce.php
      README.md
      wc-account-functions.php
      wc-attribute-functions.php
      wc-brands-functions.php
      wc-cart-functions.php
      wc-conditional-functions.php
      wc-core-functions.php
      wc-coupon-functions.php
      wc-deprecated-functions.php
      wc-formatting-functions.php
      wc-interactivity-api-functions.php
      wc-notice-functions.php
      wc-order-functions.php
      wc-order-item-functions.php
      wc-order-step-logger-functions.php
      wc-page-functions.php
      wc-product-functions.php
      wc-rest-functions.php
      wc-stock-functions.php
      wc-template-functions.php
      wc-template-hooks.php
      wc-term-functions.php
      wc-update-functions.php
      wc-user-functions.php
      wc-webhook-functions.php
      wc-widget-functions.php
    packages/
      README.md
    patterns/
      coming-soon-entire-site.php
      coming-soon-store-only.php
      coming-soon.php
      footer-large.php
      footer-simple-menu.php
      footer-with-3-menus.php
      header-centered-pattern.php
      header-distraction-free.php
      header-essential.php
      header-large.php
      header-minimal.php
      no-products-found-filters.php
      no-products-found.php
      page-coming-soon-default.php
      page-coming-soon-image-gallery.php
      page-coming-soon-minimal-left-image.php
      page-coming-soon-modern-black.php
      page-coming-soon-split-right-image.php
      page-coming-soon-with-header-footer.php
      product-search-form.php
      README.md
      related-products.php
    php-stubs/
      wc-admin-feature-config.php
      wc-constants.php
    sample-data/
      sample_products.xml
    src/
      Abilities/
        AbilityDefinition.php
      Admin/
        API/
          AI/
            BusinessDescription.php
            Images.php
            Middleware.php
            Patterns.php
            Product.php
            StoreInfo.php
            StoreTitle.php
          RateLimits/
            QRLoginRateLimits.php
          Reports/
            Categories/
              Controller.php
              DataStore.php
              Query.php
            Coupons/
              Stats/
                Controller.php
                DataStore.php
                Query.php
                Segmenter.php
              Controller.php
              DataStore.php
              Query.php
            Customers/
              Stats/
                Controller.php
                DataStore.php
                Query.php
              Controller.php
              DataStore.php
              Query.php
            Downloads/
              Files/
                Controller.php
              Stats/
                Controller.php
                DataStore.php
                Query.php
              Controller.php
              DataStore.php
              Query.php
            Export/
              Controller.php
            Import/
              Controller.php
            Orders/
              Stats/
                Controller.php
                DataStore.php
                Query.php
                Segmenter.php
              Controller.php
              DataStore.php
              Query.php
            PerformanceIndicators/
              Controller.php
            Products/
              Stats/
                Controller.php
                DataStore.php
                Query.php
                Segmenter.php
              Controller.php
              DataStore.php
              Query.php
            Revenue/
              Stats/
                Controller.php
              Query.php
            Stock/
              Stats/
                Controller.php
                DataStore.php
                Query.php
              Controller.php
            Taxes/
              Stats/
                Controller.php
                DataStore.php
                Query.php
                Segmenter.php
              Controller.php
              DataStore.php
              Query.php
            Variations/
              Stats/
                Controller.php
                DataStore.php
                Query.php
                Segmenter.php
              Controller.php
              DataStore.php
              Query.php
            Cache.php
            Controller.php
            DataStore.php
            DataStoreInterface.php
            ExportableInterface.php
            ExportableTraits.php
            FilteredGetDataTrait.php
            GenericController.php
            GenericQuery.php
            GenericStatsController.php
            OrderAwareControllerTrait.php
            ParameterException.php
            Query.php
            Segmenter.php
            SqlQuery.php
            StatsDataStoreTrait.php
            TimeInterval.php
          views/
            mobile-app-qr-login-signin-email.php
          ActivityPanelCounts.php
          AnalyticsImports.php
          Coupons.php
          CustomAttributeTraits.php
          Customers.php
          Data.php
          DataCountries.php
          DataDownloadIPs.php
          Experiments.php
          Features.php
          Init.php
          LaunchYourStore.php
          Leaderboards.php
          Marketing.php
          MarketingCampaigns.php
          MarketingCampaignTypes.php
          MarketingChannels.php
          MarketingOverview.php
          MarketingRecommendations.php
          MobileAppMagicLink.php
          MobileAppQRLogin.php
          NoteActions.php
          Notes.php
          Notice.php
          OnboardingFreeExtensions.php
          OnboardingPlugins.php
          OnboardingProducts.php
          OnboardingProductTypes.php
          OnboardingProfile.php
          OnboardingTasks.php
          OnboardingThemes.php
          Options.php
          Orders.php
          PaymentGatewaySuggestions.php
          Plugins.php
          ProductAttributes.php
          ProductAttributeTerms.php
          ProductCategories.php
          ProductForm.php
          ProductReviews.php
          Products.php
          ProductsLowInStock.php
          ProductVariations.php
          SettingOptions.php
          Settings.php
          ShippingPartnerSuggestions.php
          Taxes.php
          Themes.php
        BlockTemplates/
          BlockContainerInterface.php
          BlockInterface.php
          BlockTemplateInterface.php
          ContainerInterface.php
          README.md
        Composer/
          Package.php
        DateTimeProvider/
          CurrentDateTimeProvider.php
          DateTimeProviderInterface.php
        Features/
          Blueprint/
            Exporters/
              ExportWCCoreProfilerOptions.php
              ExportWCPaymentGateways.php
              ExportWCSettings.php
              ExportWCSettingsAccount.php
              ExportWCSettingsAdvanced.php
              ExportWCSettingsEmails.php
              ExportWCSettingsGeneral.php
              ExportWCSettingsIntegrations.php
              ExportWCSettingsProducts.php
              ExportWCSettingsShipping.php
              ExportWCSettingsSiteVisibility.php
              ExportWCSettingsTax.php
              ExportWCTaskOptions.php
            Init.php
            RestApi.php
            SettingOptions.php
          Fulfillments/
            DataStore/
              FulfillmentsDataStore.php
              FulfillmentsDataStoreInterface.php
            Providers/
              AbstractShippingProvider.php
              ACSCourierShippingProvider.php
              AmazonLogisticsShippingProvider.php
              AnPostShippingProvider.php
              ArasKargoShippingProvider.php
              AustraliaPostShippingProvider.php
              AzerpostShippingProvider.php
              BartoliniBRTShippingProvider.php
              BelpochtaShippingProvider.php
              BpostShippingProvider.php
              BulgarianPostsShippingProvider.php
              CanadaPostShippingProvider.php
              CDEKShippingProvider.php
              CeskaPostaShippingProvider.php
              ChronopostShippingProvider.php
              CorreosShippingProvider.php
              CTTShippingProvider.php
              CustomShippingProvider.php
              CyprusPostShippingProvider.php
              DeutschePostShippingProvider.php
              DHLShippingProvider.php
              DPDShippingProvider.php
              EcontShippingProvider.php
              EimskipShippingProvider.php
              ELTAShippingProvider.php
              EvriHermesShippingProvider.php
              FanCourierShippingProvider.php
              FastwayShippingProvider.php
              FedExShippingProvider.php
              GenikiTaxydromikiShippingProvider.php
              GLSShippingProvider.php
              HayPostShippingProvider.php
              HelthjemShippingProvider.php
              HrvatskaPostaShippingProvider.php
              InPostShippingProvider.php
              IslandsposturShippingProvider.php
              ItellaShippingProvider.php
              KazpostShippingProvider.php
              LaPosteColissimoShippingProvider.php
              LasershipOntracShippingProvider.php
              LatvijasPastsShippingProvider.php
              LiechtensteinischePostShippingProvider.php
              MagyarPostaShippingProvider.php
              MakedonskaPostaShippingProvider.php
              MaltaPostShippingProvider.php
              MatkahuoltoShippingProvider.php
              MondialRelayShippingProvider.php
              MPLShippingProvider.php
              MRWShippingProvider.php
              NewZealandPostShippingProvider.php
              NovaPoshtaShippingProvider.php
              OmnivaShippingProvider.php
              OsterreichischePostShippingProvider.php
              ParcelForceShippingProvider.php
              PocztaPolskaShippingProvider.php
              PostaMoldoveiShippingProvider.php
              PostaRomanaShippingProvider.php
              PosteItalianeShippingProvider.php
              PostenNorgeBringShippingProvider.php
              PosteSanMarinoShippingProvider.php
              PostLuxembourgShippingProvider.php
              PostNLShippingProvider.php
              PostNordShippingProvider.php
              PurolatorShippingProvider.php
              RoyalMailShippingProvider.php
              RussianPostShippingProvider.php
              SDAShippingProvider.php
              SeurShippingProvider.php
              SlovenskaPostaShippingProvider.php
              SpeeDeeDeliveryShippingProvider.php
              StarTrackShippingProvider.php
              SwissPostShippingProvider.php
              TollShippingProvider.php
              UkrposhtaShippingProvider.php
              UPSShippingProvider.php
              UrgentCargusShippingProvider.php
              USPSShippingProvider.php
              YurticiKargoShippingProvider.php
              ZasilkovnaShippingProvider.php
            Fulfillment.php
            FulfillmentException.php
            FulfillmentOrderNotes.php
            FulfillmentsController.php
            FulfillmentsManager.php
            FulfillmentsRenderer.php
            FulfillmentsSettings.php
            FulfillmentsTracker.php
            FulfillmentUtils.php
            OrderFulfillmentsRestController.php
            ShippingProviders.php
          MarketingRecommendations/
            DefaultMarketingRecommendations.php
            Init.php
            MarketingRecommendationsDataSourcePoller.php
            MiscRecommendationsDataSourcePoller.php
          Navigation/
            RemovedDeprecated.php
          OnboardingTasks/
            Tasks/
              AdditionalPayments.php
              Appearance.php
              CustomizeStore.php
              ExperimentalShippingRecommendation.php
              ExtendStore.php
              GetMobileApp.php
              LaunchYourStore.php
              Marketing.php
              Payments.php
              Products.php
              ReviewShippingOptions.php
              Shipping.php
              StoreCreation.php
              StoreDetails.php
              Tax.php
              TourInAppMarketplace.php
              WooCommercePayments.php
            DeprecatedExtendedTask.php
            DeprecatedOptions.php
            Init.php
            Task.php
            TaskList.php
            TaskLists.php
            TaskListSection.php
            TaskTraits.php
          PaymentGatewaySuggestions/
            DefaultPaymentGateways.php
            EvaluateSuggestion.php
            Init.php
            PaymentGatewaysController.php
            PaymentGatewaySuggestionsDataSourcePoller.php
          ProductBlockEditor/
            ProductTemplates/
              GroupInterface.php
              ProductFormTemplateInterface.php
              SectionInterface.php
              SubsectionInterface.php
            BlockRegistry.php
            ProductTemplate.php
            README.md
          ShippingPartnerSuggestions/
            DefaultShippingPartners.php
            ShippingPartnerSuggestions.php
            ShippingPartnerSuggestionsDataSourcePoller.php
          Features.php
          LaunchYourStore.php
          Onboarding.php
          TransientNotices.php
        Marketing/
          InstalledExtensions.php
          MarketingCampaign.php
          MarketingCampaignType.php
          MarketingChannelInterface.php
          MarketingChannels.php
          Price.php
        Notes/
          DataStore.php
          DeprecatedNotes.php
          Note.php
          Notes.php
          NotesUnavailableException.php
          NoteTraits.php
        Overrides/
          Order.php
          OrderRefund.php
          OrderTraits.php
          ThemeUpgrader.php
          ThemeUpgraderSkin.php
        PluginsInstallLoggers/
          AsyncPluginsInstallLogger.php
          PluginsInstallLogger.php
        PluginsProvider/
          PluginsProvider.php
          PluginsProviderInterface.php
        RemoteInboxNotifications/
          README.md
          RemoteInboxNotificationsDataSourcePoller.php
          RemoteInboxNotificationsEngine.php
          RuleProcessorInterface.php
          SpecRunner.php
          TransformerInterface.php
        RemoteSpecs/
          RuleProcessors/
            Transformers/
              ArrayColumn.php
              ArrayFlatten.php
              ArrayKeys.php
              ArraySearch.php
              ArrayValues.php
              Count.php
              DotNotation.php
              PrepareUrl.php
              README.md
              TransformerInterface.php
              TransformerService.php
            BaseLocationCountryRuleProcessor.php
            BaseLocationStateRuleProcessor.php
            ComparisonOperation.php
            ContextPluginsRuleProcessor.php
            EvaluateAndGetStatus.php
            EvaluateOverrides.php
            EvaluationLogger.php
            FailRuleProcessor.php
            GetRuleProcessor.php
            GetRuleProcessorForContext.php
            IsEcommerceRuleProcessor.php
            IsWooExpressRuleProcessor.php
            NoteStatusRuleProcessor.php
            NotRuleProcessor.php
            OnboardingProfileRuleProcessor.php
            OptionRuleProcessor.php
            OrderCountRuleProcessor.php
            OrdersProvider.php
            OrRuleProcessor.php
            PassRuleProcessor.php
            PluginsActivatedRuleProcessor.php
            PluginVersionRuleProcessor.php
            ProductCountRuleProcessor.php
            PublishAfterTimeRuleProcessor.php
            PublishBeforeTimeRuleProcessor.php
            README.md
            RuleEvaluator.php
            RuleProcessorInterface.php
            StoredStateRuleProcessor.php
            StoredStateSetupForProducts.php
            TotalPaymentsVolumeProcessor.php
            WCAdminActiveForProvider.php
            WCAdminActiveForRuleProcessor.php
            WooCommerceAdminUpdatedRuleProcessor.php
          DataSourcePoller.php
          RemoteSpecsEngine.php
        Schedulers/
          SchedulerTraits.php
        Settings/
          AGENTS.md
          LegacySettingsPageAdapter.php
          SettingsSection.php
          SettingsSectionInterface.php
          SettingsSectionRegistry.php
          SettingsSectionUIPageProviderInterface.php
          SettingsUIPageInterface.php
          SettingsUISchema.php
        DataSourcePoller.php
        DeprecatedClassFacade.php
        FeaturePlugin.php
        Loader.php
        PageController.php
        PluginsHelper.php
        PluginsInstaller.php
        ReportCSVEmail.php
        ReportCSVExporter.php
        ReportExporter.php
        ReportsSync.php
        WCAdminHelper.php
      Blocks/
        AI/
          Configuration.php
          Connection.php
        AIContent/
          ContentProcessor.php
          PatternsDictionary.php
          PatternsHelper.php
          UpdatePatterns.php
          UpdateProducts.php
        Assets/
          Api.php
          AssetDataRegistry.php
        BlockTypes/
          Accordion/
            AccordionGroup.php
            AccordionHeader.php
            AccordionItem.php
            AccordionPanel.php
          AddToCartWithOptions/
            AddToCartWithOptions.php
            GroupedProductItem.php
            GroupedProductItemLabel.php
            GroupedProductItemSelector.php
            GroupedProductSelector.php
            QuantitySelector.php
            Utils.php
            VariationDescription.php
            VariationSelector.php
            VariationSelectorAttribute.php
            VariationSelectorAttributeName.php
          OrderConfirmation/
            AbstractOrderConfirmationBlock.php
            AdditionalFields.php
            AdditionalFieldsWrapper.php
            AdditionalInformation.php
            BillingAddress.php
            BillingWrapper.php
            CreateAccount.php
            Downloads.php
            DownloadsWrapper.php
            ShippingAddress.php
            ShippingWrapper.php
            Status.php
            Summary.php
            Totals.php
            TotalsWrapper.php
          ProductCollection/
            Controller.php
            HandlerRegistry.php
            NoResults.php
            QueryBuilder.php
            Renderer.php
            Utils.php
          Reviews/
            ProductReviewAuthorName.php
            ProductReviewContent.php
            ProductReviewDate.php
            ProductReviewForm.php
            ProductReviewRating.php
            ProductReviews.php
            ProductReviewsPagination.php
            ProductReviewsPaginationNext.php
            ProductReviewsPaginationNumbers.php
            ProductReviewsPaginationPrevious.php
            ProductReviewsTitle.php
            ProductReviewTemplate.php
          AbstractBlock.php
          AbstractDynamicBlock.php
          AbstractInnerBlock.php
          AbstractProductGrid.php
          ActiveFilters.php
          AddToCartForm.php
          AddToWishlistButton.php
          AllProducts.php
          AllReviews.php
          AtomicBlock.php
          AttributeFilter.php
          Breadcrumbs.php
          Cart.php
          CartAcceptedPaymentMethodsBlock.php
          CartCrossSellsBlock.php
          CartCrossSellsProductsBlock.php
          CartExpressPaymentBlock.php
          CartItemsBlock.php
          CartLineItemsBlock.php
          CartLink.php
          CartOrderSummaryBlock.php
          CartOrderSummaryCouponFormBlock.php
          CartOrderSummaryDiscountBlock.php
          CartOrderSummaryFeeBlock.php
          CartOrderSummaryHeadingBlock.php
          CartOrderSummaryShippingBlock.php
          CartOrderSummarySubtotalBlock.php
          CartOrderSummaryTaxesBlock.php
          CartOrderSummaryTotalsBlock.php
          CartTotalsBlock.php
          CatalogSorting.php
          CategoryDescription.php
          CategoryTitle.php
          Checkout.php
          CheckoutActionsBlock.php
          CheckoutAdditionalInformationBlock.php
          CheckoutBillingAddressBlock.php
          CheckoutContactInformationBlock.php
          CheckoutExpressPaymentBlock.php
          CheckoutFieldsBlock.php
          CheckoutOrderNoteBlock.php
          CheckoutOrderSummaryBlock.php
          CheckoutOrderSummaryCartItemsBlock.php
          CheckoutOrderSummaryCouponFormBlock.php
          CheckoutOrderSummaryDiscountBlock.php
          CheckoutOrderSummaryFeeBlock.php
          CheckoutOrderSummaryShippingBlock.php
          CheckoutOrderSummarySubtotalBlock.php
          CheckoutOrderSummaryTaxesBlock.php
          CheckoutOrderSummaryTotalsBlock.php
          CheckoutPaymentBlock.php
          CheckoutPickupOptionsBlock.php
          CheckoutShippingAddressBlock.php
          CheckoutShippingMethodBlock.php
          CheckoutShippingMethodsBlock.php
          CheckoutTermsBlock.php
          CheckoutTotalsBlock.php
          ClassicShortcode.php
          ClassicTemplate.php
          ComingSoon.php
          CouponCode.php
          CustomerAccount.php
          Dropdown.php
          EmailContent.php
          EmptyCartBlock.php
          EmptyMiniCartContentsBlock.php
          EnableBlockJsonAssetsTrait.php
          FeaturedCategory.php
          FeaturedItem.php
          FeaturedProduct.php
          FilledCartBlock.php
          FilledMiniCartContentsBlock.php
          FilterWrapper.php
          HandpickedProducts.php
          MiniCart.php
          MiniCartCartButtonBlock.php
          MiniCartCheckoutButtonBlock.php
          MiniCartContents.php
          MiniCartFooterBlock.php
          MiniCartItemsBlock.php
          MiniCartProductsTableBlock.php
          MiniCartShoppingButtonBlock.php
          MiniCartTitleBlock.php
          MiniCartTitleItemsCounterBlock.php
          MiniCartTitleLabelBlock.php
          NextPreviousButtons.php
          PageContentWrapper.php
          PaymentMethodIcons.php
          PriceFilter.php
          ProceedToCheckoutBlock.php
          ProductAverageRating.php
          ProductBestSellers.php
          ProductButton.php
          ProductCategories.php
          ProductCategory.php
          ProductDescription.php
          ProductDetails.php
          ProductFilterActive.php
          ProductFilterAttribute.php
          ProductFilterCheckboxList.php
          ProductFilterChips.php
          ProductFilterClearButton.php
          ProductFilterPrice.php
          ProductFilterPriceSlider.php
          ProductFilterRating.php
          ProductFilterRemovableChips.php
          ProductFilters.php
          ProductFilterStatus.php
          ProductFilterTaxonomy.php
          ProductGallery.php
          ProductGalleryLargeImage.php
          ProductGalleryThumbnails.php
          ProductImage.php
          ProductImageGallery.php
          ProductMeta.php
          ProductNew.php
          ProductOnSale.php
          ProductPrice.php
          ProductQuery.php
          ProductRating.php
          ProductRatingCounter.php
          ProductRatingStars.php
          ProductResultsCount.php
          ProductSaleBadge.php
          ProductsByAttribute.php
          ProductSearch.php
          ProductSKU.php
          ProductSpecifications.php
          ProductStockIndicator.php
          ProductSummary.php
          ProductTag.php
          ProductTemplate.php
          ProductTitle.php
          ProductTopRated.php
          RatingFilter.php
          RelatedProducts.php
          ReviewsByCategory.php
          ReviewsByProduct.php
          SavedForLater.php
          SingleProduct.php
          StockFilter.php
          StoreNotices.php
          Wishlist.php
        Domain/
          Services/
            CheckoutFieldsSchema/
              checkout-document-schema.json
              DocumentObject.php
              json-schema-draft-07.json
              Validation.php
            CheckoutFieldTypes/
              AbstractFieldType.php
              CheckboxFieldType.php
              DateFieldType.php
              SelectFieldType.php
              TextFieldType.php
            Email/
              CustomerNewAccount.php
            CheckoutFields.php
            CheckoutFieldsAdmin.php
            CheckoutFieldsFrontend.php
            CheckoutFieldsStorage.php
            CheckoutLink.php
            CoreCheckoutFields.php
            CreateAccount.php
            DraftOrders.php
            FeatureGating.php
            functions.php
            GoogleAnalytics.php
            Hydration.php
            Notices.php
          BlockRegistrationContext.php
          Bootstrap.php
          Package.php
        Images/
          Pexels.php
        Integrations/
          IntegrationInterface.php
          IntegrationRegistry.php
        Patterns/
          AIPatterns.php
          PatternRegistry.php
          PTKClient.php
          PTKPatternsStore.php
        Payments/
          Integrations/
            AbstractPaymentMethodType.php
            BankTransfer.php
            CashOnDelivery.php
            Cheque.php
            PayPal.php
          Api.php
          PaymentMethodRegistry.php
          PaymentMethodTypeInterface.php
        Registry/
          AbstractDependencyType.php
          Container.php
          FactoryType.php
          SharedType.php
        SharedStores/
          ProductsStore.php
        Shipping/
          PickupLocation.php
          PickupLocationsRestController.php
          ShippingController.php
        Templates/
          AbstractPageTemplate.php
          AbstractTemplate.php
          AbstractTemplateCompatibility.php
          AbstractTemplatePart.php
          AbstractTemplateWithFallback.php
          ArchiveProductTemplatesCompatibility.php
          CartTemplate.php
          CheckoutHeaderTemplate.php
          CheckoutTemplate.php
          ClassicTemplatesCompatibility.php
          ComingSoonSocialLinksTemplate.php
          ComingSoonTemplate.php
          ExternalProductAddToCartWithOptionsTemplate.php
          GroupedProductAddToCartWithOptionsTemplate.php
          MiniCartTemplate.php
          OrderConfirmationTemplate.php
          ProductAttributeTemplate.php
          ProductBrandTemplate.php
          ProductCatalogTemplate.php
          ProductCategoryTemplate.php
          ProductSearchResultsTemplate.php
          ProductTagTemplate.php
          SimpleProductAddToCartWithOptionsTemplate.php
          SingleProductTemplate.php
          SingleProductTemplateCompatibility.php
          VariableProductAddToCartWithOptionsTemplate.php
        Utils/
          BlockHooksTrait.php
          BlocksSharedState.php
          BlocksWpQuery.php
          BlockTemplateUtils.php
          CartCheckoutUtils.php
          MiniCartUtils.php
          ProductAvailabilityUtils.php
          ProductDataUtils.php
          ProductDescriptionUtils.php
          ProductGalleryUtils.php
          StyleAttributesUtils.php
          Utils.php
        Assets.php
        AssetsController.php
        BlockPatterns.php
        BlockTemplatesController.php
        BlockTemplatesRegistry.php
        BlockTypesController.php
        CLAUDE.md
        CoreBreadcrumbsCompatibility.php
        DependencyDetection.php
        InboxNotifications.php
        Installer.php
        Library.php
        Options.php
        Package.php
        QueryFilters.php
        TemplateOptions.php
      Caches/
        OrderCache.php
        OrderCacheController.php
        OrderCountCache.php
        OrderCountCacheService.php
        ProductCountCache.php
        ProductCountCacheService.php
      Caching/
        CacheEngine.php
        CacheException.php
        CacheNameSpaceTrait.php
        ObjectCache.php
        WPCacheEngine.php
      Checkout/
        Helpers/
          ReserveStock.php
          ReserveStockException.php
      Enums/
        CatalogSortOrder.php
        CatalogVisibility.php
        CurrencyPosition.php
        DefaultCustomerAddress.php
        DimensionUnit.php
        FeaturePluginCompatibility.php
        OrderInternalStatus.php
        OrderItemType.php
        OrderStatus.php
        PaymentGatewayFeature.php
        ProductStatus.php
        ProductStockStatus.php
        ProductTaxStatus.php
        ProductType.php
        README.md
        StockDisplayFormat.php
        TaxBasedOn.php
        TaxDisplayMode.php
        WeightUnit.php
      Gateways/
        PayPal/
          AddressRequirements.php
          Buttons.php
          Constants.php
          Helper.php
          Notices.php
          Request.php
          TransactAccountManager.php
          WebhookHandler.php
      Internal/
        Abilities/
          Domain/
            Traits/
              OrderAbilityTrait.php
              ProductAbilityTrait.php
            AbstractDomainAbility.php
            OrderAddNote.php
            OrdersQuery.php
            OrderUpdateStatus.php
            ProductCreate.php
            ProductDelete.php
            ProductsQuery.php
            ProductUpdate.php
          REST/
            RestAbility.php
            RestAbilityFactory.php
          AbilitiesCategories.php
          AbilitiesLoader.php
          AbilitiesRegistry.php
          AbilitiesRestBridge.php
        AbilitiesApi/
          AbilitiesClient.php
        AddressProvider/
          AbstractAutomatticAddressProvider.php
          AddressProviderController.php
        Admin/
          EmailImprovements/
            EmailImprovements.php
          EmailPreview/
            EmailPreview.php
            EmailPreviewRestController.php
            PreviewOrder.php
          Emails/
            EmailListingRestController.php
          ImportExport/
            CSVUploadHelper.php
          Logging/
            FileV2/
              File.php
              FileController.php
              FileExporter.php
              FileListTable.php
              SearchListTable.php
            LogHandlerFileV2.php
            PageController.php
            Settings.php
          Marketing/
            MarketingSpecs.php
          Notes/
            CustomizeStoreWithBlocks.php
            CustomizingProductCatalog.php
            EditProductsOnTheMove.php
            EmailImprovements.php
            EUVATNumber.php
            FirstProduct.php
            FullRefundFixDataToolNotice.php
            GivingFeedbackNotes.php
            InstallJPAndWCSPlugins.php
            LaunchChecklist.php
            MagentoMigration.php
            ManageOrdersOnTheGo.php
            MarketingJetpack.php
            MigrateFromShopify.php
            MobileApp.php
            NewSalesRecord.php
            NoteActionForbiddenException.php
            OnboardingPayments.php
            OnlineClothingStore.php
            OrderMilestones.php
            PaymentsMoreInfoNeeded.php
            PaymentsRemindMeLater.php
            PerformanceOnMobile.php
            PersonalizeStore.php
            RealTimeOrderAlerts.php
            ScheduledUpdatesPromotion.php
            SellingOnlineCourses.php
            TrackingOptIn.php
            UnsecuredReportFiles.php
            WooCommercePayments.php
            WooCommerceSubscriptions.php
            WooSubscriptionsNotes.php
          Onboarding/
            Onboarding.php
            OnboardingHelper.php
            OnboardingIndustries.php
            OnboardingJetpack.php
            OnboardingMailchimp.php
            OnboardingProducts.php
            OnboardingProfile.php
            OnboardingSetupWizard.php
            OnboardingSync.php
          Orders/
            MetaBoxes/
              CustomerHistory.php
              CustomMetaBox.php
              OrderAttribution.php
              TaxonomiesMetaBox.php
            COTRedirectionController.php
            Edit.php
            EditLock.php
            ItemQuantityLimits.php
            ListTable.php
            PageController.php
            PostsRedirectionController.php
          ProductForm/
            Component.php
            ComponentTrait.php
            Field.php
            FormFactory.php
            README.md
            Section.php
            Subsection.php
            Tab.php
          ProductReviews/
            Reviews.php
            ReviewsCommentsOverrides.php
            ReviewsListTable.php
            ReviewsUtil.php
          RemoteFreeExtensions/
            DefaultFreeExtensions.php
            EvaluateExtension.php
            Init.php
            ProcessCoreProfilerPluginInstallOptions.php
            RemoteFreeExtensionsDataSourcePoller.php
          Reports/
            HposLegacyOrderReportQueryBuilder.php
            ProductSearchQuery.php
          Schedulers/
            CustomersScheduler.php
            ImportInterface.php
            ImportScheduler.php
            MailchimpScheduler.php
            OrdersScheduler.php
          Settings/
            Exceptions/
              ApiArgumentException.php
              ApiException.php
            PaymentsProviders/
              WooPayments/
                WooPaymentsController.php
                WooPaymentsRestController.php
                WooPaymentsService.php
              Affirm.php
              AfterpayClearpay.php
              Airwallex.php
              AmazonPay.php
              Antom.php
              Eway.php
              GoCardless.php
              Helcim.php
              HelioPay.php
              Klarna.php
              Komoju.php
              KustomCheckout.php
              Mastercard.php
              MercadoPago.php
              Mollie.php
              Monei.php
              NexiCheckout.php
              Payfast.php
              PaymentGateway.php
              Paymob.php
              Payoneer.php
              PayPal.php
              Paystack.php
              Paytrail.php
              PayUIndia.php
              PseudoWCPaymentGateway.php
              Razorpay.php
              Stripe.php
              Tilopay.php
              Visa.php
              Vivacom.php
              WCCore.php
              WooPayments.php
            SettingsUIPages/
              ProductsSettingsPageAdapter.php
            CLAUDE.md
            LegacySettingsPageAdapter.php
            Payments.php
            PaymentsController.php
            PaymentsProviders.php
            PaymentsRestController.php
            RegisteredSettingsSectionAdapter.php
            SettingsUIPageInterface.php
            SettingsUIRequestContext.php
            SettingsUISchema.php
            Utils.php
          Suggestions/
            Incentives/
              Incentive.php
              WooPayments.php
            PaymentsExtensionSuggestionIncentives.php
            PaymentsExtensionSuggestions.php
          WCPayPromotion/
            DefaultPromotions.php
            Init.php
            WCPaymentGatewayPreInstallWCPayPromotion.php
            WCPayPromotionDataSourcePoller.php
          ActivityPanels.php
          Analytics.php
          CategoryLookup.php
          Coupons.php
          CouponsMovedTrait.php
          CustomerEffortScoreTracks.php
          Events.php
          FeaturePlugin.php
          Homescreen.php
          Loader.php
          Marketing.php
          Marketplace.php
          MobileAppBanner.php
          OrderMilestoneEasterEgg.php
          OrderTaxLookupMigrator.php
          RemoteInboxNotifications.php
          Settings.php
          ShippingLabelBanner.php
          ShippingLabelBannerDisplayRules.php
          SiteHealth.php
          Survey.php
          SystemStatusReport.php
          TaxSettingsRecommendations.php
          Translations.php
          WCAdminAssets.php
          WCAdminSharedSettings.php
          WCAdminUser.php
          WcPayWelcomePage.php
        Api/
          Autogenerated/
            GraphQLController.php
        BatchProcessing/
          BatchProcessingController.php
          BatchProcessorInterface.php
        Caches/
          OrdersVersionStringInvalidator.php
          ProductCache.php
          ProductCacheController.php
          ProductTermCacheInvalidator.php
          ProductTransientsDeferrer.php
          ProductVersionStringInvalidator.php
          TaxRateVersionStringInvalidator.php
          VersionStringGenerator.php
        CLI/
          Migrator/
            Commands/
              ListCommand.php
              ProductsCommand.php
              ResetCommand.php
              SetupCommand.php
            Core/
              CredentialManager.php
              MigratorTracker.php
              PlatformRegistry.php
              ProductsController.php
              WooCommerceProductImporter.php
            Interfaces/
              PlatformFetcherInterface.php
              PlatformMapperInterface.php
            Lib/
              ImportSession.php
            Platforms/
              Shopify/
                README.md
                ShopifyClient.php
                ShopifyFetcher.php
                ShopifyMapper.php
                ShopifyPlatform.php
              Webflow/
                WebflowClient.php
                WebflowFetcher.php
                WebflowMapper.php
                WebflowPlatform.php
            README.md
            Runner.php
        ComingSoon/
          ComingSoonAdminBarBadge.php
          ComingSoonCacheInvalidator.php
          ComingSoonHelper.php
          ComingSoonRequestHandler.php
        CostOfGoodsSold/
          CogsAwareRestControllerTrait.php
          CogsAwareTrait.php
          CogsAwareUnitTestSuiteTrait.php
          CostOfGoodsSoldController.php
        CustomerEmailVerification/
          Admin/
            UserProfileField.php
          Emails/
            CustomerVerifyEmail.php
          CustomerEmailVerification.php
          EmailVerificationService.php
          VerificationController.php
          VerificationEventListener.php
        Customers/
          SearchService.php
        DataStores/
          Orders/
            CustomOrdersTableController.php
            DataSynchronizer.php
            HposOrderCapabilityHelper.php
            LegacyDataCleanup.php
            LegacyDataHandler.php
            OrdersTableDataStore.php
            OrdersTableDataStoreMeta.php
            OrdersTableFieldQuery.php
            OrdersTableMetaQuery.php
            OrdersTableQuery.php
            OrdersTableRefundDataStore.php
            OrdersTableSearchQuery.php
            OrdersTableStatusUnionQuery.php
          StockNotifications/
            StockNotificationsDataStore.php
            StockNotificationsMetaDataStore.php
          CustomMetaDataStore.php
        DependencyManagement/
          ContainerException.php
          RuntimeContainer.php
        Email/
          DeferredEmailQueue.php
          EmailColors.php
          EmailFont.php
          EmailLogger.php
          EmailStyleSync.php
          OrderPriceFormatter.php
        EmailEditor/
          EmailPatterns/
            PatternsController.php
            WooEmailContentPattern.php
          EmailTemplates/
            TemplateApiController.php
            TemplatesController.php
            WooEmailTemplate.php
          PersonalizationTags/
            AbstractTagProvider.php
            CustomerTagsProvider.php
            OrderTagsProvider.php
            SiteTagsProvider.php
            StoreTagsProvider.php
          WCTransactionalEmails/
            WCEmailPostsCleanup.php
            WCEmailScratchpadRefresher.php
            WCEmailTemplateAutoApplier.php
            WCEmailTemplateChangeSummary.php
            WCEmailTemplateDivergenceDetector.php
            WCEmailTemplateSelectiveApplier.php
            WCEmailTemplateSyncBackfill.php
            WCEmailTemplateSyncRegistry.php
            WCEmailTemplateSyncTracker.php
            WCTransactionalEmailPostsGenerator.php
            WCTransactionalEmailPostsManager.php
            WCTransactionalEmails.php
          BlockEmailRenderer.php
          EmailApiController.php
          Integration.php
          Logger.php
          Package.php
          PageRenderer.php
          PersonalizationTagManager.php
          TransactionalEmailPersonalizer.php
          WooContentProcessor.php
        Features/
          OrderDetailRedesign/
            Init.php
          BlockEditorUnifiedAssets.php
          FeaturesController.php
        Integrations/
          WPConsentAPI.php
          WPPostsImporter.php
        Jetpack/
          JetpackConnection.php
        LegacyAssets/
          LegacySelect2UsageTracker.php
        Logging/
          OrderLogsCleanupHelper.php
          OrderLogsDeletionProcessor.php
          RemoteLogger.php
          SafeGlobalFunctionProxy.php
        MCP/
          Transport/
            WooCommerceRestTransport.php
          MCPAdapterProvider.php
        OrderReviews/
          Endpoint.php
          ItemEligibility.php
          Meta.php
          Scheduler.php
          StarRating.php
          SubmissionHandler.php
        Orders/
          CouponsController.php
          IppFunctions.php
          MobileMessagingHandler.php
          OrderActionsRestController.php
          OrderAttributionBlocksController.php
          OrderAttributionController.php
          OrderNoteGroup.php
          OrderStatusRestController.php
          PaymentInfo.php
          PointOfSaleEmailHandler.php
          PointOfSaleOrderUtil.php
          TaxesController.php
        OrderWithdrawal/
          Emails/
            OrderWithdrawalEmailDataFormatter.php
            OrderWithdrawalEmailPreview.php
          OrderWithdrawalController.php
          OrderWithdrawalFeatureHighlightNotification.php
          OrderWithdrawalFormProcessor.php
          OrderWithdrawalFormState.php
          OrderWithdrawalFormView.php
        POS/
          Capabilities.php
          POSController.php
          POSPreset.php
        ProductAttributes/
          AttributeSlugLength.php
          VisualAttributeTermAdmin.php
          VisualAttributeTermMeta.php
        ProductAttributesLookup/
          CLIRunner.php
          DataRegenerator.php
          Filterer.php
          LookupDataStore.php
          TaxQuery.php
        ProductDownloads/
          ApprovedDirectories/
            Admin/
              SyncUI.php
              Table.php
              UI.php
            ApprovedDirectoriesException.php
            Register.php
            StoredUrl.php
            Synchronize.php
        ProductFeed/
          Feed/
            FeedInterface.php
            FeedLockException.php
            FeedValidatorInterface.php
            ProductLoader.php
            ProductMapperInterface.php
            ProductWalker.php
            ResumableFeedInterface.php
            WalkerProgress.php
          Integrations/
            POSCatalog/
              ApiController.php
              AsyncGenerator.php
              FeedValidator.php
              POSIntegration.php
              POSProductVisibilitySync.php
              ProductMapper.php
            IntegrationInterface.php
            IntegrationRegistry.php
          Mapping/
            ProductShapeMapperInterface.php
          Storage/
            JsonFileFeed.php
          Utils/
            MemoryManager.php
            StringHelper.php
          ProductFeed.php
          README.md
        ProductFilters/
          Interfaces/
            FilterUrlParam.php
            MainQueryClausesGenerator.php
            QueryClausesGenerator.php
          CacheController.php
          FilterData.php
          FilterDataProvider.php
          MainQueryController.php
          Params.php
          QueryClauses.php
          README.md
          TaxonomyHierarchyData.php
        ProductGallery/
          ProductMediaGallery.php
        ProductImage/
          MatchImageBySKU.php
        Products/
          ProductsOrderingMoveService.php
          ProductsOrderingReindexService.php
        ProductVariations/
          SelectedVariationName.php
        PushNotifications/
          Controllers/
            NotificationPreferencesRestController.php
            PushNotificationRestController.php
            PushNotificationStatusRestController.php
            PushTokenRestController.php
          DataStores/
            NotificationPreferencesDataStore.php
            PushTokensDataStore.php
          Dispatchers/
            InternalNotificationDispatcher.php
            WpcomNotificationDispatcher.php
          Entities/
            PushToken.php
          Exceptions/
            PushTokenInvalidDataException.php
            PushTokenNotFoundException.php
          Notifications/
            NewOrderNotification.php
            NewReviewNotification.php
            Notification.php
            StockNotification.php
          Services/
            DriverAvailabilityService.php
            NotificationPreferencesService.php
            NotificationProcessor.php
            NotificationRetryHandler.php
            PendingNotificationStore.php
          Traits/
            AuthorizesPushNotificationRequests.php
            ConvertsExceptionsToWpError.php
          Triggers/
            NewOrderNotificationTrigger.php
            NewReviewNotificationTrigger.php
            StockNotificationRecoveryHandler.php
            StockNotificationTrigger.php
          Validators/
            PushTokenValidator.php
          PushNotifications.php
          ROADMAP.md
        ReceiptRendering/
          Templates/
            order-receipt-css.php
            order-receipt.php
          ReceiptRenderingEngine.php
          ReceiptRenderingRestController.php
        RestApi/
          Routes/
            V4/
              Customers/
                CollectionQuery.php
                Controller.php
                CustomerSchema.php
                UpdateUtils.php
              Fulfillments/
                Schema/
                  FulfillmentSchema.php
                Controller.php
              OrderNotes/
                Schema/
                  OrderNoteSchema.php
                CollectionQuery.php
                Controller.php
              Orders/
                Schema/
                  AbstractLineItemSchema.php
                  OrderCouponSchema.php
                  OrderFeeSchema.php
                  OrderItemSchema.php
                  OrderSchema.php
                  OrderShippingSchema.php
                  OrderTaxSchema.php
                ActionController.php
                CollectionQuery.php
                Controller.php
                OrderLineMetaValidator.php
                UpdateUtils.php
              Products/
                Controller.php
                README.md
              Refunds/
                Schema/
                  RefundPreviewSchema.php
                  RefundSchema.php
                CollectionQuery.php
                Controller.php
                DataUtils.php
              Settings/
                Account/
                  Schema/
                    AccountSettingsSchema.php
                  Controller.php
                Email/
                  Schema/
                    EmailSettingsSchema.php
                  Controller.php
                Emails/
                  Schema/
                    EmailsSettingsSchema.php
                  Controller.php
                General/
                  Schema/
                    GeneralSettingsSchema.php
                  Controller.php
                OfflinePaymentMethods/
                  Schema/
                    OfflinePaymentMethodSchema.php
                  Controller.php
                PaymentGateways/
                  Schema/
                    AbstractPaymentGatewaySettingsSchema.php
                    BacsGatewaySettingsSchema.php
                    ChequeGatewaySettingsSchema.php
                    CodGatewaySettingsSchema.php
                    PaymentGatewaySettingsSchema.php
                  Controller.php
                  README.md
                Products/
                  Schema/
                    ProductSettingsSchema.php
                  Controller.php
                Tax/
                  Schema/
                    TaxSettingsSchema.php
                  Controller.php
                README.md
              ShippingZoneMethod/
                Controller.php
                ShippingMethodSchema.php
                ShippingZoneMethodService.php
              ShippingZones/
                Controller.php
                ShippingZoneSchema.php
                ShippingZoneService.php
              AbstractCollectionQuery.php
              AbstractController.php
              AbstractSchema.php
            README.md
          ProductRequestPreparationTrait.php
          README.md
        Settings/
          OptionSanitizer.php
          PointOfSaleDefaultSettings.php
        ShopperLists/
          Privacy/
            Privacy.php
          ShopperList.php
          ShopperListItem.php
          ShopperListRenderer.php
          ShopperListsController.php
        StockNotifications/
          Admin/
            Templates/
              html-admin-notification-create.php
              html-admin-notification-edit.php
              html-admin-notifications.php
              html-product-data-admin.php
            AdminManager.php
            ListTable.php
            MenusController.php
            NotificationCreatePage.php
            NotificationEditPage.php
            NotificationsPage.php
            SettingsController.php
          AsyncTasks/
            CycleStateService.php
            JobManager.php
            NotificationsProcessor.php
          Emails/
            CustomerStockNotificationEmail.php
            CustomerStockNotificationVerifiedEmail.php
            CustomerStockNotificationVerifyEmail.php
            EmailActionController.php
            EmailManager.php
            EmailTemplatesController.php
          Enums/
            NotificationCancellationSource.php
            NotificationStatus.php
          Frontend/
            FormHandlerService.php
            MyAccountEndpoint.php
            MyAccountView.php
            NotificationManagementService.php
            ProductPageIntegration.php
            SignupRateLimiter.php
            SignupResult.php
            SignupService.php
          Privacy/
            PrivacyEraser.php
          Utilities/
            EligibilityService.php
            EmailNormalizer.php
            StockManagementHelper.php
            UtmHelper.php
          Config.php
          DataRetentionController.php
          Factory.php
          Notification.php
          NotificationQuery.php
          StockNotifications.php
          StockSyncController.php
        Tax/
          TaxRateDataStore.php
        Traits/
          AccessiblePrivateMethods.php
          OrderAttributionMeta.php
          RestApiCache.php
          ScriptDebug.php
        TransientFiles/
          README.md
          TransientFilesEngine.php
        Utilities/
          ArrayUtil.php
          BlocksUtil.php
          COTMigrationUtil.php
          DatabaseUtil.php
          FilesystemUtil.php
          HtmlSanitizer.php
          LegacyRestApiStub.php
          OrderItemMetaUtil.php
          PluginInstaller.php
          PostcodeValidation.php
          PriceSeparators.php
          ProductUtil.php
          Types.php
          URL.php
          URLException.php
          Users.php
          WebhookUtil.php
        VariationGallery/
          ClassicVariationGalleryAdmin.php
          LegacyVariationGalleryCompatibility.php
          Migration.php
          Package.php
          Telemetry.php
        WCCom/
          ConnectionHelper.php
        AssignDefaultCategory.php
        Brands.php
        DownloadPermissionsAdjuster.php
        McStats.php
        OrderCouponDataMigrator.php
        README.md
        RegisterHooksInterface.php
        RestApiControllerBase.php
        RestApiParameterUtil.php
        RestockRefundedItemsAdjuster.php
        ScheduledSalePriceReconciler.php
        TermCount.php
      LayoutTemplates/
        LayoutTemplateRegistry.php
      Proxies/
        ActionsProxy.php
        LegacyProxy.php
      StoreApi/
        docs/
          rate-limiting.md
        Exceptions/
          InvalidCartException.php
          InvalidStockLevelsInCartException.php
          NotPurchasableException.php
          OutOfStockException.php
          PartialOutOfStockException.php
          RouteException.php
          StockAvailabilityException.php
          TooManyInCartException.php
        Formatters/
          CurrencyFormatter.php
          DefaultFormatter.php
          FormatterInterface.php
          HtmlFormatter.php
          MoneyFormatter.php
        Payments/
          PaymentContext.php
          PaymentResult.php
        Routes/
          V1/
            AI/
              Middleware.php
              Products.php
            AbstractCartRoute.php
            AbstractRoute.php
            AbstractTermsRoute.php
            Batch.php
            Cart.php
            CartAddItem.php
            CartApplyCoupon.php
            CartCoupons.php
            CartCouponsByCode.php
            CartExtensions.php
            CartItems.php
            CartItemsByKey.php
            CartRemoveCoupon.php
            CartRemoveItem.php
            CartSelectShippingRate.php
            CartUpdateCustomer.php
            CartUpdateItem.php
            Checkout.php
            CheckoutOrder.php
            Order.php
            Patterns.php
            ProductAttributes.php
            ProductAttributesById.php
            ProductAttributeTerms.php
            ProductBrands.php
            ProductBrandsById.php
            ProductCategories.php
            ProductCategoriesById.php
            ProductCollectionData.php
            ProductReviews.php
            Products.php
            ProductsById.php
            ProductsBySlug.php
            ProductTags.php
            ShopperListItems.php
            ShopperListItemsByKey.php
            ShopperLists.php
            ShopperListsBySlug.php
            ShopperListsNonceCheck.php
          RouteInterface.php
        Schemas/
          V1/
            AI/
              ProductsSchema.php
            AbstractAddressSchema.php
            AbstractSchema.php
            BatchSchema.php
            BillingAddressSchema.php
            CartCouponSchema.php
            CartExtensionsSchema.php
            CartFeeSchema.php
            CartItemSchema.php
            CartSchema.php
            CartShippingRateSchema.php
            CheckoutOrderSchema.php
            CheckoutSchema.php
            ErrorSchema.php
            ImageAttachmentSchema.php
            ItemSchema.php
            OrderCouponSchema.php
            OrderFeeSchema.php
            OrderItemSchema.php
            OrderSchema.php
            PatternsSchema.php
            ProductAttributeSchema.php
            ProductAttributeTermSchema.php
            ProductBrandSchema.php
            ProductCategorySchema.php
            ProductCollectionDataSchema.php
            ProductReviewSchema.php
            ProductSchema.php
            ShippingAddressSchema.php
            ShopperListItemSchema.php
            ShopperListSchema.php
            TermSchema.php
          ExtendSchema.php
        Utilities/
          ArrayUtils.php
          CartController.php
          CartTokenUtils.php
          CheckoutTrait.php
          DraftOrderTrait.php
          JsonWebToken.php
          LocalPickupUtils.php
          NoticeHandler.php
          OrderAuthorizationTrait.php
          OrderController.php
          Pagination.php
          PaymentUtils.php
          ProductItemTrait.php
          ProductLinksTrait.php
          ProductQuery.php
          ProductQueryFilters.php
          QuantityLimits.php
          RateLimits.php
          SanitizationUtils.php
          ValidationUtils.php
        Authentication.php
        deprecated.php
        Formatters.php
        functions.php
        Legacy.php
        README.md
        RoutesController.php
        SchemaController.php
        SessionHandler.php
        StoreApi.php
      Utilities/
        ArrayUtil.php
        CallbackUtil.php
        DiscountsUtil.php
        FeaturesUtil.php
        I18nUtil.php
        LoggingUtil.php
        MetaDataUtil.php
        NumberUtil.php
        OrderUtil.php
        PluginUtil.php
        RestApiUtil.php
        ShippingUtil.php
        StringUtil.php
        TimeUtil.php
      Autoloader.php
      Container.php
      Deprecated.php
      Packages.php
      README.md
    templates/
      auth/
        footer.php
        form-grant-access.php
        form-login.php
        header.php
      block-notices/
        error.php
        notice.php
        success.php
      brands/
        shortcodes/
          brands-a-z.php
          single-brand.php
        widgets/
          brand-description.php
          brand-thumbnails-description.php
          brand-thumbnails.php
        brand-description.php
        taxonomy-product_brand.php
      cart/
        cart-empty.php
        cart-item-data.php
        cart-shipping.php
        cart-totals.php
        cart.php
        cross-sells.php
        mini-cart.php
        proceed-to-checkout-button.php
        shipping-calculator.php
      checkout/
        cart-errors.php
        form-billing.php
        form-checkout.php
        form-coupon.php
        form-login.php
        form-pay.php
        form-shipping.php
        form-verify-email.php
        order-receipt.php
        order-received.php
        payment-method.php
        payment.php
        review-order.php
        terms.php
        thankyou.php
      emails/
        block/
          admin-cancelled-order.php
          admin-failed-order.php
          admin-new-order.php
          admin-payment-gateway-enabled.php
          customer-cancelled-order.php
          customer-completed-order.php
          customer-failed-order.php
          customer-fulfillment-created.php
          customer-fulfillment-deleted.php
          customer-fulfillment-updated.php
          customer-invoice.php
          customer-new-account.php
          customer-note.php
          customer-on-hold-order.php
          customer-partially-refunded-order.php
          customer-pos-completed-order.php
          customer-pos-refunded-order.php
          customer-processing-order.php
          customer-refunded-order.php
          customer-reset-password.php
          customer-review-request.php
          customer-verify-email.php
          default-block-content.php
          general-block-content-for-fulfillment-emails.php
          general-block-email.php
        plain/
          admin-cancelled-order.php
          admin-failed-order.php
          admin-new-order.php
          admin-order-withdrawal-requested.php
          admin-payment-gateway-enabled.php
          customer-cancelled-order.php
          customer-completed-order.php
          customer-failed-order.php
          customer-fulfillment-created.php
          customer-fulfillment-deleted.php
          customer-fulfillment-updated.php
          customer-invoice.php
          customer-new-account.php
          customer-note.php
          customer-on-hold-order.php
          customer-order-withdrawal-requested.php
          customer-pos-completed-order.php
          customer-pos-refunded-order.php
          customer-processing-order.php
          customer-refunded-order.php
          customer-reset-password.php
          customer-review-request.php
          customer-stock-notification-verified.php
          customer-stock-notification-verify.php
          customer-stock-notification.php
          customer-verify-email.php
          email-addresses.php
          email-customer-details.php
          email-downloads.php
          email-fulfillment-details.php
          email-fulfillment-items.php
          email-order-details.php
          email-order-items.php
        admin-cancelled-order.php
        admin-failed-order.php
        admin-new-order.php
        admin-order-withdrawal-requested.php
        admin-payment-gateway-enabled.php
        customer-cancelled-order.php
        customer-completed-order.php
        customer-failed-order.php
        customer-fulfillment-created.php
        customer-fulfillment-deleted.php
        customer-fulfillment-updated.php
        customer-invoice.php
        customer-new-account.php
        customer-note.php
        customer-on-hold-order.php
        customer-order-withdrawal-requested.php
        customer-pos-completed-order.php
        customer-pos-refunded-order.php
        customer-processing-order.php
        customer-refunded-order.php
        customer-reset-password.php
        customer-review-request.php
        customer-stock-notification-verified.php
        customer-stock-notification-verify.php
        customer-stock-notification.php
        customer-verify-email.php
        email-addresses.php
        email-button.php
        email-customer-details.php
        email-downloads.php
        email-footer.php
        email-fulfillment-details.php
        email-fulfillment-items.php
        email-header.php
        email-mobile-messaging.php
        email-order-details.php
        email-order-items.php
        email-styles.php
      global/
        breadcrumb.php
        form-login.php
        quantity-input.php
        sidebar.php
        wrapper-end.php
        wrapper-start.php
      loop/
        add-to-cart.php
        header.php
        loop-end.php
        loop-start.php
        no-products-found.php
        orderby.php
        pagination.php
        price.php
        rating.php
        result-count.php
        sale-flash.php
      myaccount/
        dashboard.php
        downloads.php
        form-add-payment-method.php
        form-edit-account.php
        form-edit-address.php
        form-login.php
        form-lost-password.php
        form-order-withdrawal.php
        form-reset-password.php
        lost-password-confirmation.php
        my-account.php
        my-address.php
        my-downloads.php
        my-orders.php
        navigation.php
        orders.php
        payment-methods.php
        stock-notifications.php
        view-order.php
      notices/
        error.php
        notice.php
        success.php
      order/
        attribution-details.php
        customer-history.php
        customer-review-order-empty.php
        customer-review-order-row.php
        customer-review-order.php
        form-tracking.php
        order-again.php
        order-details-customer.php
        order-details-fulfillment-item.php
        order-details-fulfillments.php
        order-details-item.php
        order-details.php
        order-downloads.php
        star-rating.php
        tracking.php
      parts/
        checkout-header.html
        coming-soon-social-links.html
        external-product-add-to-cart-with-options.html
        grouped-product-add-to-cart-with-options.html
        mini-cart.html
        simple-product-add-to-cart-with-options.html
        variable-product-add-to-cart-with-options.html
      product-form/
        simple.php
      single-product/
        add-to-cart/
          external.php
          grouped.php
          simple.php
          variable.php
          variation-add-to-cart-button.php
          variation.php
        tabs/
          additional-information.php
          description.php
          tabs.php
        back-in-stock-form.php
        meta.php
        photoswipe.php
        price.php
        product-attributes.php
        product-image.php
        product-thumbnails.php
        rating.php
        related.php
        review-meta.php
        review-rating.php
        review.php
        sale-flash.php
        share.php
        short-description.php
        stock.php
        title.php
        up-sells.php
      templates/
        blockified/
          archive-product.html
          coming-soon.html
          order-confirmation.html
          page-cart.html
          page-checkout.html
          product-search-results.html
          README.md
          single-product.html
          taxonomy-product_attribute.html
        archive-product.html
        coming-soon.html
        order-confirmation.html
        page-cart.html
        page-checkout.html
        product-search-results.html
        single-product.html
        taxonomy-product_attribute.html
      archive-product.php
      content-product-cat.php
      content-product.php
      content-single-product.php
      content-widget-price-filter.php
      content-widget-product.php
      content-widget-reviews.php
      dashboard-widget-reviews.php
      product-searchform.php
      single-product-reviews.php
      single-product.php
      taxonomy-product-attribute.php
      taxonomy-product-cat.php
      taxonomy-product-tag.php
    .gitattributes
    .phpunit-watcher.yml
    .wp-env.e2e.json
    .wp-env.json
    .wp-env.test.json
    composer.json
    eslint.config.mjs
    license.txt
    NEXT_CHANGELOG.md
    package.json
    phpcs.xml
    phpstan-baseline.neon
    phpstan.neon
    phpunit.xml
    README.md
    readme.txt
    tsconfig.json
    uninstall.php
    woocommerce.php
  woocommerce-beta-tester/
    api/
      admin-notes/
        add-note.php
        delete-all-notes.php
      features/
        features.php
      live-branches/
        install.php
        manifest.php
      options/
        rest-api.php
      remote-inbox-notifications/
        class-wc-beta-tester-remote-inbox-notifications-helper.php
        class-wca-test-helper-remote-inbox-notifications.php
      remote-logging/
        remote-logging.php
      remote-spec-validator/
        class-wca-test-helper-remote-spec-validator.php
      rest-api-filters/
        class-wca-test-helper-rest-api-filters.php
        hook.php
      tools/
        templates/
          9.7.1 - Coming soon entire site.html
          9.7.1 - Coming soon store only.html
        class-fake-wcpayments.php
        delete-all-products.php
        disable-wc-email.php
        fake-woo-payments-gateway.php
        load-template-version.php
        reset-launch-your-store.php
        run-wc-admin-daily.php
        set-block-template-logging-threshold.php
        set-coming-soon-mode.php
        set-wccom-base-url.php
        trigger-cron-job.php
        trigger-update-callbacks.php
        trigger-wca-install.php
        wccom-request-errors.php
      tracks/
        class-tracks-debug-log.php
      api.php
    changelog/
      .gitkeep
      49120-remove-async-product-editor-category-field
      55796-add-54370-hide_flat_rate_when_free
      56506-remove-wp-components-types
      56746-dev-webpack-deps-review
      57299-fix-wireit-in-ci
      57605-fix-wc-beta-tester-cys-reset
      58755-dev-53714
      58941-dev-consolidate-packages-license-version
      61753-fix-support-composer-update
      64076-remove-legacy-rest-api-options
      66078-dehoist-react
      66097-bump-wp-env-and-playwright
      add-55908-beta-tester-ci-config
      add-simplify-cys-remove-unnecessary-code
      add-woocommerce-beta-tester-template-load-tool
      dev-add-note-drop-image-layout
      dev-drop-phpunit-and-bump-symfony-process
      dev-eslint-no-floating-promises
      fix-beta-tester-delete-option-error
      fix-beta-tester-live-branch
      fix-live-branches-github-selectors
      fix-missing-index-build
      fix-wordpress-data-dependency
      remove-product-editor-devtools
      update-migrate-reactify-feature-flag
      update-php-dev-dependency-security-patches
      update-pnpm-10-upgrade
      update-switch-version-button-location
      update-wp-68-packages
      update-wpcs-3-4-1
      wooplug-5699-add-license-file-to-root
      wooplug-6930-adopt-import-order
      wooplug-6930-eslint-v10-flat-config
    includes/
      views/
        html-admin-missing-woocommerce.php
      class-wc-beta-tester-admin-assets.php
      class-wc-beta-tester-admin-menus.php
      class-wc-beta-tester-admin-notices.php
      class-wc-beta-tester-channel.php
      class-wc-beta-tester-cli.php
      class-wc-beta-tester-import-export.php
      class-wc-beta-tester-live-branches-installer.php
      class-wc-beta-tester-live-branches.php
      class-wc-beta-tester-override-coming-soon-options.php
      class-wc-beta-tester-plugin-upgrader.php
      class-wc-beta-tester-version-picker.php
      class-wc-beta-tester-wccom-requests.php
      class-wc-beta-tester.php
      wc-beta-tester-settings-list.php
    src/
      admin-notes/
        add-note.js
        admin-notes.js
        delete-all-notes.js
        index.js
      app/
        app.js
        index.js
      example-fills/
        experimental-woocommerce-wcpay-feature.js
      experiments/
        data/
          action-types.js
          actions.js
          constants.js
          index.js
          reducer.js
          resolvers.js
          selectors.js
        index.js
        NewExperimentForm.js
      features/
        data/
          action-types.js
          actions.js
          constants.ts
          index.js
          reducer.js
          resolvers.js
          selectors.js
        index.js
      live-branches/
        components/
          BranchList.tsx
        hooks/
          live-branches.tsx
        App.tsx
        index.tsx
      options/
        data/
          action-types.js
          actions.js
          constants.js
          index.js
          reducer.js
          resolvers.js
          selectors.js
        index.js
        option-modal.js
      payments/
        index.js
      remote-inbox-notifications/
        data/
          action-types.js
          actions.js
          constants.js
          index.js
          reducer.js
          resolvers.js
          selectors.js
        index.js
      remote-logging/
        constants.ts
        index.tsx
        register-exception-filter.tsx
      remote-spec-validator/
        data/
          action-types.js
          actions.js
          constants.js
          index.js
          reducer.js
          resolvers.js
          selectors.js
        index.js
      rest-api-filters/
        data/
          action-types.js
          actions.js
          constants.js
          index.js
          reducer.js
          resolvers.js
          selectors.js
        index.js
      tools/
        commands/
          disable-email.js
          fake-woo-payments.js
          index.js
          load-template-version.js
          set-coming-soon-mode.js
          set-wccom-base-url.js
          set-wccom-request-errors.js
          trigger-cron.js
          trigger-update-callbacks.js
          update-block-template-logging-threshold.tsx
        data/
          action-types.ts
          actions.js
          constants.js
          constants.ts
          index.js
          index.ts
          reducer.js
          resolvers.js
          selectors.js
        index.js
        README.md
      index.js
    typing/
      global.d.ts
    userscripts/
      README.md
      wc-live-branches.user.js
    .prettierrc.js
    .travis.yml
    .wp-env.json
    changelog.txt
    composer.json
    eslint.config.mjs
    EXTENDING-WC-ADMIN-HELPER.md
    NEXT_CHANGELOG.md
    package.json
    phpcs.xml
    plugin.php
    README.md
    tsconfig.json
    webpack.config.js
    woocommerce-beta-tester.php
tools/
  changelogger/
    class-formatter.php
    class-legacy-core-formatter.php
    class-package-formatter.php
    class-php-package-formatter.php
    class-plugin-formatter.php
  code-analyzer/
    src/
      commands/
        analyzer/
          analyzer-lint.ts
          analyzer-major-minor.ts
          analyzer-scan.ts
          index.ts
      print.ts
      utils.ts
    eslint.config.mjs
    index.ts
    jest.config.js
    package.json
    README.md
    tsconfig.json
  compare-perf/
    calculate-delta.ts
    config.js
    index.js
    log-to-codevitals.js
    metric-utils.js
    package.json
    performance.js
    process-reports.ts
    tsconfig.json
    utils.js
  eslint-config/
    core-modules.js
    index.js
    package.json
    README.md
  executors/
    changelogger/
      executor.json
      impl.js
      impl.ts
      package.json
      schema.json
  monorepo/
    check-changelogger-use.php
  monorepo-merge/
    codemods/
      rename-intl-domain.js
    src/
      commands/
        merge/
          index.ts
        transfer-issues/
          index.ts
      const.ts
      index.ts
      node-async.ts
    eslint.config.mjs
    package.json
    tsconfig.json
  monorepo-utils/
    fonts/
      Standard.flf
    src/
      changefile/
        index.ts
        README.md
      ci-jobs/
        index.ts
        README.md
      code-freeze/
        commands/
          accelerated-prep/
            index.ts
            types.ts
          branch/
            index.ts
          changelog/
            index.ts
            types.ts
          get-version/
            index.ts
          milestone/
            index.ts
          version-bump/
            bump.ts
            index.ts
            types.ts
          index.ts
        README.md
      core/
        github/
          api.ts
          repo.ts
          types.ts
        environment.ts
        git.ts
        logger.ts
        util.ts
        version.ts
        wpenv.ts
      github/
        commands/
          replace-labels/
            index.ts
          index.ts
        README.md
      pull-requests/
        commands/
          add-changelog-file.ts
          index.ts
        README.md
      slack/
        index.ts
        README.md
        slack-service.ts
      slack-test-report/
        index.ts
        README.md
      workflow-profiler/
        commands/
          list/
            index.ts
          profile/
            index.ts
          index.ts
        config.ts
      index.ts
    eslint.config.mjs
    jest.config.js
    package.json
    README.md
    tsconfig.json
    webpack.config.js
  package-release/
    src/
      commands/
        prepare/
          index.ts
        publish/
          index.ts
      changelogger.ts
      const.ts
      index.ts
      validate.ts
    eslint.config.mjs
    package.json
    README.md
    tsconfig.json
  release-posts/
    commands/
      release-post/
        index.ts
        release-post-beta.ts
        release-post-contributors.ts
        release-post-rc.ts
        release-post-release.ts
    templates/
      beta-release.ejs
      contributor.ejs
      contributors.ejs
      database.ejs
      hooks.ejs
      oauth.ejs
      rc-release.ejs
      release.ejs
      templates.ejs
    index.ts
    package.json
    program.ts
    README.md
    tsconfig.json
  storybook/
    .storybook/
      main.mjs
      manager.js
      preview-head.html
      preview.js
    stories/
      docs/
        introduction.mdx
    .babelrc.json
    import-wp-css-storybook.sh
    package.json
    setting.mock.js
    tsconfig.json
    webpack.config.js
  .gitkeep
  README.md
.codecov.yml
.coderabbit.yml
.gitattributes
.markdownlint.json
.npmrc
.nvmrc
.pnpmfile.cjs
.prettierrc.js
.stylelintrc
.syncpackrc
AGENTS.md
changelog.txt
CLAUDE.md
CODE_OF_CONDUCT.md
CODEOWNERS
CONTRIBUTING.md
DEVELOPMENT.md
eslint.config.mjs
license.txt
package.json
phpcs.xml
pnpm-workspace.yaml
README.md
renovate.json
SECURITY.md
tsconfig.base.json
</directory_structure>

<files>
This section contains the contents of the repository's files.

<file path=".claude/settings.json">
{
  "description": "Default Claude Code settings for the WooCommerce repository",
  "permissions": {
    "allow": [
      "Skill(woocommerce-backend-dev)",
      "Skill(woocommerce-code-review)",
      "Skill(woocommerce-copy-guidelines)",
      "Skill(woocommerce-dev-cycle)",
      "Skill(woocommerce-markdown)"
    ],
    "deny": [],
    "ask": []
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r \".tool_input.file_path // empty\" | { read -r f; if echo \"$f\" | grep -qE \"/(build|build-module|build-style|build-types|dist)/|[.]asset[.]php$\"; then printf '{\"decision\":\"block\",\"reason\":\"This is a generated/built file. Edit the source instead.\"}'; fi; }"
          }
        ]
      }
    ]
  }
}
</file>

<file path=".cursor/rules/avoid-regex.mdc">
---
description: This rule discourages the use of regular expressions in favor of more readable and maintainable alternatives.
globs: **/*.php,**/*.js,**/*.jsx,**/*.tsx,**/*.ts
alwaysApply: true
---

# Avoid Regular Expressions

This rule provides guidance for writing more readable and maintainable code by avoiding regular expressions unless absolutely necessary.

## Why Avoid Regex?

Regular expressions are:
- Hard to read and understand
- Difficult to debug when issues arise
- Prone to unexpected side effects
- Easy to introduce security vulnerabilities
- Not accessible to developers who don't use them regularly

## When Regex Might Be Acceptable

Only consider regex when:
1. **No built-in alternative exists** - The language doesn't provide a suitable string/array method
2. **Performance is critical** - And regex is significantly faster (measure first)
3. **Complex pattern matching** - And the pattern is well-documented and tested
4. **Legacy code maintenance** - When modifying existing regex that works correctly

## If You Must Use Regex

When regex is truly necessary:
... (38 lines truncated)
</file>

<file path=".cursor/rules/code-quality.mdc">
---
globs: **/*.php,**/*.js,**/*.jsx,**/*.tsx,**/*.ts
alwaysApply: false
---
# Code Quality

This rule provides guidance for best code quality practices and preventing bugs in WooCommerce.

## Best Practices

Don't trust that extension developers will follow the best practices, make sure that all code:

- Guards against unexpected inputs.
- Sanitizes and validates any potentially dangerous inputs.
- Is backwards compatible.
- Is readable and intuitive.
- Has unit or E2E tests where applicable.
</file>

<file path=".cursor/rules/generate-pr-description.mdc">
---
alwaysApply: true
---

# Generating a Pull Request Description

This rule provides guidance for generating a pull request (PR) description in this repository.

## Where to Find the Template

The PR template is located at [`.github/PULL_REQUEST_TEMPLATE.md`](mdc:.github/PULL_REQUEST_TEMPLATE.md). Always use this template as the basis for your PR descriptions.

## Best Practices

-   **Preserve Markdown Structure:** Do not remove or alter required markdown sections, especially those used by automation (e.g., changelog entry details and comments).
-   **Changelog Section:** The changelog section in the PR description must keep the markdown structure from the PR template exactly as-is, including all checkboxes, comments, and headings. Only the appropriate checkbox may be checked, and the changelog message must be placed under the `#### Message` heading and before the closing `</details>` tag. Do not add, remove, or reformat any part of the changelog section except for checking the box and adding the message in the correct place.

If the PR does not require a changelog message a comment can be left after the `#### Comment` heading and before the closing `</details>` tag.

-   **Be Concise and Clear:** Summarize the changes, testing steps, and rationale in a way that is easy for reviewers to understand.
-   **Remove Irrelevant Sections:** You may erase template sections that are not applicable to your PR, except for those required by automation. Do not remove any checkbox items.
-   **Testing Instructions:** Provide clear, step-by-step instructions for how to test the changes.
-   **Always Output Markdown:** When the user requests a PR description, always provide the output in markdown format, using the structure and sections from the PR template. The output should be copy-paste ready for a GitHub PR and must include all required sections unless the user specifies otherwise. Do not provide plain text or summary—always provide the markdown-formatted PR template filled out with the relevant details from the change, following these rules strictly.

## Example

See the PR template for the required structure and sections. When generating a PR description, ensure that all required checkboxes and markdown details are preserved for automation compatibility, and that the changelog message is placed under the appropriate heading as specified above.

# Generating a Pull Request Description

... (22 lines truncated)
</file>

<file path=".cursor/rules/git.mdc">
---
description: Rules for various git actions that happen with this project. 
globs: 
---

# Creating Branches

Branch names should go by the following structure (anything in "{}" brackets is a placeholder). "{short-slug}" should be replaced with a short name that best describes the changes - do ask for confirmation if needed.
- `release/{version}` for release branches.
- `refactor/{short-slug}` for refactors.
- `test/{short-slug}` for changes that are only test updates or additions.
- `fix/{short-slug}` for changes that fix a bug. Prompt the user for the issue number the fix is for and include that in the branch name.
- `add/{short-slug}` for changes that are adding a new feature.

# Commits

Make sure each commit addresses an atomic unit of work that independently works.

Make sure the commit message has a subject line which includes a brief description of the change and (if needed), why it was necessary. Write the subject in the imperative, start with a verb, and do not end with a period. The subject line should be no longer than 50 characters.

There must be an empty line between the subject line and the rest of the commit message (if any). The commit body should be no longer than 72 characters.

The commit message should explain what caused the problem and what its consequences are (if helpful for understanding the changes).

The commit message should explain how the changes achieve the goal, but only if it isn't obvious.
</file>

<file path=".cursor/rules/woo-build.mdc">
---
description: This rule provides guidance for building the WooCommerce plugin and watching for changes in the repository.
globs:
alwaysApply: false
---
# Building the WooCommerce plugin

This rule provides guidance for building the WooCommerce plugin and watching for changes in this repository.

## Installing dependencies and building

Specific dependencies and build instructions are listed in `README.md`.

The commands to build are

```bash
# Install the PHP and Composer dependencies for all of the plugins, packages, and tools.
# PNPM automatically uses the pinned Node version for every script it runs.
pnpm install --frozen-lockfile
# Build all of the plugins, packages, and tools in the monorepo
pnpm build
```

And the command must be run in the main repository directory.

## Watching for changes

To watch for changes use

```bash
... (11 lines truncated)
</file>

<file path=".cursor/rules/woo-phpunit.mdc">
---
description:
globs: plugins/woocommerce/tests/**/*.php
alwaysApply: false
---

# WooCommerce PHPUnit Tests

Rules for running WooCommerce PHPUnit tests.

## Run PHPUnit Tests

Run WooCommerce PHPUnit tests for specific files or directories.

The command to run is

```
pnpm run test:php:env {relative_path} --verbose
```

And the command must be run in the `plugins/woocommerce` directory.

## Test Execution Best Practices

### Command Structure

-   **Basic test file**: `pnpm run test:php:env tests/php/includes/rest-api/Controllers/Version3/class-wc-rest-product-brands-controller-test.php --verbose`
-   **Filter by test method**: `pnpm run test:php:env -- --filter="test_get_brands_with_correct_count"`
-   **Filter by test class**: `pnpm run test:php:env -- --filter="WC_REST_Product_Brands_Controller_Test"`

... (57 lines truncated)
</file>

<file path=".husky/post-checkout">
# The hook documentation: https://git-scm.com/docs/githooks.html#_post_checkout
CHECKOUT_TYPE=$3
HEAD_NEW=$2
HEAD_PREVIOUS=$1

whiteColoured='\033[0m'
orangeColoured='\033[1;33m'

# '1' is a branch checkout
if [ "$CHECKOUT_TYPE" = '1' ]; then
	# Auto-refresh dependencies when switching between branches.
	changedManifests=$( ( git diff --name-only $HEAD_NEW $HEAD_PREVIOUS | grep -E '(pnpm-lock.yaml|composer.lock)$' ) || echo '' )
	if [ -n "$changedManifests" ]; then
		printf "${whiteColoured}The following file(s) in the new branch differs from the original one, dependencies might need to be refreshed:\n"
		printf "${whiteColoured}    %s\n" $changedManifests
		printf "${orangeColoured}If you are working on something in this branch, ensure to refresh dependencies with 'pnpm install --frozen-lockfile'\n"
	fi

	# Auto-switch pnpm versions when switching between branches.
	currentPnpmVersion=$( ( command -v pnpm > /dev/null && pnpm --version 2>/dev/null ) || echo 'n/a' )
	targetPnpmVersion=$( grep packageManager package.json | sed -nr 's/.+packageManager.+pnpm@([[:digit:].]+).+/\1/p' )
	if [ "$currentPnpmVersion" != "$targetPnpmVersion" ]; then
		printf "${orangeColoured}pnpm versions mismatch: in use '$currentPnpmVersion', needed '$targetPnpmVersion'. Enabling corepack for automatic pnpm version switching (see https://nodejs.org/api/corepack.html#corepack for more details).\n"
		command -v corepack > /dev/null && corepack enable pnpm
	fi

	currentComposerDate=$( ( command -v composer > /dev/null && ( composer --version 2>/dev/null | awk '{print $4}' ) ) || echo '' )
	if [ -n "$currentComposerDate" ]; then
		current=$( php -r "echo date( 'Ymd', strtotime( '$currentComposerDate' ) );" )
		threshold=$( php -r "echo date( 'Ymd', strtotime( '-12 months' ) );" )
... (7 lines truncated)
</file>

<file path=".husky/post-merge">
# The hook documentation: https://git-scm.com/docs/githooks.html#_post_merge

# Auto-switch pnpm versions when pulled changes include pnpm version change.
currentPnpmVersion=$( ( command -v pnpm > /dev/null && pnpm --version 2>/dev/null ) || echo 'n/a' )
targetPnpmVersion=$( grep packageManager package.json | sed -nr 's/.+packageManager.+pnpm@([[:digit:].]+).+/\1/p' )
if [ "$currentPnpmVersion" != "$targetPnpmVersion" ]; then
	printf "${orangeColoured}pnpm versions mismatch: in use '$currentPnpmVersion', needed '$targetPnpmVersion'. Enabling corepack for automatic pnpm version switching (see https://nodejs.org/api/corepack.html#corepack for more details).\n"
	command -v corepack > /dev/null && corepack enable pnpm
fi

# Refresh dependencies when pulled changes might change the deps.
changedManifests=$( ( git diff --name-only HEAD ORIG_HEAD  | grep -E '(pnpm-lock.yaml|composer.lock)$' ) || echo '' )
if [ -n "$changedManifests" ]; then
	printf "It was a change in the following file(s) - refreshing dependencies:\n"
	printf "    %s\n" $changedManifests

	pnpm install --frozen-lockfile
fi

# Wireit has been removed from the monorepo. Tear down any leftover .wireit
# directories so they stop occupying disk space on machines that built with it
# previously.
leftoverWireitDirectories=$(find . -type d -name .wireit -not -path '*/node_modules/*' 2>/dev/null)
if [ -n "$leftoverWireitDirectories" ]; then
	echo "Removing leftover .wireit directories"
	echo "$leftoverWireitDirectories" | xargs rm -rf
fi
</file>

<file path=".husky/pre-commit">
changed_block_metadata=$(git diff --cached --name-only --diff-filter=ACMR -- 'plugins/woocommerce/client/blocks/assets/js/**/block.json')

if [ -z "$changed_block_metadata" ]; then
	exit 0
fi

printf '%s\n' 'Staged WooCommerce block metadata changes detected. Updating block reference documentation...'

if ! corepack pnpm --filter=@woocommerce/block-library build:docs:block-references; then
	printf '%s\n' 'Failed to regenerate block reference documentation. Aborting commit.' >&2
	exit 1
fi

git add docs/block-development/reference/block-references.md
</file>

<file path=".husky/pre-push">
./bin/pre-push.sh
</file>

<file path=".linear/release-kickoff-beta.md">
# [{release_main_version}] Release `{release_version}`

These are the instructions for releasing `{release_version}`, scheduled for `{release_date}`.

----

Perform all the steps below in order. When running _any_ GitHub workflow, ensure you do it from the `trunk` branch (the default) and input the release version or branch as indicated.

Keep the _[Release Troubleshooting & Recovery](https://developer.woocommerce.com/docs/contribution/releases/troubleshooting/)_ guide handy, in case you encounter any issues.

----

### 1. Pre-build checks

- [ ] Confirm [GitHub services](https://www.githubstatus.com/) are operational.
- [ ] Verify no open [issues]({repository_url}/issues?q=is:open+is:issue+milestone:{release_milestone}) or [pull requests]({repository_url}/pulls?q=is:open+is:pr+draft:false+milestone:{release_milestone}) exist against the `{release_milestone}` milestone. Ping authors to merge or close; if that can't happen yet, mark the PR as a draft.
- [ ] Ensure that there aren't any pull requests [with label "cherry pick failed"]({repository_url}/pulls?q=is:pr+label:%22cherry+pick+failed%22) that apply to this release that haven't been actioned.
- [ ] Confirm the `Stable tag` value [in the readme.txt on the release branch]({repository_url}/blob/{release_branch}/plugins/woocommerce/readme.txt#L7) matches the one [on WordPress.org's `trunk`](https://plugins.trac.wordpress.org/browser/woocommerce/trunk/readme.txt#L7).


### 2. Build the release package

- [ ] Run workflow **[Release: Bump version number]({repository_url}/actions/workflows/release-bump-version.yml)**: enter `{release_main_version}` as _Release branch_ and `{release_type}` as _Type of version bump to perform_.
- [ ] Review and merge the PR that was generated against the release branch. Check for remaining open [issues]({repository_url}/issues?q=is:open+is:issue+milestone:{release_milestone}) or [pull requests]({repository_url}/pulls?q=is:open+is:pr+draft:false+milestone:{release_milestone}) in the `{release_milestone}` milestone.
- [ ] Run workflow **[Release: Compile changelog]({repository_url}/actions/workflows/release-compile-changelog.yml)**: enter `{release_main_version}` as _Version_ and leave _Release date_ empty, except when building the package ahead of schedule.
- [ ] Review and merge the PRs that were generated: one against `trunk` and another one against the release branch. Both are linked in the workflow run.
- [ ] Run workflow **[Release: Build ZIP file]({repository_url}/actions/workflows/release-build-zip-file.yml)** to build the asset and create the GitHub release: enter `{release_main_version}` as _Release branch_ and check _Create GitHub release_.
- [ ] Confirm that a draft `{release_version}` release [was created in the repository]({repository_url}/releases) with an attached `woocommerce.zip` asset.


... (12 lines truncated)
</file>

<file path=".linear/release-kickoff-patch.md">
# [{release_main_version}] Release `{release_version}`

These are the instructions for releasing `{release_version}`, scheduled for `{release_date}`.

----

Perform all the steps below in order. When running _any_ GitHub workflow, ensure you do it from the `trunk` branch (the default) and input the release version or branch as indicated.

Keep the _[Release Troubleshooting & Recovery](https://developer.woocommerce.com/docs/contribution/releases/troubleshooting/)_ guide handy, in case you encounter any issues.

----

### 1. Go/no-go

For scheduled stable releases, hold this 24-48 hours before the release date with the Product DRIs named on the parent tracking issue - ping `@woo-core-release` in Slack if you need to reach them or aren't sure who's available. Bring in QualityOps and the Atomic contact when staging or monitoring left open questions. See the [readiness guide](https://developer.woocommerce.com/docs/contribution/releases/readiness/) for details.

- [ ] The readiness review is complete and its verdicts still hold.
- [ ] No new blocking findings since the readiness review (check `#woo-core-releases` threads and the [newest issues]({repository_url}/issues?q=is%3Aissue%20state%3Aopen%20sort%3Acreated-desc)).
- [ ] Decision recorded as a comment on this issue - **go**, **no-go**, or **go with conditions** - with the names behind it.

For scheduled releases, the readiness review is the one in the RC sub-issue. Point releases have no RC: run the [readiness criteria](https://developer.woocommerce.com/docs/contribution/releases/readiness/) over the changes being shipped as part of this go/no-go, with verdicts per the [release decision matrix](https://developer.woocommerce.com/docs/contribution/releases/decision-matrix/). For unscheduled point releases shipping an urgent fix, a quick go/no-go with `@woo-core-release` in `#woo-core-releases` is enough - record the outcome here all the same.


### 2. Pre-build checks

- [ ] Confirm [GitHub services](https://www.githubstatus.com/) are operational.
- [ ] Verify no open [issues]({repository_url}/issues?q=is:open+is:issue+milestone:{release_milestone}) or [pull requests]({repository_url}/pulls?q=is:open+is:pr+draft:false+milestone:{release_milestone}) exist against the `{release_milestone}` milestone. Ping authors as needed to merge or close.
- [ ] Ensure that there aren't any pull requests [with label "cherry pick failed"]({repository_url}/pulls?q=is:pr+label:%22cherry+pick+failed%22) that apply to this release that haven't been actioned.
- [ ] Confirm the `Stable tag` value [in the readme.txt on the release branch]({repository_url}/blob/{release_branch}/plugins/woocommerce/readme.txt#L7) matches the one [on WordPress.org's `trunk`](https://plugins.trac.wordpress.org/browser/woocommerce/trunk/readme.txt#L7).

... (41 lines truncated)
</file>

<file path=".linear/release-kickoff-rc.md">
# [{release_main_version}] Release `{release_version}`

These are the instructions for releasing `{release_version}`, scheduled for `{release_date}`.

----

Perform all the steps below in order. When running _any_ GitHub workflow, ensure you do it from the `trunk` branch (the default) and input the release version or branch as indicated.

Keep the _[Release Troubleshooting & Recovery](https://developer.woocommerce.com/docs/contribution/releases/troubleshooting/)_ guide handy, in case you encounter any issues.

----

### 1. Release readiness review

Go through this checklist together with the Product DRIs named on the parent tracking issue before starting the build - ping `@woo-core-release` in Slack if you need to reach them or aren't sure who's available. The goal is a deliberate "this RC is ready to go out" call, with the evidence in one place. See the [readiness guide](https://developer.woocommerce.com/docs/contribution/releases/readiness/) for details on each item.

- [ ] Review the QIT compatibility regression sweep report for this prerelease. Every introduced issue has a verdict: blocking or not; non-blocking findings get their full verdict in the next item.
- [ ] Every open finding against this release (bug reports, testing threads, monitoring alerts, non-blocking QIT sweep findings) has a linked issue and a verdict per the [release decision matrix](https://developer.woocommerce.com/docs/contribution/releases/decision-matrix/): release-blocking / fix in a point release / next release / not a bug.
- [ ] The rollback path for this release is known: who reverts, how, and what revert means for this version (see the [troubleshooting guide](https://developer.woocommerce.com/docs/contribution/releases/troubleshooting/)).
- [ ] Comms are ready: the changelog is in shape and there's a known-issues list if the verdicts above left anything open.

If an item can't be checked, raise it in `#woo-core-releases` before continuing - delaying an RC is cheaper than reverting a stable.


### 2. Pre-build checks

- [ ] Confirm [GitHub services](https://www.githubstatus.com/) are operational.
- [ ] Verify no open [issues]({repository_url}/issues?q=is:open+is:issue+milestone:{release_milestone}) or [pull requests]({repository_url}/pulls?q=is:open+is:pr+draft:false+milestone:{release_milestone}) exist against the `{release_milestone}` milestone. Ping authors as needed to merge or close.
- [ ] Ensure that there aren't any pull requests [with label "cherry pick failed"]({repository_url}/pulls?q=is:pr+label:%22cherry+pick+failed%22) that apply to this release that haven't been actioned.
- [ ] Confirm the `Stable tag` value [in the readme.txt on the release branch]({repository_url}/blob/{release_branch}/plugins/woocommerce/readme.txt#L7) matches the one [on WordPress.org's `trunk`](https://plugins.trac.wordpress.org/browser/woocommerce/trunk/readme.txt#L7).
... (35 lines truncated)
</file>

<file path=".linear/release-kickoff.md">
# [{release_main_version}] Release tracking

This issue provides visibility on the progress of the release process of WooCommerce core **{release_main_version}**.

- **Main version being released:** `{release_main_version}`
- **Milestone:** [{release_milestone}]({repository_url}/issues?q=is:open+milestone:{release_milestone})
- **Release branch:** [`{release_branch}`]({repository_url}/tree/{release_branch})
- **Release lead:** {lead_user} ({lead_team})
- **Product DRI:** James Kemp, Warren Holmes (reachable via `@woo-core-release` in Slack)
- **Relevant dates:** ([release calendar](https://developer.woocommerce.com/release-calendar/))
  - **Feature Freeze:** {date_feature_freeze}
  - **Beta 1:** {date_beta1}
  - **Beta 2:** {date_beta2}
  - **RC 1:** {date_rc1}
  - **Stable:** {date_stable}

---

⚠ Complete the setup steps below to get started, and keep the rest of this section handy as reference throughout the release cycle.

##### Setup

- [ ] Read this issue carefully and familiarize yourself with the [release process documentation](https://developer.woocommerce.com/docs/contribution/releases/).
- [ ] On feature freeze ({date_feature_freeze}), update `@woo-core-release` membership in Slack: add yourself, give {previous_release_lead} a heads-up, then remove them. The previous cycle's lead stays for point releases. Leave everyone else alone.
- [ ] Join the release channels in Slack (`#woo-core-releases`, `#woo-core-releases-notifications`), where discussions happen and notifications are sent.

##### Good to know

- When in doubt at any step, ping `@woo-core-release` in Slack. In particular, you'll need to loop in the Product DRIs listed above via the handle for the readiness review and the go/no-go during the RC and stable releases.
- For every release in the cycle, there's a corresponding sub-issue. On the date of each release (see schedule above), open the relevant issue and follow the instructions in it.
... (9 lines truncated)
</file>

<file path="docs/_docu-tools/consent-plugin/gtag.ts">
import type {ClientModule} from '@docusaurus/types';
⋮----
onRouteDidUpdate(
</file>

<file path="docs/_docu-tools/consent-plugin/index.ts">
import type { LoadContext, Plugin } from '@docusaurus/types';
⋮----
interface ConsentPluginOptions {
	trackingID?: string;
}
⋮----
export default function pluginConsent(
	context: LoadContext,
	options: ConsentPluginOptions = {}
): Plugin | null
⋮----
contentLoaded(
⋮----
injectHtmlTags()
</file>

<file path="docs/_docu-tools/llms-txt/index.ts">
import type { LoadContext, Plugin } from '@docusaurus/types';
⋮----
export default function llmsTxtPlugin(
    context: LoadContext,
): Plugin<void>
⋮----
async postBuild(): Promise<void>
⋮----
async function getAllMarkdownFiles(dir: string): Promise<Array<
⋮----
async function scanDirectory(currentDir: string, relativePath: string = ''): Promise<void>
⋮----
// Skip _docu-tools directory
⋮----
function extractTitle(content: string, filename: string): string
⋮----
async function generateFileList(files: Array<
⋮----
async function generateCombinedContent(files: Array<
⋮----
function extractDescription(content: string): string
⋮----
// Remove headers
⋮----
// Get first paragraph (non-empty line)
⋮----
function removeFrontmatter(content: string): string
</file>

<file path="docs/_docu-tools/src/components/CookieBanner/index.tsx">
import React, { useState, useEffect } from 'react';
import Cookies from 'js-cookie';
⋮----
interface CookieBuckets {
  ad_storage: boolean;
  analytics_storage: boolean;
  functionality_storage: boolean;
  personalization_storage: boolean;
  security_storage: boolean;
}
⋮----
interface CookiePreferences {
  ok: boolean;
  isDefault: boolean;
  buckets: CookieBuckets;
}
⋮----
const createConsentOptions = (buckets: CookieBuckets) => (
⋮----
const updateGtagConsent = (buckets: CookieBuckets) =>
⋮----
const handleAcceptAll = () =>
⋮----
const handleSavePreferences = () =>
⋮----
onChange=
</file>

<file path="docs/_docu-tools/src/components/HomepageFeatures/index.tsx">
import type {ReactNode} from 'react';
import clsx from 'clsx';
import Heading from '@theme/Heading';
import styles from './styles.module.css';
⋮----
type FeatureItem = {
  title: string;
  Svg: React.ComponentType<React.ComponentProps<'svg'>>;
  description: ReactNode;
};
⋮----
<div className=
</file>

<file path="docs/_docu-tools/src/components/MarkdownCopy/index.tsx">
import React, { useState, useRef } from 'react';
import TurndownService from 'turndown';
⋮----
const copyMarkdownToClipboard = async () =>
⋮----
const announceToScreenReader = (message: string) =>
⋮----
const handleKeyDown = (event: React.KeyboardEvent) =>
⋮----
const getAriaLabel = () =>
⋮----
const getButtonText = () =>
⋮----
aria-label=
</file>

<file path="docs/_docu-tools/src/js/sidebar-filters.js">
export function filterSidebarItems( items )
</file>

<file path="docs/_docu-tools/src/theme/MDXContent/index.tsx">
import React, {type ReactNode} from 'react';
import MDXContent from '@theme-original/MDXContent';
import type MDXContentType from '@theme/MDXContent';
import type {WrapperProps} from '@docusaurus/types';
import MarkdownCopy from '../../components/MarkdownCopy';
⋮----
type Props = WrapperProps<typeof MDXContentType>;
⋮----
export default function MDXContentWrapper(props: Props): ReactNode
</file>

<file path="docs/_docu-tools/src/theme/Root.js">
export default function Root(
</file>

<file path="docs/_docu-tools/utils/docusaurus-faster.deploy.config.js">

</file>

<file path="docs/_docu-tools/utils/docusaurus.deploy.config.js">
configureWebpack()
</file>

<file path="docs/_docu-tools/docusaurus.config.ts">
import { themes as prismThemes } from 'prism-react-renderer';
import type { Config } from '@docusaurus/types';
⋮----
import { filterSidebarItems } from './src/js/sidebar-filters';
⋮----
async sidebarItemsGenerator({
						defaultSidebarItemsGenerator,
						...args
})
</file>

<file path="docs/_docu-tools/package.json">
{
  "name": "woo-docs-migration",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "docusaurus": "docusaurus",
    "start": "docusaurus start",
    "build": "pnpm run lint:markdown && docusaurus build",
    "swizzle": "docusaurus swizzle",
    "deploy": "docusaurus deploy",
    "clear": "docusaurus clear",
    "serve": "docusaurus serve",
    "deploy-build": "docusaurus build --config ./utils/docusaurus.deploy.config.js",
    "write-translations": "docusaurus write-translations",
    "write-heading-ids": "docusaurus write-heading-ids",
    "lint:markdown": "markdownlint \"../**/*.md\" --ignore=\"../_docu-tools/\" --config=\"../../.markdownlint.json\"",
    "typecheck": "tsc"
  },
  "dependencies": {
    "@docsearch/core": "^4.7.0",
    "@docusaurus/core": "^3.10.2",
    "@docusaurus/faster": "^3.10.2",
    "@docusaurus/preset-classic": "^3.10.2",
    "@mdx-js/react": "^3.0.0",
    "clsx": "^2.0.0",
    "prism-react-renderer": "^2.3.0",
    "react": "^19.1.3",
    "js-cookie": "^3.0.8",
    "react-dom": "^19.1.3",
    "turndown": "^7.1.2"
... (25 lines truncated)
</file>

<file path="docs/_docu-tools/README.md">
# Website

This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.

## Installation

```bash
pnpm install
```

## Local Development

```bash
pnpm start
```

This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.

## Build

```bash
pnpm build
```

This command generates static content into the `build` directory and can be served using any static contents hosting service.

## Deployment

The contents in the `woocommerce/docs` folder are pulled via a nightly GitHub Actions cron job in the [woocommerce-woo-docs-multi-com repository](https://github.com/wpcomvip/woocommerce-woo-docs-multi-com), built for production, and a PR is created against the main branch of the same repository. The PR is then merged and the changes are deployed to the live site.

... (2 lines truncated)
</file>

<file path="docs/_docu-tools/sidebars.ts">
import type {SidebarsConfig} from '@docusaurus/plugin-content-docs';
</file>

<file path="docs/_docu-tools/tsconfig.json">
{
  // This file is not used in compilation. It is here just for a nice editor experience.
  "extends": "@docusaurus/tsconfig",
  "compilerOptions": {
    "baseUrl": "."
  },
  "exclude": [".docusaurus", "build"]
}
</file>

<file path="docs/apis/dual-api/_category_.json">
{
  "label": "Dual API (experimental)",
  "position": 3
}
</file>

<file path="docs/apis/dual-api/README.md">
---
post_title: 'Dual API (code + GraphQL)'
sidebar_label: 'Dual API'
sidebar_position: 0
---

# WooCommerce Dual API

The **dual API** is a code-first API architecture: you write plain PHP classes (the **code API**), and a build script generates a fully functional **GraphQL API** that mirrors them.

The dual API was introduced as an experimental feature in WooCommerce core 10.9, but as of WooCommerce 11.2 its engine has moved to a dedicated plugin, [WooCommerce Dual API](https://github.com/woocommerce/woocommerce-dual-api), which any plugin can use to build its own dual API.

> **This feature is experimental.** Everything under the `Automattic\WooCommerce\Api` namespace can change in backwards-incompatible ways, or be removed, in any release. Do not use it in production extensions.

## Where the documentation lives

The engine and its documentation live in the plugin's repository:

- **Plugin**: [woocommerce/woocommerce-dual-api](https://github.com/woocommerce/woocommerce-dual-api)
- **Documentation**: the [`docs/` directory](https://github.com/woocommerce/woocommerce-dual-api/tree/trunk/docs) of that repository
- **Working example**: [woocommerce/woocommerce-simple-events](https://github.com/woocommerce/woocommerce-simple-events), a runnable reference plugin that exercises the engine end to end

## Requirements

WooCommerce 11.2 or newer on PHP 8.1+, with the WooCommerce Dual API plugin installed and active. There is no feature flag: activating the plugin enables the engine.

WooCommerce 10.9 to 11.1 ship the engine inside core, behind a hidden `dual_code_graphql_api` feature flag (`wp option update woocommerce_feature_dual_code_graphql_api_enabled yes` to enable it). The plugin stays dormant on those versions and the flag remains the switch there.
</file>

<file path="docs/apis/rest-api/v1/_category_.json">
{
	"label": "v1",
	"position": 5
}
</file>

<file path="docs/apis/rest-api/v1/coupons.mdx">
---
sidebar_position: 4
sidebar_label: 'Coupons'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Coupons
The coupons API allows you to create, view, update, and delete individual, or a batch, of coupon codes.

## Coupon properties
|           Attribute           |    Type   |                                                                      Description                                                                      |
|-------------------------------|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id`                          | integer   | Unique identifier for the object. `READ-ONLY`                                                                           |
| `code`                        | string    | Coupon code. `MANDATORY`                                                                                                |
| `date_created`                | date-time | The date the coupon was created, in the site's timezone. `READ-ONLY`                                                    |
| `date_modified`               | date-time | The date the coupon was last modified, in the site's timezone. `READ-ONLY`                                              |
| `description`                 | string    | Coupon description.                                                                                                                                   |
| `discount_type`               | string    | Determines the type of discount that will be applied. Options: `fixed_cart`, `percent`, `fixed_product` and `percent_product`. Default: `fixed_cart`. |
| `amount`                      | string    | The amount of discount.                                                                                                                               |
| `expiry_date`                 | string    | UTC DateTime when the coupon expires.                                                                                                                 |
| `usage_count`                 | integer   | Number of times the coupon has been used already. `READ-ONLY`                                                           |
| `individual_use`              | boolean   | Whether coupon can only be used individually.                                                                                                         |
| `product_ids`                 | array     | List of product ID's the coupon can be used on.                                                                                                       |
| `exclude_product_ids`         | array     | List of product ID's the coupon cannot be used on.                                                                                                    |
| `usage_limit`                 | integer   | How many times the coupon can be used.                                                                                                                |
| `usage_limit_per_user`        | integer   | How many times the coupon can be used per customer.                                                                                                   |
| `limit_usage_to_x_items`      | integer   | Max number of items in the cart the coupon can be applied to.                                                                                         |
| `free_shipping`               | boolean   | Define if can be applied for free shipping.                                                                                                           |
... (986 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/customers.mdx">
---
sidebar_position: 5
sidebar_label: 'Customers'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Customers
The customer API allows you to create, view, update, and delete individual, or a batch, of customers.

## Customer properties
|    Attribute    |    Type   |                                                                                                                                                                            Description                                                                                                                                                                             |
|-----------------|-----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id`            | integer   | Unique identifier for the resource. `READ-ONLY`                                                                                                                                                                                                                                                                                      |
| `date_created`  | date-time | The date the customer was created, in the site's timezone. `READ-ONLY`                                                                                                                                                                                                                                                               |
| `date_modified` | date-time | The date the customer was last modified, in the site's timezone. `READ-ONLY`                                                                                                                                                                                                                                                         |
| `email`         | string    | The email address for the customer. `MANDATORY`                                                                                                                                                                                                                                                                                      |
| `first_name`    | string    | Customer first name.                                                                                                                                                                                                                                                                                                                                               |
| `last_name`     | string    | Customer last name.                                                                                                                                                                                                                                                                                                                                                |
| `username`      | string    | Customer login name. Can be generated automatically from the customer's email address if the option `woocommerce_registration_generate_username` is equal to `yes` `CANNOT BE CHANGED` `MAYBE MANDATORY`                                                                                               |
| `password`      | string    | Customer password. Can be generated automatically with [`wp_generate_password()`](http://codex.wordpress.org/Function_Reference/wp_generate_password) if the "Automatically generate customer password" option is enabled, check the index meta for `generate_password` `WRITE-ONLY` `MAYBE MANDATORY` |
| `last_order`    | array     | Last order data. See [Customer Last Order properties](#customer-last-order-properties). `READ-ONLY`                                                                                                                                                                                                                                  |
| `orders_count`  | integer   | Quantity of orders made by the customer. `READ-ONLY`                                                                                                                                                                                                                                                                                 |
| `total_spent`   | string    | Total amount spent. `READ-ONLY`                                                                                                                                                                                                                                                                                                      |
| `avatar_url`    | string    | Avatar URL.                                                                                                                                                                                                                                                                                                                                                        |
| `billing`       | array     | List of billing address data. See [Billing Address properties](#billing-address-properties).                                                                                                                                                                                                                                                                       |
| `shipping`      | array     | List of shipping address data. See [Shipping Address properties](#shipping-address-properties).                                                                                                                                                                                                                                                                    |

### Customer last order properties
... (1632 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/index.mdx">
---
title: REST API v1
slug: /apis/rest-api/v1
sidebar_position: 0
---

import DocCardList from '@theme/DocCardList';

Legacy version of the WooCommerce REST API. Use `/wp-json/wc/v1/` endpoints. Consider migrating to v3 for new integrations.

<DocCardList />
</file>

<file path="docs/apis/rest-api/v1/order-notes.mdx">
---
sidebar_position: 7
sidebar_label: 'Order notes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Order notes
The order notes API allows you to create, view, and delete individual order notes.  
Order notes are added by administrators and programmatically to store data about an order, or order events.

## Order note properties
|    Attribute    |    Type   |                                                     Description                                                     |
|-----------------|-----------|---------------------------------------------------------------------------------------------------------------------|
| `id`            | integer   | Unique identifier for the resource. `READ-ONLY`                                       |
| `date_created`  | date-time | The date the order note was created, in the site's timezone. `READ-ONLY`              |
| `note`          | string    | Order note. `REQUIRED`                                                                |
| `customer_note` | boolean   | Shows/define if the note is only for reference or for the customer (the user will be notified). Default is `false`. |

## Create an order note
This API helps you to create a new note for an order.

```http
POST /wp-json/wc/v1/orders/<id>/notes
```

<Tabs>
  <TabItem value="curl" label="cURL">

... (367 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/order-refunds.mdx">
---
sidebar_position: 8
sidebar_label: 'Order refunds'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Refunds
The refunds API allows you to create, view, and delete individual refunds.

## Refund properties
|   Attribute    |    Type   |                                               Description                                                |
|----------------|-----------|----------------------------------------------------------------------------------------------------------|
| `id`           | integer   | Unique identifier for the resource. `READ-ONLY`                            |
| `date_created` | date-time | The date the order refund was created, in the site's timezone. `READ-ONLY` |
| `amount`       | string    | Refund amount. `REQUIRED`                                                  |
| `reason`       | string    | Reason for refund.                                                                                       |
| `line_items`   | array     | Line items data. See [Refunds Line Items properties](#refund-line-item-properties).                    |

### Refund line item properties
|   Attribute    |   Type  |                                          Description                                           |
|----------------|---------|------------------------------------------------------------------------------------------------|
| `id`           | integer | Item ID. `READ-ONLY`                                             |
| `name`         | string  | Product name. `READ-ONLY`                                        |
| `sku`          | string  | Product SKU. `READ-ONLY`                                         |
| `product_id`   | integer | Product ID.                                                                                    |
| `variation_id` | integer | Variation ID, if applicable.                                                                   |
| `quantity`     | integer | Quantity ordered.                                                                              |
| `tax_class`    | string  | Tax class of product. `READ-ONLY`                                |
... (430 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/orders.mdx">
---
sidebar_position: 6
sidebar_label: 'Orders'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Orders
The orders API allows you to create, view, update, and delete individual, or a batch, of orders.

## Order properties
|       Attribute        |    Type   |                                                                             Description                                                                              |
|------------------------|-----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id`                   | integer   | Unique identifier for the resource. `READ-ONLY`                                                                                        |
| `parent_id`            | integer   | Parent order ID.                                                                                                                                                     |
| `status`               | string    | Order status. Default is `pending`. Options (plugins may include new status): `pending`, `processing`, `on-hold`, `completed`, `cancelled`, `refunded` and `failed`. |
| `order_key`            | string    | Order key. `READ-ONLY`                                                                                                                 |
| `number`               | string    | Order number. `READ-ONLY`                                                                                                              |
| `currency`             | string    | Currency the order was created with, in ISO format, e.g `USD`. Default is the current store currency.                                                                |
| `version`              | string    | Version of WooCommerce when the order was made. `READ-ONLY`                                                                            |
| `prices_include_tax`   | boolean   | Shows if the prices included tax during checkout. `READ-ONLY`                                                                          |
| `date_created`         | date-time | The date the order was created, in the site's timezone. `READ-ONLY`                                                                    |
| `date_modified`        | date-time | The date the order was last modified, in the site's timezone. `READ-ONLY`                                                              |
| `customer_id`          | integer   | User ID who owns the order. Use `0` for guests. Default is `0`.                                                                                                      |
| `discount_total`       | string    | Total discount amount for the order. `READ-ONLY`                                                                                       |
| `discount_tax`         | string    | Total discount tax amount for the order. `READ-ONLY`                                                                                   |
| `shipping_total`       | string    | Total shipping amount for the order. `READ-ONLY`                                                                                       |
| `shipping_tax`         | string    | Total shipping tax amount for the order. `READ-ONLY`                                                                                   |
| `cart_tax`             | string    | Sum of line item taxes only. `READ-ONLY`                                                                                               |
... (2717 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/product-attribute-terms.mdx">
---
sidebar_position: 12
sidebar_label: 'Product attribute terms'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product attribute terms
The product attribute terms API allows you to create, view, update, and delete individual, or a batch, of attribute terms.

## Attribute term properties
|   Attribute   |   Type  |                                       Description                                        |
|---------------|---------|------------------------------------------------------------------------------------------|
| `id`          | integer | Unique identifier for the resource. `READ-ONLY`            |
| `name`        | string  | Term name. `REQUIRED`                                      |
| `slug`        | string  | An alphanumeric identifier for the resource unique to its type.                          |
| `description` | string  | HTML description of the resource.                                                        |
| `menu_order`  | integer | Menu order, used to custom sort the resource.                                            |
| `count`       | integer | Number of published products for the resource. `READ-ONLY` |

## Create an attribute term
This API helps you to create a new product attribute term.

```http
POST /wp-json/wc/v1/products/attributes/<attribute_id>/terms
```

<Tabs>
  <TabItem value="curl" label="cURL">
... (847 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/product-attributes.mdx">
---
sidebar_position: 11
sidebar_label: 'Product attributes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product attributes
The product attributes API allows you to create, view, update, and delete individual, or a batch, of product attributes.

## Product attribute properties
|   Attribute    |   Type  |                                                Description                                                |
|----------------|---------|-----------------------------------------------------------------------------------------------------------|
| `id`           | integer | Unique identifier for the resource. `READ-ONLY`                             |
| `name`         | string  | Attribute name. `REQUIRED`                                                  |
| `slug`         | string  | An alphanumeric identifier for the resource unique to its type.                                           |
| `type`         | string  | Type of attribute. Default is `select`. Options: `select` and `text` (some plugins can include new types) |
| `order_by`     | string  | Default sort order. Default is `menu_order`. Options: `menu_order`, `name`, `name_num` and `id`.          |
| `has_archives` | boolean | Enable/Disable attribute archives. Default is `false`.                                                    |

## Create a product attribute
This API helps you to create a new product attribute.

```http
POST /wp-json/wc/v1/products/attributes
```

<Tabs>
  <TabItem value="curl" label="cURL">
... (730 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/product-categories.mdx">
---
sidebar_position: 13
sidebar_label: 'Product categories'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product categories
The product categories API allows you to create, view, update, and delete individual, or a batch, of categories.

## Product category properties
|   Attribute   |   Type  |                                                   Description                                                   |
|---------------|---------|-----------------------------------------------------------------------------------------------------------------|
| `id`          | integer | Unique identifier for the resource. `READ-ONLY`                                   |
| `name`        | string  | Category name. `REQUIRED`                                                         |
| `slug`        | string  | An alphanumeric identifier for the resource unique to its type.                                                 |
| `parent`      | integer | The id for the parent of the resource.                                                                          |
| `description` | string  | HTML description of the resource.                                                                               |
| `display`     | string  | Category archive display type. Default is `default`. Options: `default`, `products`, `subcategories` and `both` |
| `image`       | array   | Image data. See [Category Image properties](#category-image-properties)                                         |
| `menu_order`  | integer | Menu order, used to custom sort the resource.                                                                   |
| `count`       | integer | Number of published products for the resource. `READ-ONLY`                        |

### Category Image properties
|    Attribute    |    Type   |                                               Description                                               |
|-----------------|-----------|---------------------------------------------------------------------------------------------------------|
| `id`            | integer   | Image ID (attachment ID). In write-mode used to attach pre-existing images.                             |
| `date_created`  | date-time | The date the image was created, in the site's timezone. `READ-ONLY`       |
| `date_modified` | date-time | The date the image was last modified, in the site's timezone. `READ-ONLY` |
... (990 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/product-shipping-classes.mdx">
---
sidebar_position: 15
sidebar_label: 'Product shipping classes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product shipping classes
The product shipping class API allows you to create, view, update, and delete individual, or a batch, of shipping classes.

## Shipping class properties
|   Attribute   |   Type  |                                       Description                                        |
|---------------|---------|------------------------------------------------------------------------------------------|
| `id`          | integer | Unique identifier for the resource. `READ-ONLY`            |
| `name`        | string  | Shipping class name. `REQUIRED`                            |
| `slug`        | string  | An alphanumeric identifier for the resource unique to its type.                          |
| `description` | string  | HTML description of the resource.                                                        |
| `count`       | integer | Number of published products for the resource. `READ-ONLY` |

## Create a shipping class
This API helps you to create a new product shipping class.

```http
POST /wp-json/wc/v1/products/shipping_classes
```

> Example of how to create a product shipping class:

<Tabs>
... (712 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/product-tags.mdx">
---
sidebar_position: 14
sidebar_label: 'Product tags'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product tags
The product tags API allows you to create, view, update, and delete individual, or a batch, of product tags.

## Product tag properties
|   Attribute   |   Type  |                                       Description                                        |
|---------------|---------|------------------------------------------------------------------------------------------|
| `id`          | integer | Unique identifier for the resource. `READ-ONLY`            |
| `name`        | string  | Tag name. `REQUIRED`                                       |
| `slug`        | string  | An alphanumeric identifier for the resource unique to its type.                          |
| `description` | string  | HTML description of the resource.                                                        |
| `count`       | integer | Number of published products for the resource. `READ-ONLY` |

## Create a product tag
This API helps you to create a new product tag.

```http
POST /wp-json/wc/v1/products/tags
```

> Example of how to create a product tag:

<Tabs>
... (712 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/products.mdx">
---
sidebar_position: 9
sidebar_label: 'Products'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Products
The products API allows you to create, view, update, and delete individual, or a batch, of products.

## Product properties
| Attribute            | Type      | Description                                                                                                                                                                                                                                                                                                                                                   |
|----------------------|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id`                 | integer   | Unique identifier for the resource. `READ-ONLY`                                                                                                                                                                                                                                                                                 |
| `name`               | string    | Product name.                                                                                                                                                                                                                                                                                                                                                 |
| `slug`               | string    | Product slug.                                                                                                                                                                                                                                                                                                                                                 |
| `permalink`          | string    | Product URL. `READ-ONLY`                                                                                                                                                                                                                                                                                                        |
| `date_created`       | date-time | The date the product was created, in the site's timezone. `READ-ONLY`                                                                                                                                                                                                                                                           |
| `date_modified`      | date-time | The date the product was last modified, in the site's timezone. `READ-ONLY`                                                                                                                                                                                                                                                     |
| `type`               | string    | Product type. Default is `simple`. Options (plugins may add new options): `simple`, `grouped`, `external`, `variable`.                                                                                                                                                                                                                                        |
| `status`             | string    | Product status (post status). Default is `publish`. Options (plugins may add new options): `draft`, `pending`, `private` and `publish`.                                                                                                                                                                                                                       |
| `featured`           | boolean   | Featured product. Default is `false`.                                                                                                                                                                                                                                                                                                                         |
| `catalog_visibility` | string    | Catalog visibility. Default is `visible`. Options: `visible` (Catalog and search), `catalog` (Only in catalog), `search` (Only in search) and `hidden` (Hidden from all).                                                                                                                                                                                     |
| `description`        | string    | Product description.                                                                                                                                                                                                                                                                                                                                          |
| `short_description`  | string    | Product short description.                                                                                                                                                                                                                                                                                                                                    |
| `sku`                | string    | Unique identifier.                                                                                                                                                                                                                                                                                                                                            |
| `price`              | string    | Current product price. This is set from `regular_price` and `sale_price`. `READ-ONLY`                                                                                                                                                                                                                                        |
| `regular_price`      | string    | Product regular price.                                                                                                                                                                                                                                                                                                                                        |
| `sale_price`         | string    | Product sale price.                                                                                                                                                                                                                                                                                                                                           |
... (3579 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/reports.mdx">
---
sidebar_position: 16
sidebar_label: 'Reports'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Reports
The reports API allows you to view all types of reports available.

## List all reports
This API lets you retrieve and view a simple list of available reports.

```http
GET /wp-json/wc/v1/reports
```

<Tabs>
  <TabItem value="curl" label="cURL">

```shell
curl https://example.com/wp-json/wc/v1/reports \
	-u consumer_key:consumer_secret
```

  </TabItem>
  <TabItem value="js" label="JavaScript">

```javascript
... (332 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/tax-classes.mdx">
---
sidebar_position: 18
sidebar_label: 'Tax classes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Tax classes
The tax classes API allows you to create, view, and delete individual tax classes.

## Tax class properties
| Attribute |  Type  |                                  Description                                  |
|-----------|--------|-------------------------------------------------------------------------------|
| `slug`    | string | Unique identifier for the resource. `READ-ONLY` |
| `name`    | string | Tax class name. `REQUIRED`                      |

## Create a tax class
This API helps you to create a new tax class.

```http
POST /wp-json/wc/v1/taxes/classes
```

<Tabs>
  <TabItem value="curl" label="cURL">

```shell
curl -X POST https://example.com/wp-json/wc/v1/taxes/classes \
    -u consumer_key:consumer_secret \
... (251 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/taxes.mdx">
---
sidebar_position: 17
sidebar_label: 'Taxes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Tax rates
The taxes API allows you to create, view, update, and delete individual tax rates, or a batch of tax rates.

## Tax rate properties
| Attribute  |   Type  |                                                                                   Description                                                                                   |
|------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id`       | integer | Unique identifier for the resource. `READ-ONLY`                                                                                                   |
| `country`  | string  | Country ISO 3166 code. See [ISO 3166 Codes (Countries)](http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html) for more details                                              |
| `state`    | string  | State code.                                                                                                                                                                     |
| `postcode` | string  | Postcode/ZIP.                                                                                                                                                                   |
| `city`     | string  | City name.                                                                                                                                                                      |
| `rate`     | string  | Tax rate.                                                                                                                                                                       |
| `name`     | string  | Tax rate name.                                                                                                                                                                  |
| `priority` | integer | Tax priority. Only 1 matching rate per priority will be used. To define multiple tax rates for a single area you need to specify a different priority per rate. Default is `1`. |
| `compound` | boolean | Whether or not this is a compound rate. Compound tax rates are applied on top of other tax rates. Default is `false`.                                                           |
| `shipping` | boolean | Whether or not this tax rate also gets applied to shipping. Default is `true`.                                                                                                  |
| `order`    | integer | Indicates the order that will appear in queries.                                                                                                                                |
| `class`    | string  | Tax class. Default is `standard`.                                                                                                                                               |

## Create a tax rate
This API helps you to create a new tax rate.

... (3998 lines truncated)
</file>

<file path="docs/apis/rest-api/v1/webhooks.mdx">
---
sidebar_position: 19
sidebar_label: 'Webhooks'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Webhooks
The webhooks API allows you to create, view, update, and delete individual, or a batch, of webhooks.

Webhooks can be managed via the WooCommerce settings screen or by using the REST API endpoints. The `WC_Webhook` class manages all data storage and retrieval of the webhook custom post type, as well as enqueuing webhook actions and processing/delivering/logging webhooks. On `woocommerce_init`, active webhooks are loaded.

Each webhook has:

* `status`: active (delivers payload), paused (delivery paused by admin), disabled (delivery paused by failure).
* `topic`: determines which resource events the webhook is triggered for.
* `delivery URL`: URL where the payload is delivered, must be HTTP or HTTPS.
* `secret`: an optional secret key that is used to generate a HMAC-SHA256 hash of the request body so the receiver can verify authenticity of the webhook.
* `hooks`: an array of hook names that are added and bound to the webhook for processing.

### Topics
The topic is a combination resource (e.g. order) and event (e.g. created) and maps to one or more hook names (e.g. `woocommerce_checkout_order_processed`). Webhooks can be created using the topic name and the appropriate hooks are automatically added.

Core topics are:

* Coupons: `coupon.created`, `coupon.updated` and `coupon.deleted`.
* Customers: `customer.created`, `customer.updated` and `customer.deleted`.
* Orders: `order.created`, `order.updated` and `order.deleted`.
* Products: `product.created`, `product.updated` and `product.deleted`.
... (1126 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/_category_.json">
{
	"label": "v2",
	"position": 4
}
</file>

<file path="docs/apis/rest-api/v2/coupons.mdx">
---
sidebar_position: 4
sidebar_label: 'Coupons'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Coupons
The coupons API allows you to create, view, update, and delete individual, or a batch, of coupon codes.

## Coupon properties
| Attribute                     | Type      | Description                                                                                                                          |
| ----------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `id`                          | integer   | Unique identifier for the object. `READ-ONLY`                                                          |
| `code`                        | string    | Coupon code. `MANDATORY`                                                                               |
| `amount`                      | string    | The amount of discount. Should always be numeric, even if setting a percentage.                                                      |
| `date_created`                | date-time | The date the coupon was created, in the site's timezone. `READ-ONLY`                                   |
| `date_created_gmt`            | date-time | The date the coupon was created, as GMT. `READ-ONLY`                                                   |
| `date_modified`               | date-time | The date the coupon was last modified, in the site's timezone. `READ-ONLY`                             |
| `date_modified_gmt`           | date-time | The date the coupon was last modified, as GMT. `READ-ONLY`                                             |
| `discount_type`               | string    | Determines the type of discount that will be applied. Options: `percent`, `fixed_cart` and `fixed_product`. Default is `fixed_cart`. |
| `description`                 | string    | Coupon description.                                                                                                                  |
| `date_expires`                | string    | The date the coupon expires, in the site's timezone.                                                                                 |
| `date_expires_gmt`            | string    | The date the coupon expires, as GMT.                                                                                                 |
| `usage_count`                 | integer   | Number of times the coupon has been used already. `READ-ONLY`                                          |
| `individual_use`              | boolean   | If true, the coupon can only be used individually. Other applied coupons will be removed from the cart. Default is `false`.          |
| `product_ids`                 | array     | List of product IDs the coupon can be used on.                                                                                       |
| `excluded_product_ids`        | array     | List of product IDs the coupon cannot be used on.                                                                                    |
| `usage_limit`                 | integer   | How many times the coupon can be used in total.                                                                                      |
... (1036 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/customers.mdx">
---
sidebar_position: 5
sidebar_label: 'Customers'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Customers
The customer API allows you to create, view, update, and delete individual, or a batch, of customers.

## Customer properties
| Attribute            | Type      | Description                                                                                                |
| -------------------- | --------- | ---------------------------------------------------------------------------------------------------------- |
| `id`                 | integer   | Unique identifier for the resource. `READ-ONLY`                              |
| `date_created`       | date-time | The date the customer was created, in the site's timezone. `READ-ONLY`       |
| `date_created_gmt`   | date-time | The date the customer was created, as GMT. `READ-ONLY`                       |
| `date_modified`      | date-time | The date the customer was last modified, in the site's timezone. `READ-ONLY` |
| `date_modified_gmt`  | date-time | The date the customer was last modified, as GMT. `READ-ONLY`                 |
| `email`              | string    | The email address for the customer. `MANDATORY`                              |
| `first_name`         | string    | Customer first name.                                                                                       |
| `last_name`          | string    | Customer last name.                                                                                        |
| `role`               | string    | Customer role. `READ-ONLY`                                                   |
| `username`           | string    | Customer login name.                                                                                       |
| `password`           | string    | Customer password. `WRITE-ONLY`                                              |
| `billing`            | object    | List of billing address data. See [Customer - Billing properties](#customer---billing-properties)            |
| `shipping`           | object    | List of shipping address data. See [Customer - Shipping properties](#customer---shipping-properties)         |
| `is_paying_customer` | bool      | Is the customer a paying customer? `READ-ONLY`                               |
| `orders_count`       | integer   | Quantity of orders made by the customer. `READ-ONLY`                         |
| `total_spent`        | string    | Total amount spent. `READ-ONLY`                                              |
... (1658 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/index.mdx">
---
title: REST API v2
slug: /apis/rest-api/v2
sidebar_position: 0
---

import DocCardList from '@theme/DocCardList';

Legacy version of the WooCommerce REST API. Use `/wp-json/wc/v2/` endpoints. Consider migrating to v3 for new integrations.

<DocCardList />
</file>

<file path="docs/apis/rest-api/v2/order-notes.mdx">
---
sidebar_position: 7
sidebar_label: 'Order notes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Order notes
The order notes API allows you to create, view, and delete individual order notes.  
Order notes are added by administrators and programmatically to store data about an order, or order events.

## Order note properties
| Attribute          | Type      | Description                                                                                                                                      |
| ------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`               | integer   | Unique identifier for the resource. `READ-ONLY`                                                                    |
| `date_created`     | date-time | The date the order note was created, in the site's timezone. `READ-ONLY`                                           |
| `date_created_gmt` | date-time | The date the order note was created, as GMT. `READ-ONLY`                                                           |
| `note`             | string    | Order note content. `MANDATORY`                                                                                    |
| `customer_note`    | boolean   | If true, the note will be shown to customers and they will be notified. If false, the note will be for admin reference only. Default is `false`. |

## Create an order note
This API helps you to create a new note for an order.

```http
POST /wp-json/wc/v2/orders/<id>/notes
```

<Tabs>
  <TabItem value="curl" label="cURL">
... (403 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/order-refunds.mdx">
---
sidebar_position: 8
sidebar_label: 'Order refunds'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Refunds
The refunds API allows you to create, view, and delete individual refunds.

## Order refund properties
| Attribute          | Type      | Description                                                                                                                      |
|--------------------|-----------|----------------------------------------------------------------------------------------------------------------------------------|
| `id`               | integer   | Unique identifier for the resource. `READ-ONLY`                                                    |
| `date_created`     | date-time | The date the order refund was created, in the site's timezone. `READ-ONLY`                         |
| `date_created_gmt` | date-time | The date the order refund was created, as GMT. `READ-ONLY`                                         |
| `amount`           | string    | Refund amount.                                                                                                                   |
| `reason`           | string    | Reason for refund.                                                                                                               |
| `refunded_by`      | integer   | User ID of user who created the refund.                                                                                          |
| `meta_data`        | array     | Meta data. See [Order refund - Meta data properties](#order-refund---meta-data-properties)                                         |
| `line_items`       | array     | Line items data. See [Order refund - Line items properties](#order-refund---line-items-properties)                                 |
| `api_refund`       | boolean   | When true, the payment gateway API is used to generate the refund. Default is `true`. `WRITE-ONLY` |

### Order refund - Meta data properties
| Attribute | Type    | Description                                        |
|-----------|---------|----------------------------------------------------|
| `id`      | integer | Meta ID. `READ-ONLY` |
| `key`     | string  | Meta key.                                          |
| `value`   | string  | Meta value.                                        |
... (468 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/orders.mdx">
---
sidebar_position: 6
sidebar_label: 'Orders'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Orders
The orders API allows you to create, view, update, and delete individual, or a batch, of orders.

## Order properties
| Attribute              | Type      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
|------------------------|-----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id`                   | integer   | Unique identifier for the resource. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `parent_id`            | integer   | Parent order ID.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `number`               | string    | Order number. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `order_key`            | string    | Order key. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `created_via`          | string    | Shows where the order was created. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `version`              | string    | Version of WooCommerce which last updated the order. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `status`               | string    | Order status. Options: `pending`, `processing`, `on-hold`, `completed`, `cancelled`, `refunded`, `failed` and `trash`. Default is `pending`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `currency`             | string    | Currency the order was created with, in ISO format. Options: `AED`, `AFN`, `ALL`, `AMD`, `ANG`, `AOA`, `ARS`, `AUD`, `AWG`, `AZN`, `BAM`, `BBD`, `BDT`, `BGN`, `BHD`, `BIF`, `BMD`, `BND`, `BOB`, `BRL`, `BSD`, `BTC`, `BTN`, `BWP`, `BYR`, `BZD`, `CAD`, `CDF`, `CHF`, `CLP`, `CNY`, `COP`, `CRC`, `CUC`, `CUP`, `CVE`, `CZK`, `DJF`, `DKK`, `DOP`, `DZD`, `EGP`, `ERN`, `ETB`, `EUR`, `FJD`, `FKP`, `GBP`, `GEL`, `GGP`, `GHS`, `GIP`, `GMD`, `GNF`, `GTQ`, `GYD`, `HKD`, `HNL`, `HRK`, `HTG`, `HUF`, `IDR`, `ILS`, `IMP`, `INR`, `IQD`, `IRR`, `IRT`, `ISK`, `JEP`, `JMD`, `JOD`, `JPY`, `KES`, `KGS`, `KHR`, `KMF`, `KPW`, `KRW`, `KWD`, `KYD`, `KZT`, `LAK`, `LBP`, `LKR`, `LRD`, `LSL`, `LYD`, `MAD`, `MDL`, `MGA`, `MKD`, `MMK`, `MNT`, `MOP`, `MRO`, `MUR`, `MVR`, `MWK`, `MXN`, `MYR`, `MZN`, `NAD`, `NGN`, `NIO`, `NOK`, `NPR`, `NZD`, `OMR`, `PAB`, `PEN`, `PGK`, `PHP`, `PKR`, `PLN`, `PRB`, `PYG`, `QAR`, `RON`, `RSD`, `RUB`, `RWF`, `SAR`, `SBD`, `SCR`, `SDG`, `SEK`, `SGD`, `SHP`, `SLL`, `SOS`, `SRD`, `SSP`, `STD`, `SYP`, `SZL`, `THB`, `TJS`, `TMT`, `TND`, `TOP`, `TRY`, `TTD`, `TWD`, `TZS`, `UAH`, `UGX`, `USD`, `UYU`, `UZS`, `VEF`, `VND`, `VUV`, `WST`, `XAF`, `XCD`, `XOF`, `XPF`, `YER`, `ZAR` and `ZMW`. Default is `USD`. |
| `date_created`         | date-time | The date the order was created, in the site's timezone. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `date_created_gmt`     | date-time | The date the order was created, as GMT. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `date_modified`        | date-time | The date the order was last modified, in the site's timezone. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `date_modified_gmt`    | date-time | The date the order was last modified, as GMT. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `discount_total`       | string    | Total discount amount for the order. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `discount_tax`         | string    | Total discount tax amount for the order. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `shipping_total`       | string    | Total shipping amount for the order. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `shipping_tax`         | string    | Total shipping tax amount for the order. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
... (2962 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/payment-gateways.mdx">
---
sidebar_position: 20
sidebar_label: 'Payment gateways'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Payment gateways
The payment gateways API allows you to view, and update individual payment gateways. Results are not paginated - all gateways will be returned.

## Payment gateway properties
| Attribute            | Type    | Description                                                                                                 |
| -------------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| `id`                 | string  | Payment gateway ID. `READ-ONLY`                                               |
| `title`              | string  | Payment gateway title on checkout.                                                                          |
| `description`        | string  | Payment gateway description on checkout.                                                                    |
| `order`              | integer | Payment gateway sort order.                                                                                 |
| `enabled`            | boolean | Payment gateway enabled status.                                                                             |
| `method_title`       | string  | Payment gateway method title. `READ-ONLY`                                     |
| `method_description` | string  | Payment gateway method description. `READ-ONLY`                               |
| `settings`           | object  | Payment gateway settings. See [Payment gateway - Settings properties](#payment-gateway---settings-properties) |

### Payment gateway - Settings properties
| Attribute     | Type   | Description                                                                                                                                                                                     |
| ------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`          | string | A unique identifier for the setting. `READ-ONLY`                                                                                                                  |
| `label`       | string | A human readable label for the setting used in interfaces. `READ-ONLY`                                                                                            |
| `description` | string | A human readable description for the setting used in interfaces. `READ-ONLY`                                                                                      |
| `type`        | string | Type of setting. Options: `text`, `email`, `number`, `color`, `password`, `textarea`, `select`, `multiselect`, `radio`, `image_width` and `checkbox`. `READ-ONLY` |
... (620 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/product-attribute-terms.mdx">
---
sidebar_position: 12
sidebar_label: 'Product attribute terms'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product attribute terms
The product attribute terms API allows you to create, view, update, and delete individual, or a batch, of attribute terms.

## Product attribute term properties
| Attribute     | Type    | Description                                                                              |
| ------------- | ------- | ---------------------------------------------------------------------------------------- |
| `id`          | integer | Unique identifier for the resource. `READ-ONLY`            |
| `name`        | string  | Term name. `MANDATORY`                                     |
| `slug`        | string  | An alphanumeric identifier for the resource unique to its type.                          |
| `description` | string  | HTML description of the resource.                                                        |
| `menu_order`  | integer | Menu order, used to custom sort the resource.                                            |
| `count`       | integer | Number of published products for the resource. `READ-ONLY` |

## Create an attribute term
This API helps you to create a new product attribute term.

```http
POST /wp-json/wc/v2/products/attributes/<attribute_id>/terms
```

<Tabs>
  <TabItem value="curl" label="cURL">
... (847 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/product-attributes.mdx">
---
sidebar_position: 11
sidebar_label: 'Product attributes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product attributes
The product attributes API allows you to create, view, update, and delete individual, or a batch, of product attributes.

## Product attribute properties
| Attribute      | Type    | Description                                                                                      |
| -------------- | ------- | ------------------------------------------------------------------------------------------------ |
| `id`           | integer | Unique identifier for the resource. `READ-ONLY`                    |
| `name`         | string  | Attribute name. `MANDATORY`                                        |
| `slug`         | string  | An alphanumeric identifier for the resource unique to its type.                                  |
| `type`         | string  | Type of attribute. By default only `select` is supported.                           |
| `order_by`     | string  | Default sort order. Options: `menu_order`, `name`, `name_num` and `id`. Default is `menu_order`. |
| `has_archives` | boolean | Enable/Disable attribute archives. Default is `false`.                                           |

## Create a product attribute
This API helps you to create a new product attribute.

```http
POST /wp-json/wc/v2/products/attributes
```

<Tabs>
  <TabItem value="curl" label="cURL">
... (735 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/product-categories.mdx">
---
sidebar_position: 13
sidebar_label: 'Product categories'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product categories
The product categories API allows you to create, view, update, and delete individual, or a batch, of categories.

## Product category properties
| Attribute     | Type    | Description                                                                                                      |
| ------------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
| `id`          | integer | Unique identifier for the resource. `READ-ONLY`                                    |
| `name`        | string  | Category name. `MANDATORY`                                                         |
| `slug`        | string  | An alphanumeric identifier for the resource unique to its type.                                                  |
| `parent`      | integer | The ID for the parent of the resource.                                                                           |
| `description` | string  | HTML description of the resource.                                                                                |
| `display`     | string  | Category archive display type. Options: `default`, `products`, `subcategories` and `both`. Default is `default`. |
| `image`       | object  | Image data. See [Product category - Image properties](#product-category---image-properties)                        |
| `menu_order`  | integer | Menu order, used to custom sort the resource.                                                                    |
| `count`       | integer | Number of published products for the resource. `READ-ONLY`                         |

### Product category - Image properties
| Attribute           | Type      | Description                                                                                             |
| ------------------- | --------- | ------------------------------------------------------------------------------------------------------- |
| `id`                | integer   | Image ID.                                                                                               |
| `date_created`      | date-time | The date the image was created, in the site's timezone. `READ-ONLY`       |
| `date_created_gmt`  | date-time | The date the image was created, as GMT `READ-ONLY`                        |
... (1002 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/product-shipping-classes.mdx">
---
sidebar_position: 15
sidebar_label: 'Product shipping classes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product shipping classes
The product shipping class API allows you to create, view, update, and delete individual, or a batch, of shipping classes.

## Product shipping class properties
| Attribute     | Type    | Description                                                                              |
| ------------- | ------- | ---------------------------------------------------------------------------------------- |
| `id`          | integer | Unique identifier for the resource. `READ-ONLY`            |
| `name`        | string  | Shipping class name. `MANDATORY`                           |
| `slug`        | string  | An alphanumeric identifier for the resource unique to its type.                          |
| `description` | string  | HTML description of the resource.                                                        |
| `count`       | integer | Number of published products for the resource. `READ-ONLY` |

## Create a shipping class
This API helps you to create a new product shipping class.

```http
POST /wp-json/wc/v2/products/shipping_classes
```

> Example of how to create a product shipping class:

<Tabs>
... (713 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/product-tags.mdx">
---
sidebar_position: 14
sidebar_label: 'Product tags'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product tags
The product tags API allows you to create, view, update, and delete individual, or a batch, of product tags.

## Product tag properties
| Attribute     | Type    | Description                                                                              |
| ------------- | ------- | ---------------------------------------------------------------------------------------- |
| `id`          | integer | Unique identifier for the resource. `READ-ONLY`            |
| `name`        | string  | Tag name. `MANDATORY`                                      |
| `slug`        | string  | An alphanumeric identifier for the resource unique to its type.                          |
| `description` | string  | HTML description of the resource.                                                        |
| `count`       | integer | Number of published products for the resource. `READ-ONLY` |

## Create a product tag
This API helps you to create a new product tag.

```http
POST /wp-json/wc/v2/products/tags
```

> Example of how to create a product tag:

<Tabs>
... (713 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/product-variations.mdx">
---
sidebar_position: 10
sidebar_label: 'Product variations'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product variations
The product variations API allows you to create, view, update, and delete individual, or a batch, of product variations.

## Product variation properties
| Attribute               | Type      | Description                                                                                                         |
|-------------------------|-----------|---------------------------------------------------------------------------------------------------------------------|
| `id`                    | integer   | Unique identifier for the resource. `READ-ONLY`                                       |
| `date_created`          | date-time | The date the variation was created, in the site's timezone. `READ-ONLY`               |
| `date_created_gmt`      | date-time | The date the variation was created, as GMT. `READ-ONLY`                               |
| `date_modified`         | date-time | The date the variation was last modified, in the site's timezone. `READ-ONLY`         |
| `date_modified_gmt`     | date-time | The date the variation was last modified, as GMT. `READ-ONLY`                         |
| `description`           | string    | Variation description.                                                                                              |
| `permalink`             | string    | Variation URL. `READ-ONLY`                                                            |
| `sku`                   | string    | Unique identifier.                                                                                                  |
| `price`                 | string    | Current variation price. `READ-ONLY`                                                  |
| `regular_price`         | string    | Variation regular price.                                                                                            |
| `sale_price`            | string    | Variation sale price.                                                                                               |
| `date_on_sale_from`     | date-time | Start date of sale price, in the site's timezone.                                                                   |
| `date_on_sale_from_gmt` | date-time | Start date of sale price, as GMT.                                                                                   |
| `date_on_sale_to`       | date-time | End date of sale price, in the site's timezone.                                                                     |
| `date_on_sale_to_gmt`   | date-time | End date of sale price, as GMT.                                                                                     |
| `on_sale`               | boolean   | Shows if the variation is on sale. `READ-ONLY`                                        |
... (1499 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/products.mdx">
---
sidebar_position: 9
sidebar_label: 'Products'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Products
The products API allows you to create, view, update, and delete individual, or a batch, of products.

## Product properties
| Attribute               | Type      | Description                                                                                                          |       |                                                                               |
|-------------------------|-----------|----------------------------------------------------------------------------------------------------------------------|-------|-------------------------------------------------------------------------------|
| `id`                    | integer   | Unique identifier for the resource. `READ-ONLY`                                        |       |                                                                               |
| `name`                  | string    | Product name.                                                                                                        |       |                                                                               |
| `slug`                  | string    | Product slug.                                                                                                        |       |                                                                               |
| `permalink`             | string    | Product URL. `READ-ONLY`                                                               |       |                                                                               |
| `date_created`          | date-time | The date the product was created, in the site's timezone. `READ-ONLY`                  |       |                                                                               |
| `date_created_gmt`      | date-time | The date the product was created, as GMT. `READ-ONLY`                                  |       |                                                                               |
| `date_modified`         | date-time | The date the product was last modified, in the site's timezone. `READ-ONLY`            |       |                                                                               |
| `date_modified_gmt`     | date-time | The date the product was last modified, as GMT. `READ-ONLY`                            |       |                                                                               |
| `type`                  | string    | Product type. Options: `simple`, `grouped`, `external` and `variable`. Default is `simple`.                          |       |                                                                               |
| `status`                | string    | Product status (post status). Options: `draft`, `pending`, `private` and `publish`. Default is `publish`.            |       |                                                                               |
| `featured`              | boolean   | Featured product. Default is `false`.                                                                                |       |                                                                               |
| `catalog_visibility`    | string    | Catalog visibility. Options: `visible`, `catalog`, `search` and `hidden`. Default is `visible`.                      |       |                                                                               |
| `description`           | string    | Product description.                                                                                                 |       |                                                                               |
| `short_description`     | string    | Product short description.                                                                                           |       |                                                                               |
| `sku`                   | string    | Unique identifier.                                                                                                   |       |                                                                               |
| `price`                 | string    | Current product price. `READ-ONLY`                                                     |       |                                                                               |
... (3194 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/reports.mdx">
---
sidebar_position: 16
sidebar_label: 'Reports'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Reports
The reports API allows you to view all types of reports available.

## List all reports
This API lets you retrieve and view a simple list of available reports.

```http
GET /wp-json/wc/v2/reports
```

<Tabs>
  <TabItem value="curl" label="cURL">

```shell
curl https://example.com/wp-json/wc/v2/reports \
	-u consumer_key:consumer_secret
```

  </TabItem>
  <TabItem value="js" label="JavaScript">

```javascript
... (332 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/setting-options.mdx">
---
sidebar_position: 26
sidebar_label: 'Setting options'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Setting options
## Setting option properties
| Attribute     | Type   | Description                                                                                                                                                                                     |
| ------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`          | string | A unique identifier for the setting. `READ-ONLY`                                                                                                                  |
| `label`       | string | A human readable label for the setting used in interfaces. `READ-ONLY`                                                                                            |
| `description` | string | A human readable description for the setting used in interfaces. `READ-ONLY`                                                                                      |
| `value`       | mixed  | Setting value.                                                                                                                                                                                  |
| `default`     | mixed  | Default value for the setting. `READ-ONLY`                                                                                                                        |
| `tip`         | string | Additional help text shown to the user about the setting. `READ-ONLY`                                                                                             |
| `placeholder` | string | Placeholder text to be displayed in text inputs. `READ-ONLY`                                                                                                      |
| `type`        | string | Type of setting. Options: `text`, `email`, `number`, `color`, `password`, `textarea`, `select`, `multiselect`, `radio`, `image_width` and `checkbox`. `READ-ONLY` |
| `options`     | object | Array of options (key value pairs) for inputs such as select, multiselect, and radio buttons. `READ-ONLY`                                                         |

## Retrieve an setting option
This API lets you retrieve and view a specific setting option.

```http
GET /wp-json/wc/v2/settings/<group_id>/<id>
```

<Tabs>
... (1912 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/settings.mdx">
---
sidebar_position: 25
sidebar_label: 'Settings'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Settings
The settings API allows you to view all groups of settings available.

## Setting group properties
| Attribute     | Type   | Description                                                                                                |
| ------------- | ------ | ---------------------------------------------------------------------------------------------------------- |
| `id`          | string | A unique identifier that can be used to link settings together. `READ-ONLY`  |
| `label`       | string | A human readable label for the setting used in interfaces. `READ-ONLY`       |
| `description` | string | A human readable description for the setting used in interfaces. `READ-ONLY` |
| `parent_id`   | string | ID of parent grouping. `READ-ONLY`                                           |
| `sub_groups`  | string | IDs for settings sub groups. `READ-ONLY`                                     |

## List all settings groups
This API helps you to view all the settings groups.

```http
GET /wp-json/wc/v2/settings
```

<Tabs>
  <TabItem value="curl" label="cURL">

... (342 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/shipping-methods.mdx">
---
sidebar_position: 24
sidebar_label: 'Shipping methods'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Shipping methods
The shipping methods API allows you to view individual shipping methods.

## Shipping method properties
| Attribute     | Type   | Description                                                            |
| ------------- | ------ | ---------------------------------------------------------------------- |
| `id`          | string | Method ID. `READ-ONLY`                   |
| `title`       | string | Shipping method title. `READ-ONLY`       |
| `description` | string | Shipping method description. `READ-ONLY` |

## Retrieve a shipping method
This API lets you retrieve and view a specific shipping method.

```http
GET /wp-json/wc/v2/shipping_methods/<id>
```

<Tabs>
  <TabItem value="curl" label="cURL">

```shell
curl https://example.com/wp-json/wc/v2/shipping_methods/flat_rate \
... (174 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/shipping-zone-locations.mdx">
---
sidebar_position: 22
sidebar_label: 'Shipping zone locations'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Shipping zone locations
The shipping zone locations API allows you to view and batch update locations of a shipping zone.

## Shipping location properties
| Attribute | Type   | Description                                                                                                 |
| --------- | ------ | ----------------------------------------------------------------------------------------------------------- |
| `code`    | string | Shipping zone location code.                                                                                |
| `type`    | string | Shipping zone location type. Options: `postcode`, `state`, `country` and `continent`. Default is `country`. |

## List all locations of a shipping zone
This API helps you to view all the locations of a shipping zone.

```http
GET /wp-json/wc/v2/shipping/zones/<id>/locations
```

<Tabs>
  <TabItem value="curl" label="cURL">

```shell
curl https://example.com/wp-json/wc/v2/shipping/zones/5/locations \
	-u consumer_key:consumer_secret
... (212 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/shipping-zone-methods.mdx">
---
sidebar_position: 23
sidebar_label: 'Shipping zone methods'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Shipping zone methods
The shipping zone methods API allows you to create, view, update, and delete individual methods of a shipping zone.

## Shipping method properties
| Attribute            | Type    | Description                                                                                                 |
| -------------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| `instance_id`        | integer | Shipping method instance ID. `READ-ONLY`                                      |
| `title`              | string  | Shipping method customer facing title. `READ-ONLY`                            |
| `order`              | integer | Shipping method sort order.                                                                                 |
| `enabled`            | boolean | Shipping method enabled status.                                                                             |
| `method_id`          | string  | Shipping method ID. `READ-ONLY` `MANDATORY`     |
| `method_title`       | string  | Shipping method title. `READ-ONLY`                                            |
| `method_description` | string  | Shipping method description. `READ-ONLY`                                      |
| `settings`           | object  | Shipping method settings. See [Shipping method - Settings properties](#shipping-method---settings-properties) |

### Shipping method - Settings properties
| Attribute     | Type   | Description                                                                                                                                                                                     |
| ------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`          | string | A unique identifier for the setting. `READ-ONLY`                                                                                                                  |
| `label`       | string | A human readable label for the setting used in interfaces. `READ-ONLY`                                                                                            |
| `description` | string | A human readable description for the setting used in interfaces. `READ-ONLY`                                                                                      |
| `type`        | string | Type of setting. Options: `text`, `email`, `number`, `color`, `password`, `textarea`, `select`, `multiselect`, `radio`, `image_width` and `checkbox`. `READ-ONLY` |
... (1003 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/shipping-zones.mdx">
---
sidebar_position: 21
sidebar_label: 'Shipping zones'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Shipping zones
The shipping zones API allows you to create, view, update, and delete individual shipping zones.

## Shipping zone properties
| Attribute | Type    | Description                                                                   |
| --------- | ------- | ----------------------------------------------------------------------------- |
| `id`      | integer | Unique identifier for the resource. `READ-ONLY` |
| `name`    | string  | Shipping zone name. `MANDATORY`                 |
| `order`   | integer | Shipping zone order.                                                          |

## Create a shipping zone
This API helps you to create a new shipping zone.

```http
POST /wp-json/wc/v2/shipping/zones
```

<Tabs>
  <TabItem value="curl" label="cURL">

```shell
curl -X POST https://example.com/wp-json/wc/v2/shipping/zones \
... (463 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/system-status-tools.mdx">
---
sidebar_position: 28
sidebar_label: 'System status tools'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# System status tools
The system status tools API allows you to view and run tools from system status.

## System status tool properties
| Attribute     | Type    | Description                                                                                                         |
| ------------- | ------- | ------------------------------------------------------------------------------------------------------------------- |
| `id`          | string  | A unique identifier for the tool. `READ-ONLY`                                         |
| `name`        | string  | Tool name. `READ-ONLY`                                                                |
| `action`      | string  | What running the tool will do. `READ-ONLY`                                            |
| `description` | string  | Tool description. `READ-ONLY`                                                         |
| `success`     | boolean | Did the tool run successfully? `READ-ONLY` `WRITE-ONLY` |
| `message`     | string  | Tool return message. `READ-ONLY` `WRITE-ONLY`           |
| `confirm`     | boolean | Confirm execution of the tool. Default is `false`. `WRITE-ONLY`                       |

## Retrieve a tool from system status
This API lets you retrieve and view a specific tool from system status by ID.

```http
GET /wp-json/wc/v2/system_status/tools/<id>
```

<Tabs>
... (534 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/system-status.mdx">
---
sidebar_position: 27
sidebar_label: 'System status'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# System status
The system status API allows you to view all system status items.

## System status properties
| Attribute        | Type   | Description                                                                                                                                |
| ---------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `environment`    | object | Environment. See [System status - Environment properties](#system-status---environment-properties) `READ-ONLY` |
| `database`       | object | Database. See [System status - Database properties](#system-status---database-properties) `READ-ONLY`          |
| `active_plugins` | array  | Active plugins. `READ-ONLY`                                                                                  |
| `theme`          | object | Theme. See [System status - Theme properties](#system-status---theme-properties) `READ-ONLY`                   |
| `settings`       | object | Settings. See [System status - Settings properties](#system-status---settings-properties) `READ-ONLY`          |
| `security`       | object | Security. See [System status - Security properties](#system-status---security-properties) `READ-ONLY`          |
| `pages`          | array  | WooCommerce pages. `READ-ONLY`                                                                               |

### System status - Environment properties
| Attribute                   | Type    | Description                                                                |
| --------------------------- | ------- | -------------------------------------------------------------------------- |
| `home_url`                  | string  | Home URL. `READ-ONLY`                        |
| `site_url`                  | string  | Site URL. `READ-ONLY`                        |
| `wc_version`                | string  | WooCommerce version. `READ-ONLY`             |
| `log_directory`             | string  | Log directory. `READ-ONLY`                   |
| `log_directory_writable`    | boolean | Is log directory writable? `READ-ONLY`       |
... (274 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/tax-classes.mdx">
---
sidebar_position: 18
sidebar_label: 'Tax classes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Tax classes
The tax classes API allows you to create, view, and delete individual tax classes.

## Tax class properties
| Attribute |  Type  |                                  Description                                  |
|-----------|--------|-------------------------------------------------------------------------------|
| `slug`    | string | Unique identifier for the resource. `READ-ONLY` |
| `name`    | string | Tax class name. `REQUIRED`                      |

## Create a tax class
This API helps you to create a new tax class.

```http
POST /wp-json/wc/v2/taxes/classes
```

<Tabs>
  <TabItem value="curl" label="cURL">

```shell
curl -X POST https://example.com/wp-json/wc/v2/taxes/classes \
    -u consumer_key:consumer_secret \
... (251 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/taxes.mdx">
---
sidebar_position: 17
sidebar_label: 'Taxes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Tax rates
The taxes API allows you to create, view, update, and delete individual tax rates, or a batch of tax rates.

## Tax rate properties
| Attribute  |   Type  |                                                                                   Description                                                                                   |
|------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id`       | integer | Unique identifier for the resource. `READ-ONLY`                                                                                                   |
| `country`  | string  | Country ISO 3166 code. See [ISO 3166 Codes (Countries)](http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html) for more details                                              |
| `state`    | string  | State code.                                                                                                                                                                     |
| `postcode` | string  | Postcode/ZIP.                                                                                                                                                                   |
| `city`     | string  | City name.                                                                                                                                                                      |
| `rate`     | string  | Tax rate.                                                                                                                                                                       |
| `name`     | string  | Tax rate name.                                                                                                                                                                  |
| `priority` | integer | Tax priority. Only 1 matching rate per priority will be used. To define multiple tax rates for a single area you need to specify a different priority per rate. Default is `1`. |
| `compound` | boolean | Whether or not this is a compound rate. Compound tax rates are applied on top of other tax rates. Default is `false`.                                                           |
| `shipping` | boolean | Whether or not this tax rate also gets applied to shipping. Default is `true`.                                                                                                  |
| `order`    | integer | Indicates the order that will appear in queries.                                                                                                                                |
| `class`    | string  | Tax class. Default is `standard`.                                                                                                                                               |

## Create a tax rate
This API helps you to create a new tax rate.

... (3998 lines truncated)
</file>

<file path="docs/apis/rest-api/v2/webhooks.mdx">
---
sidebar_position: 19
sidebar_label: 'Webhooks'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Webhooks
The webhooks API allows you to create, view, update, and delete individual, or a batch, of webhooks.

Webhooks can be managed via the WooCommerce settings screen or by using the REST API endpoints. The `WC_Webhook` class manages all data storage and retrieval of the webhook custom post type, as well as enqueuing webhook actions and processing/delivering/logging webhooks. On `woocommerce_init`, active webhooks are loaded.

Each webhook has:

* `status`: active (delivers payload), paused (delivery paused by admin), disabled (delivery paused by failure).
* `topic`: determines which resource events the webhook is triggered for.
* `delivery URL`: URL where the payload is delivered, must be HTTP or HTTPS.
* `secret`: an optional secret key that is used to generate a HMAC-SHA256 hash of the request body so the receiver can verify authenticity of the webhook.
* `hooks`: an array of hook names that are added and bound to the webhook for processing.

### Topics
The topic is a combination resource (e.g. order) and event (e.g. created) and maps to one or more hook names (e.g. `woocommerce_checkout_order_processed`). Webhooks can be created using the topic name and the appropriate hooks are automatically added.

Core topics are:

* Coupons: `coupon.created`, `coupon.updated` and `coupon.deleted`.
* Customers: `customer.created`, `customer.updated` and `customer.deleted`.
* Orders: `order.created`, `order.updated` and `order.deleted`.
* Products: `product.created`, `product.updated` and `product.deleted`.
... (1150 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/_category_.json">
{
	"label": "v3 (current)",
	"position": 3
}
</file>

<file path="docs/apis/rest-api/v3/api-reference.mdx">
---
sidebar_position: 0
sidebar_label: 'API Reference'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Index

By default, the API provides information about all available endpoints on the site. Authentication is not required to access the API index.

```http
GET /wp-json/wc/v3
```

<Tabs>
  <TabItem value="curl" label="cURL">

```shell
curl https://example.com/wp-json/wc/v3
```

  </TabItem>
  <TabItem value="js" label="JavaScript">

```javascript
WooCommerce.get( '' )
	.then( ( response ) => {
		console.log( response.data );
... (8986 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/coupons.mdx">
---
sidebar_position: 1
sidebar_label: 'Coupons'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Coupons

The coupons API allows you to create, view, update, and delete individual, or a batch, of coupon codes.

## Coupon properties

| Attribute                     | Type      | Description                                                                                                                          |
| ----------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `id`                          | integer   | Unique identifier for the object. `READ-ONLY`                                                          |
| `code`                        | string    | Coupon code. `MANDATORY`                                                                               |
| `amount`                      | string    | The amount of discount. Should always be numeric, even if setting a percentage.                                                      |
| `date_created`                | date-time | The date the coupon was created, in the site's timezone. `READ-ONLY`                                   |
| `date_created_gmt`            | date-time | The date the coupon was created, as GMT. `READ-ONLY`                                                   |
| `date_modified`               | date-time | The date the coupon was last modified, in the site's timezone. `READ-ONLY`                             |
| `date_modified_gmt`           | date-time | The date the coupon was last modified, as GMT. `READ-ONLY`                                             |
| `discount_type`               | string    | Determines the type of discount that will be applied. Options: `percent`, `fixed_cart` and `fixed_product`. Default is `fixed_cart`. |
| `description`                 | string    | Coupon description.                                                                                                                  |
| `date_expires`                | string    | The date the coupon expires, in the site's timezone.                                                                                 |
| `date_expires_gmt`            | string    | The date the coupon expires, as GMT.                                                                                                 |
| `usage_count`                 | integer   | Number of times the coupon has been used already. `READ-ONLY`                                          |
| `individual_use`              | boolean   | If true, the coupon can only be used individually. Other applied coupons will be removed from the cart. Default is `false`.          |
| `product_ids`                 | array     | List of product IDs the coupon can be used on.                                                                                       |
... (1048 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/customers.mdx">
---
sidebar_position: 2
sidebar_label: 'Customers'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Customers

The customer API allows you to create, view, update, and delete individual, or a batch, of customers.

## Customer properties

| Attribute            | Type      | Description                                                                                                |
| -------------------- | --------- | ---------------------------------------------------------------------------------------------------------- |
| `id`                 | integer   | Unique identifier for the resource. `READ-ONLY`                              |
| `date_created`       | date-time | The date the customer was created, in the site's timezone. `READ-ONLY`       |
| `date_created_gmt`   | date-time | The date the customer was created, as GMT. `READ-ONLY`                       |
| `date_modified`      | date-time | The date the customer was last modified, in the site's timezone. `READ-ONLY` |
| `date_modified_gmt`  | date-time | The date the customer was last modified, as GMT. `READ-ONLY`                 |
| `email`              | string    | The email address for the customer. `MANDATORY`                              |
| `first_name`         | string    | Customer first name.                                                                                       |
| `last_name`          | string    | Customer last name.                                                                                        |
| `role`               | string    | Customer role. `READ-ONLY`                                                   |
| `username`           | string    | Customer login name.                                                                                       |
| `password`           | string    | Customer password. `WRITE-ONLY`                                              |
| `billing`            | object    | List of billing address data. See [Customer - Billing properties](#customer---billing-properties)            |
| `shipping`           | object    | List of shipping address data. See [Customer - Shipping properties](#customer---shipping-properties)         |
| `is_paying_customer` | bool      | Is the customer a paying customer? `READ-ONLY`                               |
... (1651 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/data.mdx">
---
sidebar_position: 30
sidebar_label: 'Data'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Data

The data API allows you to view all types of data available.

## List all data

This API lets you retrieve and view a simple list of available data endpoints.

```http
GET /wp-json/wc/v3/data
```

<Tabs>
  <TabItem value="curl" label="cURL">

```shell
curl https://example.com/wp-json/wc/v3/data \
	-u consumer_key:consumer_secret
```

  </TabItem>
  <TabItem value="js" label="JavaScript">
... (1324 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/index.mdx">
---
title: REST API v3
slug: /apis/rest-api/v3
sidebar_position: 0
---

import DocCardList from '@theme/DocCardList';

The current and recommended version of the WooCommerce REST API. Use `/wp-json/wc/v3/` endpoints for all new integrations.

<DocCardList />
</file>

<file path="docs/apis/rest-api/v3/order-actions.mdx">
---
sidebar_position: 4
sidebar_label: 'Order Actions'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Order actions

The order actions API allows you to perform specific actions with existing orders like you can from the Edit Order screen in the web app.

_Note: currently only some actions are available, other actions will be introduced at a later time._

## Send order details to customer

This endpoint allows you to trigger an email to the customer with the details of their order. In case the order doesn't yet have a billing email set, you can specify an email recipient. However, if the order does have an existing billing email, this will return an error, unless you also specify that the existing email should be overwritten by using the `force_email_update` parameter.

```http
POST /wp-json/wc/v3/orders/<id>/actions/send_order_details
```

<Tabs>
  <TabItem value="curl" label="cURL">

```shell
curl -X POST https://example.com/wp-json/wc/v3/orders/723/actions/send_order_details \
	-u consumer_key:consumer_secret \
	-d '{
	  "email": "somebody@example.com",
... (258 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/order-notes.mdx">
---
sidebar_position: 5
sidebar_label: 'Order Notes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Order notes

The order notes API allows you to create, view, and delete individual order notes.  
Order notes are added by administrators and programmatically to store data about an order, or order events.

## Order note properties

| Attribute          | Type      | Description                                                                                                                                      |
| ------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`               | integer   | Unique identifier for the resource. `READ-ONLY`                                                                    |
| `author`           | string    | Order note author. `READ-ONLY`                                                                                     |
| `date_created`     | date-time | The date the order note was created, in the site's timezone. `READ-ONLY`                                           |
| `date_created_gmt` | date-time | The date the order note was created, as GMT. `READ-ONLY`                                                           |
| `note`             | string    | Order note content. `MANDATORY`                                                                                    |
| `customer_note`    | boolean   | If true, the note will be shown to customers and they will be notified. If false, the note will be for admin reference only. Default is `false`. |
| `added_by_user`    | boolean   | If true, this note will be attributed to the current user. If false, the note will be attributed to the system. Default is `false`.              |

## Create an order note

This API helps you to create a new note for an order.

```http
... (420 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/order-refunds.mdx">
---
sidebar_position: 6
sidebar_label: 'Order Refunds'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Order refunds

The order refunds API allows you to create, view, and delete individual refunds, based on an existing order.

## Order refund properties

| Attribute          | Type      | Description                                                                                                                                                                   |
| ------------------ | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`               | integer   | Unique identifier for the resource. `READ-ONLY`                                                                                                 |
| `date_created`     | date-time | The date the order refund was created, in the site's timezone. `READ-ONLY`                                                                      |
| `date_created_gmt` | date-time | The date the order refund was created, as GMT. `READ-ONLY`                                                                                      |
| `amount`           | string    | Total refund amount. Optional. If this parameter is provided, it will take precedence over line item totals, even when total of line items does not matches with this amount. |
| `reason`           | string    | Reason for refund.                                                                                                                                                            |
| `refunded_by`      | integer   | User ID of user who created the refund.                                                                                                                                       |
| `refunded_payment` | boolean   | If the payment was refunded via the API. See `api_refund`. `READ-ONLY`                                                                          |
| `meta_data`        | array     | Meta data. See [Order refund - Meta data properties](#order-refund---meta-data-properties)                                                                                      |
| `line_items`       | array     | Line items data. See [Order refund - Line items properties](#order-refund---line-items-properties)                                                                              |
| `tax_lines`        | array     | Tax lines data. See [Order refund - Tax lines properties](#order-refund---tax-lines-properties) `READ-ONLY`                                       |
| `shipping_lines`   | array     | Shipping lines data. See [Order refund - Shipping lines properties](#order-refund---shipping-lines-properties)                                                                  |
| `fee_lines`        | array     | Fee lines data. See [Order refund - Fee lines properties](#order-refund---fee-lines-properties)                                                                                 |
| `api_refund`       | boolean   | When true, the payment gateway API is used to generate the refund. Default is `true`. `WRITE-ONLY`                                              |
| `api_restock`      | boolean   | When true, the selected line items are restocked Default is `true`. `WRITE-ONLY`                                                                |
... (764 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/orders.mdx">
---
sidebar_position: 3
sidebar_label: 'Orders'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Orders

The orders API allows you to create, view, update, and delete individual, or a batch, of orders.

## Order properties

| Attribute              | Type      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| ---------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                   | integer   | Unique identifier for the resource. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `parent_id`            | integer   | Parent order ID.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `number`               | string    | Order number. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `order_key`            | string    | Order key. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `created_via`          | string    | Shows where the order was created. It can only be set during order creation and cannot be modified afterward.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `version`              | string    | Version of WooCommerce which last updated the order. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `status`               | string    | Order status. Options: `pending`, `processing`, `on-hold`, `completed`, `cancelled`, `refunded`, `failed` and `trash`. Default is `pending`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `currency`             | string    | Currency the order was created with, in ISO format. Options: `AED`, `AFN`, `ALL`, `AMD`, `ANG`, `AOA`, `ARS`, `AUD`, `AWG`, `AZN`, `BAM`, `BBD`, `BDT`, `BGN`, `BHD`, `BIF`, `BMD`, `BND`, `BOB`, `BRL`, `BSD`, `BTC`, `BTN`, `BWP`, `BYR`, `BZD`, `CAD`, `CDF`, `CHF`, `CLP`, `CNY`, `COP`, `CRC`, `CUC`, `CUP`, `CVE`, `CZK`, `DJF`, `DKK`, `DOP`, `DZD`, `EGP`, `ERN`, `ETB`, `EUR`, `FJD`, `FKP`, `GBP`, `GEL`, `GGP`, `GHS`, `GIP`, `GMD`, `GNF`, `GTQ`, `GYD`, `HKD`, `HNL`, `HRK`, `HTG`, `HUF`, `IDR`, `ILS`, `IMP`, `INR`, `IQD`, `IRR`, `IRT`, `ISK`, `JEP`, `JMD`, `JOD`, `JPY`, `KES`, `KGS`, `KHR`, `KMF`, `KPW`, `KRW`, `KWD`, `KYD`, `KZT`, `LAK`, `LBP`, `LKR`, `LRD`, `LSL`, `LYD`, `MAD`, `MDL`, `MGA`, `MKD`, `MMK`, `MNT`, `MOP`, `MRO`, `MUR`, `MVR`, `MWK`, `MXN`, `MYR`, `MZN`, `NAD`, `NGN`, `NIO`, `NOK`, `NPR`, `NZD`, `OMR`, `PAB`, `PEN`, `PGK`, `PHP`, `PKR`, `PLN`, `PRB`, `PYG`, `QAR`, `RON`, `RSD`, `RUB`, `RWF`, `SAR`, `SBD`, `SCR`, `SDG`, `SEK`, `SGD`, `SHP`, `SLL`, `SOS`, `SRD`, `SSP`, `STD`, `SYP`, `SZL`, `THB`, `TJS`, `TMT`, `TND`, `TOP`, `TRY`, `TTD`, `TWD`, `TZS`, `UAH`, `UGX`, `USD`, `UYU`, `UZS`, `VEF`, `VND`, `VUV`, `WST`, `XAF`, `XCD`, `XOF`, `XPF`, `YER`, `ZAR` and `ZMW`. Default is `USD`. |
| `date_created`         | date-time | The date the order was created, in the site's timezone. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `date_created_gmt`     | date-time | The date the order was created, as GMT. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `date_modified`        | date-time | The date the order was last modified, in the site's timezone. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `date_modified_gmt`    | date-time | The date the order was last modified, as GMT. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `discount_total`       | string    | Total discount amount for the order. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `discount_tax`         | string    | Total discount tax amount for the order. `READ-ONLY`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
... (2985 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/payment-gateways.mdx">
---
sidebar_position: 23
sidebar_label: 'Payment Gateways'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Payment gateways

The payment gateways API allows you to view, and update individual payment gateways. Results are not paginated - all gateways will be returned.

## Payment gateway properties

| Attribute            | Type    | Description                                                                                                 |
| -------------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| `id`                 | string  | Payment gateway ID. `READ-ONLY`                                               |
| `title`              | string  | Payment gateway title on checkout.                                                                          |
| `description`        | string  | Payment gateway description on checkout.                                                                    |
| `order`              | integer | Payment gateway sort order.                                                                                 |
| `enabled`            | boolean | Payment gateway enabled status.                                                                             |
| `method_title`       | string  | Payment gateway method title. `READ-ONLY`                                     |
| `method_description` | string  | Payment gateway method description. `READ-ONLY`                               |
| `method_supports`    | array   | Supported features for this payment gateway. `READ-ONLY`                      |
| `settings`           | object  | Payment gateway settings. See [Payment gateway - Settings properties](#payment-gateway---settings-properties) |

### Payment gateway - Settings properties

| Attribute     | Type   | Description                                                                                                                                                                                     |
| ------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
... (633 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/product-attribute-terms.mdx">
---
sidebar_position: 10
sidebar_label: 'Product Attribute Terms'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product attribute terms

The product attribute terms API allows you to create, view, update, and delete individual, or a batch, of attribute terms.

## Product attribute term properties

| Attribute     | Type    | Description                                                                              |
| ------------- | ------- | ---------------------------------------------------------------------------------------- |
| `id`          | integer | Unique identifier for the resource. `READ-ONLY`            |
| `name`        | string  | Term name. `MANDATORY`                                     |
| `slug`        | string  | An alphanumeric identifier for the resource unique to its type.                          |
| `description` | string  | HTML description of the resource.                                                        |
| `menu_order`  | integer | Menu order, used to custom sort the resource.                                            |
| `count`       | integer | Number of published products for the resource. `READ-ONLY` |

## Create an attribute term

This API helps you to create a new product attribute term.

```http
POST /wp-json/wc/v3/products/attributes/<attribute_id>/terms
```
... (855 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/product-attributes.mdx">
---
sidebar_position: 9
sidebar_label: 'Product Attributes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product attributes

The product attributes API allows you to create, view, update, and delete individual, or a batch, of product attributes.

## Product attribute properties

| Attribute      | Type    | Description                                                                                      |
| -------------- | ------- | ------------------------------------------------------------------------------------------------ |
| `id`           | integer | Unique identifier for the resource. `READ-ONLY`                    |
| `name`         | string  | Attribute name. `MANDATORY`                                        |
| `slug`         | string  | An alphanumeric identifier for the resource unique to its type.                                  |
| `type`         | string  | Type of attribute. By default only `select` is supported.                                        |
| `order_by`     | string  | Default sort order. Options: `menu_order`, `name`, `name_num` and `id`. Default is `menu_order`. |
| `has_archives` | boolean | Enable/Disable attribute archives. Default is `false`.                                           |

## Create a product attribute

This API helps you to create a new product attribute.

```http
POST /wp-json/wc/v3/products/attributes
```
... (744 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/product-categories.mdx">
---
sidebar_position: 11
sidebar_label: 'Product Categories'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product categories

The product categories API allows you to create, view, update, and delete individual, or a batch, of categories.

## Product category properties

| Attribute     | Type    | Description                                                                                                      |
| ------------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
| `id`          | integer | Unique identifier for the resource. `READ-ONLY`                                    |
| `name`        | string  | Category name. `MANDATORY`                                                         |
| `slug`        | string  | An alphanumeric identifier for the resource unique to its type.                                                  |
| `parent`      | integer | The ID for the parent of the resource.                                                                           |
| `description` | string  | HTML description of the resource.                                                                                |
| `display`     | string  | Category archive display type. Options: `default`, `products`, `subcategories` and `both`. Default is `default`. |
| `image`       | object  | Image data. See [Product category - Image properties](#product-category---image-properties)                        |
| `menu_order`  | integer | Menu order, used to custom sort the resource.                                                                    |
| `count`       | integer | Number of published products for the resource. `READ-ONLY`                         |

### Product category - Image properties

| Attribute           | Type      | Description                                                                                             |
| ------------------- | --------- | ------------------------------------------------------------------------------------------------------- |
... (1011 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/product-custom-fields.mdx">
---
sidebar_position: 12
sidebar_label: 'Product Custom Fields'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product custom fields

The product custom fields API allows you to view the custom field names that have been recorded.

## Custom fields available parameters

| Parameter  | Type    | Description                                                                                                                  |
| ---------- | ------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `context`  | string  | Scope under which the request is made; determines fields present in response. Options: `view` and `edit`. Default is `view`. |
| `page`     | integer | Current page of the collection. Default is `1`.                                                                              |
| `per_page` | integer | Maximum number of items to be returned in result set. Default is `10`.                                                       |
| `search`   | string  | Limit results to those matching a string.                                                                                    |
| `order`    | string  | Order sort attribute ascending or descending. Options: `asc` and `desc`. Default is `desc`.                                  |

## Retrieve product custom field names

This API lets you retrieve filtered custom field names.

```http
GET /wp-json/wc/v3/products/custom-fields/names
```

... (57 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/product-reviews.mdx">
---
sidebar_position: 15
sidebar_label: 'Product Reviews'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product reviews

The product reviews API allows you to create, view, update, and delete individual, or a batch, of product reviews.

## Product review properties

| Attribute          | Type    | Description                                                                                                         |
| ------------------ | ------- | ------------------------------------------------------------------------------------------------------------------- |
| `id`               | integer | Unique identifier for the resource. `READ-ONLY`                                       |
| `date_created`     | string  | The date the review was created, in the site's timezone. `READ-ONLY`                  |
| `date_created_gmt` | string  | The date the review was created, as GMT. `READ-ONLY`                                  |
| `product_id`       | integer | Unique identifier for the product that the review belongs to.                                                       |
| `status`           | string  | Status of the review. Options: `approved`, `hold`, `spam`, `unspam`, `trash` and `untrash`. Defaults to `approved`. |
| `reviewer`         | string  | Reviewer name.                                                                                                      |
| `reviewer_email`   | string  | Reviewer email.                                                                                                     |
| `review`           | string  | The content of the review.                                                                                          |
| `rating`           | integer | Review rating (0 to 5).                                                                                             |
| `verified`         | boolean | Shows if the reviewer bought the product or not.                                                                    |

## Create a product review

This API helps you to create a new product review.
... (931 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/product-shipping-classes.mdx">
---
sidebar_position: 13
sidebar_label: 'Product Shipping Classes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product shipping classes

The product shipping class API allows you to create, view, update, and delete individual, or a batch, of shipping classes.

## Product shipping class properties

| Attribute     | Type    | Description                                                                              |
| ------------- | ------- | ---------------------------------------------------------------------------------------- |
| `id`          | integer | Unique identifier for the resource. `READ-ONLY`            |
| `name`        | string  | Shipping class name. `MANDATORY`                           |
| `slug`        | string  | An alphanumeric identifier for the resource unique to its type.                          |
| `description` | string  | HTML description of the resource.                                                        |
| `count`       | integer | Number of published products for the resource. `READ-ONLY` |

## Create a shipping class

This API helps you to create a new product shipping class.

```http
POST /wp-json/wc/v3/products/shipping_classes
```

... (722 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/product-tags.mdx">
---
sidebar_position: 14
sidebar_label: 'Product Tags'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product tags

The product tags API allows you to create, view, update, and delete individual, or a batch, of product tags.

## Product tag properties

| Attribute     | Type    | Description                                                                              |
| ------------- | ------- | ---------------------------------------------------------------------------------------- |
| `id`          | integer | Unique identifier for the resource. `READ-ONLY`            |
| `name`        | string  | Tag name. `MANDATORY`                                      |
| `slug`        | string  | An alphanumeric identifier for the resource unique to its type.                          |
| `description` | string  | HTML description of the resource.                                                        |
| `count`       | integer | Number of published products for the resource. `READ-ONLY` |

## Create a product tag

This API helps you to create a new product tag.

```http
POST /wp-json/wc/v3/products/tags
```

... (722 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/product-variations.mdx">
---
sidebar_position: 8
sidebar_label: 'Product Variations'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Product variations

The product variations API allows you to create, view, update, and delete individual, or a batch, of product variations.

## Product variation properties

| Attribute               | Type            | Description                                                                                                         |
| ----------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------- |
| `id`                    | integer         | Unique identifier for the resource. `READ-ONLY`                                       |
| `date_created`          | date-time       | The date the variation was created, in the site's timezone. `READ-ONLY`               |
| `date_created_gmt`      | date-time       | The date the variation was created, as GMT. `READ-ONLY`                               |
| `date_modified`         | date-time       | The date the variation was last modified, in the site's timezone. `READ-ONLY`         |
| `date_modified_gmt`     | date-time       | The date the variation was last modified, as GMT. `READ-ONLY`                         |
| `description`           | string          | Variation description.                                                                                              |
| `permalink`             | string          | Variation URL. `READ-ONLY`                                                            |
| `sku`                   | string          | Unique identifier.                                                                                                  |
| `global_unique_id`      | string          | GTIN, UPC, EAN or ISBN. A global unique identifier for the variation.                                               |
| `price`                 | string          | Current variation price. `READ-ONLY`                                                  |
| `regular_price`         | string          | Variation regular price.                                                                                            |
| `sale_price`            | string          | Variation sale price.                                                                                               |
| `date_on_sale_from`     | date-time       | Start date of sale price, in the site's timezone.                                                                   |
| `date_on_sale_from_gmt` | date-time       | Start date of sale price, as GMT.                                                                                   |
... (1513 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/products.mdx">
---
sidebar_position: 7
sidebar_label: 'Products'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Products

The products API allows you to create, view, update, and delete individual, or a batch, of products.

## Product properties

| Attribute               | Type      | Description                                                                                                                                                                                                                            |
| ----------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                    | integer   | Unique identifier for the resource. `READ-ONLY`                                                                                                                                                          |
| `name`                  | string    | Product name.                                                                                                                                                                                                                          |
| `slug`                  | string    | Product slug.                                                                                                                                                                                                                          |
| `permalink`             | string    | Product URL. `READ-ONLY`                                                                                                                                                                                 |
| `date_created`          | date-time | The date the product was created, in the site's timezone. `READ-ONLY`                                                                                                                                    |
| `date_created_gmt`      | date-time | The date the product was created, as GMT. `READ-ONLY`                                                                                                                                                    |
| `date_modified`         | date-time | The date the product was last modified, in the site's timezone. `READ-ONLY`                                                                                                                              |
| `date_modified_gmt`     | date-time | The date the product was last modified, as GMT. `READ-ONLY`                                                                                                                                              |
| `type`                  | string    | Product type. Options: `simple`, `grouped`, `external` and `variable`. Default is `simple`.                                                                                                                                            |
| `status`                | string    | Product status (post status). Options: `draft`, `pending`, `private` and `publish`. Default is `publish`.                                                                                                                              |
| `featured`              | boolean   | Featured product. Default is `false`.                                                                                                                                                                                                  |
| `catalog_visibility`    | string    | Catalog visibility. Options: `visible`, `catalog`, `search` and `hidden`. Default is `visible`.                                                                                                                                        |
| `description`           | string    | Product description.                                                                                                                                                                                                                   |
| `short_description`     | string    | Product short description.                                                                                                                                                                                                             |
... (2959 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/refunds.mdx">
---
sidebar_position: 17
sidebar_label: 'Refunds'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Refunds

The refunds API is a simple, read-only endpoint that allows you to retrieve a list of refunds outside the context of an existing order. To create, view, and delete individual refunds, check out the [order refunds API](../order-refunds).

## Refund properties

All properties are the same as those in the [order refunds endpoint](../order-refunds#order-refund-properties), but with one additional property:

| Attribute   | Type    | Description                                        |
| ----------- | ------- | -------------------------------------------------- |
| `parent_id` | integer | The ID of the order the refund is associated with. |

## Retrieve a list of refunds

This API lets you retrieve and view refunds from your store, regardless of which order they are associated with.

```http
GET /wp-json/wc/v3/refunds
```

<Tabs>
  <TabItem value="curl" label="cURL">
... (151 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/reports.mdx">
---
sidebar_position: 16
sidebar_label: 'Reports'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Reports

The reports API allows you to view all types of reports available.

## List all reports

This API lets you retrieve and view a simple list of available reports.

```http
GET /wp-json/wc/v3/reports
```

<Tabs>
  <TabItem value="curl" label="cURL">

```shell
curl https://example.com/wp-json/wc/v3/reports \
	-u consumer_key:consumer_secret
```

  </TabItem>
  <TabItem value="js" label="JavaScript">
... (934 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/setting-options.mdx">
---
sidebar_position: 22
sidebar_label: 'Setting Options'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Setting options

## Setting option properties

| Attribute     | Type   | Description                                                                                                                                                                                     |
| ------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`          | string | A unique identifier for the setting. `READ-ONLY`                                                                                                                  |
| `label`       | string | A human readable label for the setting used in interfaces. `READ-ONLY`                                                                                            |
| `description` | string | A human readable description for the setting used in interfaces. `READ-ONLY`                                                                                      |
| `value`       | mixed  | Setting value.                                                                                                                                                                                  |
| `default`     | mixed  | Default value for the setting. `READ-ONLY`                                                                                                                        |
| `tip`         | string | Additional help text shown to the user about the setting. `READ-ONLY`                                                                                             |
| `placeholder` | string | Placeholder text to be displayed in text inputs. `READ-ONLY`                                                                                                      |
| `type`        | string | Type of setting. Options: `text`, `email`, `number`, `color`, `password`, `textarea`, `select`, `multiselect`, `radio`, `image_width` and `checkbox`. `READ-ONLY` |
| `options`     | object | Array of options (key value pairs) for inputs such as select, multiselect, and radio buttons. `READ-ONLY`                                                         |
| `group_id`    | string | An identifier for the group this setting belongs to. `READ-ONLY`                                                                                                  |

## Retrieve a setting option

This API lets you retrieve and view a specific setting option.

```http
... (1919 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/settings.mdx">
---
sidebar_position: 21
sidebar_label: 'Settings'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Settings

The settings API allows you to view all groups of settings available.

## Setting group properties

| Attribute     | Type   | Description                                                                                                |
| ------------- | ------ | ---------------------------------------------------------------------------------------------------------- |
| `id`          | string | A unique identifier that can be used to link settings together. `READ-ONLY`  |
| `label`       | string | A human readable label for the setting used in interfaces. `READ-ONLY`       |
| `description` | string | A human readable description for the setting used in interfaces. `READ-ONLY` |
| `parent_id`   | string | ID of parent grouping. `READ-ONLY`                                           |
| `sub_groups`  | string | IDs for settings sub groups. `READ-ONLY`                                     |

## List all settings groups

This API helps you to view all the settings groups.

```http
GET /wp-json/wc/v3/settings
```

... (345 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/shipping-methods.mdx">
---
sidebar_position: 27
sidebar_label: 'Shipping Methods'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Shipping methods

The shipping methods API allows you to view individual shipping methods.

## Shipping method properties

| Attribute     | Type   | Description                                                            |
| ------------- | ------ | ---------------------------------------------------------------------- |
| `id`          | string | Method ID. `READ-ONLY`                   |
| `title`       | string | Shipping method title. `READ-ONLY`       |
| `description` | string | Shipping method description. `READ-ONLY` |

## Retrieve a shipping method

This API lets you retrieve and view a specific shipping method.

```http
GET /wp-json/wc/v3/shipping_methods/<id>
```

<Tabs>
  <TabItem value="curl" label="cURL">
... (178 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/shipping-zone-locations.mdx">
---
sidebar_position: 25
sidebar_label: 'Shipping Zone Locations'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Shipping zone locations

The shipping zone locations API allows you to view and batch update locations of a shipping zone.

## Shipping location properties

| Attribute | Type   | Description                                                                                                 |
| --------- | ------ | ----------------------------------------------------------------------------------------------------------- |
| `code`    | string | Shipping zone location code.                                                                                |
| `type`    | string | Shipping zone location type. Options: `postcode`, `state`, `country` and `continent`. Default is `country`. |

## List all locations of a shipping zone

This API helps you to view all the locations of a shipping zone.

```http
GET /wp-json/wc/v3/shipping/zones/<id>/locations
```

<Tabs>
  <TabItem value="curl" label="cURL">

... (216 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/shipping-zone-methods.mdx">
---
sidebar_position: 26
sidebar_label: 'Shipping Zone Methods'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Shipping zone methods

The shipping zone methods API allows you to create, view, update, and delete individual methods of a shipping zone.

## Shipping method properties

| Attribute            | Type    | Description                                                                                                 |
| -------------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| `instance_id`        | integer | Shipping method instance ID. `READ-ONLY`                                      |
| `title`              | string  | Shipping method customer facing title. `READ-ONLY`                            |
| `order`              | integer | Shipping method sort order.                                                                                 |
| `enabled`            | boolean | Shipping method enabled status.                                                                             |
| `method_id`          | string  | Shipping method ID. `READ-ONLY` `MANDATORY`     |
| `method_title`       | string  | Shipping method title. `READ-ONLY`                                            |
| `method_description` | string  | Shipping method description. `READ-ONLY`                                      |
| `settings`           | object  | Shipping method settings. See [Shipping method - Settings properties](#shipping-method---settings-properties) |

### Shipping method - Settings properties

| Attribute     | Type   | Description                                                                                                                                                                                     |
| ------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`          | string | A unique identifier for the setting. `READ-ONLY`                                                                                                                  |
... (1012 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/shipping-zones.mdx">
---
sidebar_position: 24
sidebar_label: 'Shipping Zones'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Shipping zones

The shipping zones API allows you to create, view, update, and delete individual shipping zones.

## Shipping zone properties

| Attribute | Type    | Description                                                                   |
| --------- | ------- | ----------------------------------------------------------------------------- |
| `id`      | integer | Unique identifier for the resource. `READ-ONLY` |
| `name`    | string  | Shipping zone name. `MANDATORY`                 |
| `order`   | integer | Shipping zone order.                                                          |

## Create a shipping zone

This API helps you to create a new shipping zone.

```http
POST /wp-json/wc/v3/shipping/zones
```

<Tabs>
  <TabItem value="curl" label="cURL">
... (471 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/system-status-tools.mdx">
---
sidebar_position: 29
sidebar_label: 'System Status Tools'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# System status tools

The system status tools API allows you to view and run tools from system status.

## System status tool properties

| Attribute     | Type    | Description                                                                                                         |
| ------------- | ------- | ------------------------------------------------------------------------------------------------------------------- |
| `id`          | string  | A unique identifier for the tool. `READ-ONLY`                                         |
| `name`        | string  | Tool name. `READ-ONLY`                                                                |
| `action`      | string  | What running the tool will do. `READ-ONLY`                                            |
| `description` | string  | Tool description. `READ-ONLY`                                                         |
| `success`     | boolean | Did the tool run successfully? `READ-ONLY` `WRITE-ONLY` |
| `message`     | string  | Tool return message. `READ-ONLY` `WRITE-ONLY`           |
| `confirm`     | boolean | Confirm execution of the tool. Default is `false`. `WRITE-ONLY`                       |

## Retrieve a tool from system status

This API lets you retrieve and view a specific tool from system status by ID.

```http
GET /wp-json/wc/v3/system_status/tools/<id>
... (539 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/system-status.mdx">
---
sidebar_position: 28
sidebar_label: 'System Status'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# System status

The system status API allows you to view all system status items.

## System status properties

| Attribute        | Type   | Description                                                                                                                                |
| ---------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `environment`    | object | Environment. See [System status - Environment properties](#system-status---environment-properties) `READ-ONLY` |
| `database`       | object | Database. See [System status - Database properties](#system-status---database-properties) `READ-ONLY`          |
| `active_plugins` | array  | Active plugins. `READ-ONLY`                                                                                  |
| `theme`          | object | Theme. See [System status - Theme properties](#system-status---theme-properties) `READ-ONLY`                   |
| `settings`       | object | Settings. See [System status - Settings properties](#system-status---settings-properties) `READ-ONLY`          |
| `security`       | object | Security. See [System status - Security properties](#system-status---security-properties) `READ-ONLY`          |
| `pages`          | array  | WooCommerce pages. `READ-ONLY`                                                                               |

### System status - Environment properties

| Attribute                   | Type    | Description                                                                |
| --------------------------- | ------- | -------------------------------------------------------------------------- |
| `home_url`                  | string  | Home URL. `READ-ONLY`                        |
| `site_url`                  | string  | Site URL. `READ-ONLY`                        |
... (282 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/tax-classes.mdx">
---
sidebar_position: 19
sidebar_label: 'Tax Classes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Tax classes

The tax classes API allows you to create, view, and delete individual tax classes.

## Tax class properties

| Attribute | Type   | Description                                                                   |
| --------- | ------ | ----------------------------------------------------------------------------- |
| `slug`    | string | Unique identifier for the resource. `READ-ONLY` |
| `name`    | string | Tax class name. `REQUIRED`                      |

## Create a tax class

This API helps you to create a new tax class.

```http
POST /wp-json/wc/v3/taxes/classes
```

<Tabs>
  <TabItem value="curl" label="cURL">

... (257 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/taxes.mdx">
---
sidebar_position: 18
sidebar_label: 'Taxes'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Tax rates

The taxes API allows you to create, view, update, and delete individual tax rates, or a batch of tax rates.

## Tax rate properties

| Attribute   | Type     | Description                                                                                                                                                                     |
| ----------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`        | integer  | Unique identifier for the resource. `READ-ONLY`                                                                                                   |
| `country`   | string   | Country ISO 3166 code. See [ISO 3166 Codes (Countries)](http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html) for more details                                              |
| `state`     | string   | State code.                                                                                                                                                                     |
| `postcode`  | string   | Postcode/ZIP, it doesn't support multiple values. Deprecated as of WooCommerce 5.3, `postcodes` should be used instead.                                                         |
| `city`      | string   | City name, it doesn't support multiple values. Deprecated as of WooCommerce 5.3, `postcodes` should be used instead.                                                            |
| `postcodes` | string[] | Postcodes/ZIPs. Introduced in WooCommerce 5.3.                                                                                                                                  |
| `cities`    | string[] | City names. Introduced in WooCommerce 5.3.                                                                                                                                      |
| `rate`      | string   | Tax rate.                                                                                                                                                                       |
| `name`      | string   | Tax rate name.                                                                                                                                                                  |
| `priority`  | integer  | Tax priority. Only 1 matching rate per priority will be used. To define multiple tax rates for a single area you need to specify a different priority per rate. Default is `1`. |
| `compound`  | boolean  | Whether or not this is a compound tax rate. Compound rates are applied on top of other tax rates. Default is `false`.                                                           |
| `shipping`  | boolean  | Whether or not this tax rate also gets applied to shipping. Default is `true`.                                                                                                  |
| `order`     | integer  | Indicates the order that will appear in queries.                                                                                                                                |
| `class`     | string   | Tax class. Default is `standard`.                                                                                                                                               |
... (4145 lines truncated)
</file>

<file path="docs/apis/rest-api/v3/webhooks.mdx">
---
sidebar_position: 20
sidebar_label: 'Webhooks'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Webhooks

The webhooks API allows you to create, view, update, and delete individual, or a batch, of webhooks.

Webhooks can be managed via the WooCommerce settings screen or by using the REST API endpoints. The `WC_Webhook` class manages all data storage and retrieval of the webhook custom post type, as well as enqueuing webhook actions and processing/delivering/logging webhooks. On `woocommerce_init`, active webhooks are loaded.

Each webhook has:

-   `status`: active (delivers payload), paused (delivery paused by admin), disabled (delivery paused by failure).
-   `topic`: determines which resource events the webhook is triggered for.
-   `delivery URL`: URL where the payload is delivered, must be HTTP or HTTPS.
-   `secret`: an optional secret key that is used to generate a HMAC-SHA256 hash of the request body so the receiver can verify authenticity of the webhook.
-   `hooks`: an array of hook names that are added and bound to the webhook for processing.

### Topics

The topic is a combination resource (e.g. order) and event (e.g. created) and maps to one or more hook names (e.g. `woocommerce_checkout_order_processed`). Webhooks can be created using the topic name and the appropriate hooks are automatically added.

Core topics are:

-   Coupons: `coupon.created`, `coupon.updated` and `coupon.deleted`.
-   Customers: `customer.created`, `customer.updated` and `customer.deleted`.
... (858 lines truncated)
</file>

<file path="docs/apis/rest-api/_category_.json">
{
  "label": "REST API",
  "position": 1
}
</file>

<file path="docs/apis/rest-api/authentication.mdx">
---
sidebar_position: 1
sidebar_label: 'Authentication'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Authentication

WooCommerce includes two ways to authenticate with the WP REST API. It is also possible to authenticate using any [WP REST API authentication](http://v3.wp-api.org/guide/authentication/) plugin or method.

## REST API keys

Pre-generated keys can be used to authenticate use of the REST API endpoints. New keys can be generated either through the WordPress admin interface or they can be auto-generated through an endpoint.

### Generating API keys in the WordPress admin interface

To create or manage keys for a specific WordPress user, go to WooCommerce > Settings > Advanced > REST API.

*Note: Keys/Apps was found at WooCommerce > Settings > API > Key/Apps prior to WooCommerce 3.4.*

![WooCommerce REST API keys settings](v3/images/woocommerce-api-keys-settings.png)

Click the "Add Key" button. In the next screen, add a description and select the WordPress user you would like to generate the key for. Use of the REST API with the generated keys will conform to that user's WordPress roles and capabilities.

Choose the level of access for this REST API key, which can be _Read_ access, _Write_ access or _Read/Write_ access. Then click the "Generate API Key" button and WooCommerce will generate REST API keys for the selected user.

![Creating a new REST API key](v3/images/woocommerce-creating-api-keys.png)

... (404 lines truncated)
</file>

<file path="docs/apis/rest-api/index.mdx">
---
sidebar_label: 'Introduction'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# WooCommerce REST API

WooCommerce (WC) 2.6+ is fully integrated with the WordPress [REST](http://en.wikipedia.org/wiki/Representational_State_Transfer) API. This allows WC data to be created, read, updated, and deleted using requests in JSON format and using WordPress REST API Authentication methods and standard HTTP verbs which are understood by most HTTP clients.

The current WP REST API integration version is `v3` which takes a first-order position in endpoints.

## Requirements

To use the REST API you must be using:

- WooCommerce 3.5+
- WordPress 4.4+
- Pretty permalinks in **Settings > Permalinks** (default permalinks will not work)

You may access the API over either HTTP or HTTPS, but *HTTPS is recommended where possible*.

:::note
You are **not** required to install the [WP REST API (WP API)](https://wordpress.org/plugins/rest-api/) plugin.
:::

If you use ModSecurity and see `501 Method Not Implemented` errors, see [this issue](https://github.com/woocommerce/woocommerce/issues/9838) for details.

## Libraries and tools
... (276 lines truncated)
</file>

<file path="docs/apis/store-api/extending-store-api/available-endpoints-to-extend.md">
# Available extensible endpoints

Some endpoints of the Store API are extensible via a class called `ExtendSchema`. This allows you to customise the data (including the schema) that is returned by the Store API so that it can be consumed by your application or plugin.

For more information about extending the Store API, you may also be interested in:

-   [How to add your data to Store API using `ExtendSchema`](./extend-store-api-add-data.md)
-   [How to add a new endpoint](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/internal-developers/rest-api/extend-rest-api-new-endpoint.md)

Below is a list of available endpoints that you can extend using `ExtendSchema`, as well as some example use-cases.

## Products

The main `wc/store/products` endpoint is extensible via ExtendSchema. The data is available via the `extensions` key for each `product` in the response array.

This endpoint can be extended using the `ProductSchema::IDENTIFIER` key. For this endpoint, your `data_callback` callback function is passed `$product` as a parameter. Your `schema_callback` function is passed no additional parameters; all products should share the same schema.

### Use Cases

This endpoint is useful for adding additional data about individual products. This could be some meta data, additional pricing, or anything else to support custom blocks or components on the products page.

### Example

```php
woocommerce_store_api_register_endpoint_data(
	array(
		'endpoint'        => ProductSchema::IDENTIFIER,
		'namespace'       => 'my_plugin_namespace',
		'data_callback'   => function( $product ) {
			return array(
... (128 lines truncated)
</file>

<file path="docs/apis/store-api/extending-store-api/extend-store-api-add-custom-fields.md">
# Adding fields and passing values

This document describes how a developer can insert an input field into the Checkout block and have its value passed to the Store API so it's available when processing the checkout.

## Overview

Developers can extend the Checkout block to add new inner blocks and process additional data through the checkout POST request. This involves leveraging the extensibility interfaces provided by Gutenberg and WooCommerce Blocks. This is demonstrated in more detail in our tutorial: [Tutorial: Extending the WooCommerce Checkout Block
](https://developer.woocommerce.com/2023/08/07/extending-the-woocommerce-checkout-block-to-add-custom-shipping-options/).

## Prerequisites

- Basic understanding of React and the Gutenberg block editor.
- Familiarity with WooCommerce Blocks' extensibility interfaces and the Store API.

## Step-by-Step Guide

### 1. Set Up Your Development Environment

Ensure you have the following files in your project:

- `index.js`: Entry point for Webpack, imports, and registers the block type.
- `edit.js`: Handles the rendering of the block in the editor interface.
- `block.json`: Provides metadata and configurations for the block.
- `block.js`: Manages the block's state and user interactions.
- `frontend.js`: Registers the checkout block component for the frontend.

Refer to [this tutorial](https://developer.woocommerce.com/2023/08/07/extending-the-woocommerce-checkout-block-to-add-custom-shipping-options/) for an example of adding a custom shipping option to the checkout block.

### 2. Add a new field block to the Checkout Block

... (255 lines truncated)
</file>

<file path="docs/apis/store-api/extending-store-api/extend-store-api-add-data.md">
# Exposing your data

## The problem

You want to extend the Mini-Cart, Cart and Checkout blocks, but you want to use some custom data not available on Store API or the context. You don't want to create your own endpoints or Ajax actions. You want to piggyback on the existing StoreAPI calls.

## Solution

ExtendSchema offers the possibility to add contextual custom data to Store API endpoints, like `wc/store/cart` and `wc/store/cart/items` endpoints. That data is namespaced to your plugin and protected from other plugins causing it to malfunction. The data is available on all frontend filters and slotFills for you to consume.

## Basic usage

You can use ExtendSchema by registering a couple of functions, `schema_callback` and `data_callback` on a specific endpoint namespace. ExtendSchema will call them at execution time and will pass them relevant data as well.

This example below uses the Cart endpoint, [see passed parameters.](./available-endpoints-to-extend.md)

**Note: Make sure to read the "Things to consider" section below.**

```php
use Automattic\WooCommerce\StoreApi\Schemas\V1\CartSchema;

add_action('woocommerce_blocks_loaded', function() {
 woocommerce_store_api_register_endpoint_data(
	array(
		'endpoint' => CartSchema::IDENTIFIER,
		'namespace' => 'plugin_namespace',
		'data_callback' => 'my_data_callback',
		'schema_callback' => 'my_schema_callback',
		'schema_type' => ARRAY_A,
		)
... (287 lines truncated)
</file>

<file path="docs/apis/store-api/extending-store-api/extend-store-api-formatters.md">
# Available Formatters 

`Formatters` are utility classes that allow you to format values to so that they are compatible with the StoreAPI. Default formatters handle values such as monetary amounts, currency information, or HTML.

It is recommended that you use these formatters when you are extending the StoreAPI.

## Why are formatters useful?

Using the formatter utilities when returning certain types of data will ensure that your custom data is consistent and compatible with other endpoints. They also take care of any store specific settings that may affect the formatting of the data, such as currency settings.

Store API includes formatters for:

-   [Money](#moneyformatter)
-   [Currency](#currencyformatter)
-   [HTML](#htmlformatter)

## How to use formatters

To get a formatter, you can use the `get_formatter` method of the `ExtendSchema` class. This method accepts a string, which is the name of the formatter you want to use.

```php
get_formatter('money'); // For the MoneyFormatter
get_formatter('html'); // For the HtmlFormatter
get_formatter('currency'); // CurrencyFormatter
```

This returns a `FormatterInterface` which has the `format` method. The `format` method signature is:

```php
format( $value, array $options = [] );
... (145 lines truncated)
</file>

<file path="docs/apis/store-api/extending-store-api/extend-store-api-update-cart.md">
# Updating the cart on-demand

## The problem

You're an extension developer, and your extension does some server-side processing as a result of some client-side input, i.e. a shopper filling in an input field in the Cart sidebar, and then pressing a button.

This server-side processing causes the state of the cart to change, and you want to update the data displayed in the client-side Cart or Checkout block.

You can't simply update the client-side cart state yourself. This is restricted to prevent malfunctioning extensions inadvertently updating it with malformed or invalid data which will cause the whole block to break.

## The solution

`ExtendSchema` offers the ability for extensions to register callback functions to be executed when signalled to do so by the client-side Cart or Checkout.

WooCommerce Blocks also provides a front-end function called `extensionCartUpdate` which can be called by client-side code, this will send data (specified by you when calling `extensionCartUpdate`) to the `cart/extensions` endpoint. When this endpoint gets hit, any relevant (based on the namespace provided to `extensionCartUpdate`) callbacks get executed, and the latest server-side cart data gets returned and the block is updated with this new data.

## Basic usage

In your extension's server-side integration code:

```php
add_action('woocommerce_blocks_loaded', function() {
  woocommerce_store_api_register_update_callback(
    [
      'namespace' => 'extension-unique-namespace',
      'callback'  => /* Add your callable here */
    ]
  );
} );
```
... (147 lines truncated)
</file>

<file path="docs/apis/store-api/extending-store-api/README.md">
---
sidebar_label: Extending the Store API
---
# Extending the Store API

Your application can change the way the Store API works by extending certain endpoints. It can add data to certain endpoints to make your server-side data available to the client-side.

You can also use the Store API trigger a server-side cart update from the client which will then update the client-side cart with the data returned by the API.

The documents listed below contain further details on how to achieve the above.

| Document | Description |
|----------|-------------|
| [Exposing your data](./extend-store-api-add-data/) | Explains how you can add additional data to Store API endpoints. |
| [Available extensible endpoints](./available-endpoints-to-extend/) | A list of all available endpoints to extend. |
| [Available Formatters](./extend-store-api-formatters/) | Available `Formatters` to format data for use in the Store API. |
| [Updating the cart on-demand](./extend-store-api-update-cart/) | Update the server-side cart following an action from the front-end. |
| [Adding fields and passing values](./extend-store-api-add-custom-fields/) | How to add custom fields to Store API endpoints. |
</file>

<file path="docs/apis/store-api/resources-endpoints/_category_.json">
{
    "label": "Resources and Endpoints",
    "link": {
      "type": "generated-index",
      "title": "Resources and Endpoints",
      "slug": "/apis/store-api/resources-endpoints"
    }
}
</file>

<file path="docs/apis/store-api/resources-endpoints/cart-coupons.md">
# Cart Coupons API 

## List Cart Coupons

```http
GET /cart/coupons
```

There are no parameters required for this endpoint.

```sh
curl "https://example-store.com/wp-json/wc/store/v1/cart/coupons"
```

**Example response:**

```json
[
	{
		"code": "20off",
		"type": "fixed_cart",
		"totals": {
			"currency_code": "GBP",
			"currency_symbol": "£",
			"currency_minor_unit": 2,
			"currency_decimal_separator": ".",
			"currency_thousand_separator": ",",
			"currency_prefix": "£",
			"currency_suffix": "",
			"total_discount": "1667",
... (126 lines truncated)
</file>

<file path="docs/apis/store-api/resources-endpoints/cart-items.md">
# Cart Items API

## List Cart Items

```http
GET /cart/items
```

There are no extra parameters needed to use this endpoint.

```sh
curl "https://example-store.com/wp-json/wc/store/v1/cart/items"
```

**Example response:**

```json
[
	{
		"key": "c74d97b01eae257e44aa9d5bade97baf",
		"id": 16,
		"quantity": 1,
		"type": "simple",
		"quantity_limits": {
			"minimum": 1,
			"maximum": 1,
			"multiple_of": 1,
			"editable": false
		},
		"name": "Beanie",
... (368 lines truncated)
</file>

<file path="docs/apis/store-api/resources-endpoints/cart.md">
# Cart API 

The cart API returns the current state of the cart for the current session or logged in user.

All POST endpoints require a [Nonce Token](/docs/apis/store-api/nonce-tokens) or a [Cart Token](/docs/apis/store-api/cart-tokens) and return the updated state of the full cart once complete.

## Get Cart

```http
GET /cart
```

There are no parameters required for this endpoint.

```sh
curl "https://example-store.com/wp-json/wc/store/v1/cart"
```

Returns the full cart object response (see [Cart Response](#cart-response)).

## Responses

All endpoints under `/cart` (listed in this doc) return responses in the same format; a cart object which includes cart items, applied coupons, shipping addresses and rates, and non-sensitive customer data.

### Cart Response

```json
{
	"items": [
		{
... (592 lines truncated)
</file>

<file path="docs/apis/store-api/resources-endpoints/checkout-order.md">
# Checkout order API 

The checkout order API facilitates the processing of existing orders and handling payments.

All checkout order endpoints require a [Nonce Token](/docs/apis/store-api/nonce-tokens) or a [Cart Token](/docs/apis/store-api/cart-tokens) otherwise these endpoints will return an error.

## Process Order and Payment

Accepts the final chosen payment method, and any additional payment data, then attempts payment and
returns the result.

```http
POST /wc/store/v1/checkout/{ORDER_ID}
```

| Attribute          | Type   | Required | Description                                                         |
| :----------------- | :----- | :------: | :------------------------------------------------------------------ |
| `key`              | string |   Yes    | The key for the order verification.                                 |
| `billing_email`    | string |   No     | The email address used to verify guest orders.                      |
| `billing_address`  | object |   Yes    | Object of updated billing address data for the customer.            |
| `shipping_address` | object |   Yes    | Object of updated shipping address data for the customer.           |
| `payment_method`   | string |   Yes    | The ID of the payment method being used to process the payment.     |
| `payment_data`     | array  |    No    | Data to pass through to the payment method when processing payment. |

```sh
curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/checkout/{ORDER_ID} -d '{"key":"wc_order_oFmQYREzh9Tfv","billing_email":"admin@example.com","payment_method":"cheque","billing_address":{...},"shipping_address":{...}'
```

**Example request:**

... (120 lines truncated)
</file>

<file path="docs/apis/store-api/resources-endpoints/checkout.md">
# Checkout API 

The checkout API facilitates the creation of orders (from the current cart) and handling payments for payment methods.

All checkout endpoints require either a [Nonce Token](/docs/apis/store-api/nonce-tokens) or a [Cart Token](/docs/apis/store-api/cart-tokens) otherwise these endpoints will return an error.

## Get Checkout Data

Returns data required for the checkout. This includes a draft order (created from the current cart) and customer billing and shipping addresses. The payment information will be empty, as it's only persisted when the order gets updated via POST requests (right before payment processing).

```http
GET /wc/store/v1/checkout
```

There are no parameters required for this endpoint.

```sh
curl --header "Nonce: 12345" --request GET https://example-store.com/wp-json/wc/store/v1/checkout
```

### Example Response

```json
{
  "order_id": 146,
  "status": "checkout-draft",
  "order_key": "wc_order_VPffqyvgWVqWL",
  "customer_note": "",
  "customer_id": 1,
  "billing_address": {
... (262 lines truncated)
</file>

<file path="docs/apis/store-api/resources-endpoints/order.md">
# Order API 

The order API returns the pay-for-order order.

## Get Order

```http
GET /order/{ORDER_ID}?key={KEY}&billing_email={BILLING_EMAIL}
```

There is one required parameter for this endpoint which is `key`. `billing_email` must be added for guest orders.

```sh
curl "https://example-store.com/wp-json/wc/store/v1/order/{ORDER_ID}?key={KEY}&billing_email={BILLING_EMAIL}"
```

Returns the full order object response (see [Order Response](#order-response)).

## Responses

Order endpoints return responses in the same format as `/cart`; an order object which includes order items, applied coupons, shipping addresses and rates, and non-sensitive customer data.

One difference worth calling out is `item_data`. Order items carry stored order item metadata; cart items carry display data from the `woocommerce_get_item_data` filter. Both are lists, but the entries hold different properties. See [Item data](#item-data).

### Order Response

```json
{
	"id": 147,
	"status": "pending",
... (235 lines truncated)
</file>

<file path="docs/apis/store-api/resources-endpoints/product-attribute-terms.md">
# Product Attribute Terms API

```http
GET /products/attributes/:id/terms
GET /products/attributes/:id/terms?orderby=slug
```

| Attribute               | Type    | Required | Description                                                                                                   |
| :---------------------- | :------ | :------: | :------------------------------------------------------------------------------------------------------------ |
| `id`                    | integer |   Yes    | The ID of the attribute to retrieve terms for.                                                                |
| `order`                 | string  |    no    | Order ascending or descending. Allowed values: `asc`, `desc`                                                  |
| `orderby`               | string  |    no    | Sort collection by object attribute. Allowed values: `id`, `name`, `name_num`, `slug`, `count`, `menu_order`. |
| `__experimental_visual` | boolean |    no    | If true, include experimental visual swatch data for `wc-visual` attribute terms.                             |

## Visual response fields

The following fields are included only when `__experimental_visual=true` is passed for `wc-visual` attribute terms.
Other attribute types keep the default term response without `__experimentalVisual`.

| Attribute                    | Type   | Description                                                                                                    |
| :--------------------------- | :----- | :------------------------------------------------------------------------------------------------------------- |
| `__experimentalVisual`       | object | Experimental visual swatch data for `wc-visual` attribute terms.                                               |
| `__experimentalVisual.type`  | string | Visual swatch type. Allowed values: `color`, `image`, `none`.                                                  |
| `__experimentalVisual.value` | string | Visual swatch value. Returns a hex color for `color`, an image URL for `image`, or an empty string for `none`. |

```sh
curl "https://example-store.com/wp-json/wc/store/v1/products/attributes/1/terms?__experimental_visual=true"
```

**Example response for visual attribute terms:**
... (45 lines truncated)
</file>

<file path="docs/apis/store-api/resources-endpoints/product-attributes.md">
# Product Attributes API 

## List Product Attributes

```http
GET /products/attributes
```

There are no parameters required for this endpoint.

```sh
curl "https://example-store.com/wp-json/wc/store/v1/products/attributes"
```

Example response:

```json
[
	{
		"id": 1,
		"name": "Color",
		"taxonomy": "pa_color",
		"type": "select",
		"order": "menu_order",
		"has_archives": false
	},
	{
		"id": 2,
		"name": "Size",
		"taxonomy": "pa_size",
... (36 lines truncated)
</file>

<file path="docs/apis/store-api/resources-endpoints/product-brands.md">
# Product Brands API 

## List Product Brands

```http
GET /products/brands
```

| Attribute    | Type    | Required | Description                                                                                                           |
| :----------- | :------ | :------: | :-------------------------------------------------------------------------------------------------------------------- |
| `context`    | string  |    No    | Scope under which the request is made; determines fields present in response.                                         |
| `page`       | integer |    No    | Current page of the collection. Defaults to `1`.                                                                      |
| `per_page`   | integer |    No    | Maximum number of items to be returned in result set. Defaults to no limit. Values between `0` and `100` are allowed. |
| `search`     | string  |    No    | Limit results to those matching a string.                                                                             |
| `exclude`    | array   |    No    | Ensure result set excludes specific IDs.                                                                              |
| `include`    | array   |    No    | Limit result set to specific IDs.                                                                                     |
| `order`      | string  |    No    | Sort ascending or descending. Allowed values: `asc`, `desc`. Defaults to `asc`.                                       |
| `orderby`    | string  |    No    | Sort by term property. Allowed values: `name`, `slug`, `count`. Defaults to `name`.                                   |
| `hide_empty` | boolean |    No    | If true, empty terms will not be returned. Defaults to `true`.                                                        |
| `parent`     | integer |    No    | Limit results to those with a specific parent ID.                                                                     |

```sh
curl "https://example-store.com/wp-json/wc/store/v1/products/brands"
```

Example response:

```json
[
	{
... (76 lines truncated)
</file>

<file path="docs/apis/store-api/resources-endpoints/product-categories.md">
# Product Categories API 

## List Product Categories

```http
GET /products/categories
```

| Attribute    | Type    | Required | Description                                                                                                           |
| :----------- | :------ | :------: | :-------------------------------------------------------------------------------------------------------------------- |
| `context`    | string  |    No    | Scope under which the request is made; determines fields present in response.                                         |
| `page`       | integer |    No    | Current page of the collection. Defaults to `1`.                                                                      |
| `per_page`   | integer |    No    | Maximum number of items to be returned in result set. Defaults to no limit. Values between `0` and `100` are allowed. |
| `search`     | string  |    No    | Limit results to those matching a string.                                                                             |
| `exclude`    | array   |    No    | Ensure result set excludes specific IDs.                                                                              |
| `include`    | array   |    No    | Limit result set to specific IDs.                                                                                     |
| `order`      | string  |    No    | Sort ascending or descending. Allowed values: `asc`, `desc`. Defaults to `asc`.                                       |
| `orderby`    | string  |    No    | Sort by term property. Allowed values: `name`, `slug`, `count`. Defaults to `name`.                                   |
| `hide_empty` | boolean |    No    | If true, empty terms will not be returned. Defaults to `true`.                                                        |
| `parent`     | integer |    No    | Limit results to those with a specific parent ID.                                                                     |

```sh
curl "https://example-store.com/wp-json/wc/store/v1/products/categories"
```

Example response:

```json
[
	{
... (64 lines truncated)
</file>

<file path="docs/apis/store-api/resources-endpoints/product-collection-data.md">
# Product Collection Data API

This endpoint allows you to get aggregate data from a collection of products, for example, the min and max price in a collection of products (ignoring pagination). This is used by blocks for product filtering widgets, since counts are based on the product catalog being viewed.

```http
GET /products/collection-data
GET /products/collection-data?calculate_price_range=true
GET /products/collection-data?calculate_attribute_counts[0][query_type]=or&calculate_attribute_counts[0][taxonomy]=pa_color
GET /products/collection-data?calculate_rating_counts=true
GET /products/collection-data?calculate_taxonomy_counts=product_cat
```

| Attribute                       | Type   | Required | Description                                                                                                                                                                                                |
| :------------------------------ | :----- | :------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `calculate_price_range`         | bool   |    No    | Returns the min and max price for the product collection. If false, only `null` will be returned.                                                                                                          |
| `calculate_attribute_counts`    | object |    No    | Returns attribute counts for a list of attribute taxonomies you pass in via this parameter. Each should be provided as an object with keys "taxonomy" and "query_type". If empty, `null` will be returned. |
| `calculate_rating_counts`       | bool   |    No    | Returns the counts of products with a certain average rating, 1-5. If false, only `null` will be returned.                                                                                                 |
| `calculate_stock_status_counts` | bool   |    No    | Returns counts of products with each stock status (in stock, out of stock, on backorder). If false, only `null` will be returned.                                                                         |
| `calculate_taxonomy_counts`     | array  |    No    | Returns taxonomy counts for a list of taxonomies you pass in via this parameter. Each should be provided as a taxonomy name string. If empty, `null` will be returned.                                 |


**In addition to the above attributes**, all product list attributes are supported. This allows you to get data for a certain subset of products. See [the products API list products section](/docs/apis/store-api/resources-endpoints/products#list-products) for the full list.

```sh
curl "https://example-store.com/wp-json/wc/store/v1/products/collection-data?calculate_price_range=true&calculate_attribute_counts=pa_size,pa_color&calculate_rating_counts=true&calculate_taxonomy_counts=product_cat,product_tag"
```

**Example response:**

```json
... (54 lines truncated)
</file>

<file path="docs/apis/store-api/resources-endpoints/product-reviews.md">
# Product Reviews API 

## List Product Reviews

This endpoint returns product reviews (comments) and can also show results from either specific products or specific categories.

```http
GET /products/reviews
GET /products/reviews?category_id=1,2,3
GET /products/reviews?product_id=1,2,3
GET /products/reviews?orderby=rating&order=desc
```

| Attribute     | Type    | Required | Description                                                                                         |
| :------------ | :------ | :------: | :-------------------------------------------------------------------------------------------------- |
| `page`        | integer |    no    | Current page of the collection.                                                                     |
| `per_page`    | integer |    no    | Maximum number of items to be returned in result set.                                               |
| `offset`      | integer |    no    | Offset the result set by a specific number of items.                                                |
| `order`       | string  |    no    | Order sort attribute ascending or descending. Allowed values: `asc`, `desc`                         |
| `orderby`     | string  |    no    | Sort collection by object attribute. Allowed values : `date`, `date_gmt`, `id`, `rating`, `product` |
| `category_id` | string  |    no    | Limit result set to reviews from specific category IDs.                                             |
| `product_id`  | string  |    no    | Limit result set to reviews from specific product IDs.                                              |

```sh
curl "https://example-store.com/wp-json/wc/store/v1/products/collection-data?calculate_price_range=true&calculate_attribute_counts=pa_size,pa_color&calculate_rating_counts=true"
```

**Example response:**

```json
... (39 lines truncated)
</file>

<file path="docs/apis/store-api/resources-endpoints/product-tags.md">
# Product Tags API 

## List Product Tags

```http
GET /products/tags
```

| Attribute    | Type    | Required | Description                                                                                                           |
| :----------- | :------ | :------: | :-------------------------------------------------------------------------------------------------------------------- |
| `context`    | string  |    No    | Scope under which the request is made; determines fields present in response.                                         |
| `page`       | integer |    No    | Current page of the collection. Defaults to `1`.                                                                      |
| `per_page`   | integer |    No    | Maximum number of items to be returned in result set. Defaults to no limit. Values between `0` and `100` are allowed. |
| `search`     | string  |    No    | Limit results to those matching a string.                                                                             |
| `exclude`    | array   |    No    | Ensure result set excludes specific IDs.                                                                              |
| `include`    | array   |    No    | Limit result set to specific IDs.                                                                                     |
| `order`      | string  |    No    | Sort ascending or descending. Allowed values: `asc`, `desc`. Defaults to `asc`.                                       |
| `orderby`    | string  |    No    | Sort by term property. Allowed values: `name`, `slug`, `count`. Defaults to `name`.                                   |
| `hide_empty` | boolean |    No    | If true, empty terms will not be returned. Defaults to `true`.                                                        |

```sh
curl "https://example-store.com/wp-json/wc/store/v1/products/tags"
```

Example response:

```json
[
	{
		"id": 1,
... (17 lines truncated)
</file>

<file path="docs/apis/store-api/resources-endpoints/products.md">
# Products API 

The store products API provides public product data so it can be rendered on the client side.

## Product Visibility

### Draft and non-published products

Only published products are accessible via the Store API. Requesting a draft, pending, or other non-published product by ID or slug returns a `404` error. Non-published products are also excluded from the collection endpoint.

### Password-protected products

Password-protected products, including variations whose parent product is password-protected, are visible in the API, but their `description` and `short_description` fields are redacted (returned as empty strings) until the correct password has been submitted.

The `is_password_protected` field indicates whether the product or its parent has a configured password. It remains `true` after the current visitor has submitted the correct password and the descriptions become accessible.

Password verification uses WordPress's native `wp-postpass_*` cookie, set when a user submits the password form on the frontend. The Store API does not accept passwords directly.

Other product data (price, images, categories, etc.) remains accessible regardless of password status.

## List Products

```http
GET /products
GET /products?search=product%20name
GET /products?slug=slug-1,slug-2
GET /products?after=2017-03-22&date_column=date
GET /products?before=2017-03-22&date_column=date
GET /products?exclude=10,44,33
GET /products?include=10,44,33
... (320 lines truncated)
</file>

<file path="docs/apis/store-api/cart-tokens.md">
---
sidebar_label: Cart Tokens
sidebar_position: 3
---

# Cart Tokens 

Cart tokens can be used instead of cookies based sessions for headless interaction with carts. When using a `Cart-Token` a  [Nonce Token](/docs/apis/store-api/nonce-tokens) is not required.

## Obtaining a Cart Token

Requests to `/cart` endpoints return a `Cart-Token` header alongside the response. This contains a token which can later be sent as a request header to the Store API Cart and Checkout endpoints to identify the cart.

The quickest method of obtaining a Cart Token is to make a GET request `/wp-json/wc/store/v1/cart` and observe the response headers. You should see a `Cart-Token` header there.

## How to use a Cart-Token

To use a `Cart-Token`, include it as a header with your request. The response will contain the current cart state from the session associated with the `Cart-Token`.

**Example:**

```sh
curl --header "Cart-Token: 12345" --request GET https://example-store.com/wp-json/wc/store/v1/cart
```

The same method will allow you to checkout using a `Cart-Token` on the `/checkout` route.
</file>

<file path="docs/apis/store-api/guiding-principles.md">
---
sidebar_label: Guiding principles  
sidebar_position: 0
---

# Store API Guiding principles 

The following principles should be considered when extending, creating, or updating endpoints in the Store API.

## Routes must include a [well-defined JSON schema](https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/)

Each route/endpoint requires a particular structure of input data and should return data using a defined and predictable structure. This is defined in the JSON schema, which contains a comprehensive list of all of the properties the API can return and which input parameters it can accept.

Well-defined schema also provides a layer of security, as it enables us to validate and sanitize the requests being made to the API.

When defining schema, take note of the [WordPress REST API handbook](https://developer.wordpress.org/rest-api/extending-the-rest-api/schema/) which documents available properties and types, as well as the [JSON schema standard](http://json-schema.org/). In addition to this:

* Properties should use snake_case 🐍
* Ambiguous terms should be avoided, and property names should try to use understandable language, rather than "WooCommerce" terminology or setting names
* Properties should be defined using US English, but the descriptions of fields should be localized
* Multiple types are permitted, for example, using a `null` type if a value is not applicable
* `sanitize_callback` and `validate_callback` are encouraged where possible to ensure data is received in the correct format before processing requests

If you’re struggling to define a consistent schema, your approach may be flawed. A common real-world example of this would be representing something like _Post Tags_. It may be tempting to use the Slug as the property field name in the response:

```php
tags: [
  "my-tag": {
    // ...tag data
  },
... (97 lines truncated)
</file>

<file path="docs/apis/store-api/nonce-tokens.md">
---
sidebar_position: 1
---

# Nonce Tokens 

Nonces are generated numbers used to verify origin and intent of requests for security purposes. You can read more about [nonces in the WordPress codex](https://developer.wordpress.org/apis/security/nonces/).

## Store API Endpoints that Require Nonces

POST requests to the `/cart` endpoints and all requests to the `/checkout` endpoints require a nonce to function. Failure to provide a valid nonce will return an error response, unless you're using [Cart Tokens](/docs/apis/store-api/cart-tokens) instead.

## Sending Nonce Tokens with requests

Nonce tokens are included with the request headers. Create a request header named `Nonce`. This will be validated by the API.

**Example:**

```sh
curl --header "Nonce: 12345" --request GET https://example-store.com/wp-json/wc/store/v1/checkout
```

After making a successful request, an updated `Nonce` header will be sent back--this needs to be stored and updated by the client to make subsequent requests.

## Generating security nonces from WordPress

Nonces must be created using the [`wp_create_nonce` function](https://developer.wordpress.org/reference/functions/wp_create_nonce/) with the key `wc_store_api`.

```php
wp_create_nonce( 'wc_store_api' )
... (16 lines truncated)
</file>

<file path="docs/apis/store-api/rate-limiting.md">
---
sidebar_label: Rate Limiting 
sidebar_position: 4
---

# Rate Limiting for Store API endpoints 

[Rate Limiting](https://github.com/woocommerce/woocommerce-blocks/pull/5962) is available for Store API endpoints. This is optional and disabled by default. It can be enabled by following [these instructions](#rate-limiting-options-filter).

The main purpose prevent abuse on endpoints from excessive calls and performance degradation on the machine running the store.

Rate limit tracking is controlled by either `USER ID` (logged in), `IP ADDRESS` (unauthenticated requests) or filter defined logic to fingerprint and group requests.

It also offers standard support for running behind a proxy, load balancer, etc. This also optional and disabled by default.

## UI Control

Currently, this feature is only controlled via the `woocommerce_store_api_rate_limit_options` filter. To control it via a UI, you can use the following community plugin: [Rate Limiting UI for WooCommerce](https://wordpress.org/plugins/rate-limiting-ui-for-woocommerce/).

## Checkout rate limiting

You can enable rate limiting for Checkout place order and `POST /checkout` endpoint only via the UI by going to WooCommerce -> Settings -> Advanced -> Features and enabling "Rate limiting Checkout block and Store API".

When enabled via the UI, the rate limiting will only be applied to the `POST /checkout` and Place Order flow for Checkout block. The limit will be a maximum of 3 requests per 60 seconds.

## Limit information

A default maximum of 25 requests can be made within a 10-second time frame. These can be changed through an [options filter](#rate-limiting-options-filter).

## Methods restricted by Rate Limiting
... (75 lines truncated)
</file>

<file path="docs/apis/store-api/README.md">
---
sidebar_label: Store API 
category_slug: store-api
post_title: Store API
---

# WooCommerce Store API

**The Store API provides public Rest API endpoints for the development of customer-facing cart, checkout, and product functionality. It follows many of the patterns used in the [WordPress REST API](https://developer.wordpress.org/rest-api/key-concepts/).**

In contrast to the WooCommerce REST API, the Store API is unauthenticated and does not provide access to sensitive store data or other customer information.

Example of a valid API request using cURL:

```sh
curl "https://example-store.com/wp-json/wc/store/v1/products"
```

Possible uses of the Store API include:

1. Obtaining a list of products to display that can be searched or filtered
2. Adding products to the cart and returning an updated cart object for display
3. Obtaining shipping rates for a cart
4. Converting a customer’s cart to an Order, collecting addresses, and then facilitating payment

## Requirements and limitations

* This is an unauthenticated API. It does not require API keys or authentication tokens for access.
* All API responses return JSON-formatted data.
* Data returned from the API is reflective of the current user (customer). Customer sessions in WooCommerce are cookie-based.
... (136 lines truncated)
</file>

<file path="docs/apis/_category_.json">
{
  "customProps" : {
    "id" : "apis"
  }
}
</file>

<file path="docs/apis/README.md">
---
post_title: 'Getting Started with WooCommerce APIs'
sidebar_label: 'Getting started'
sidebar_position: 0
---

# Getting Started with WooCommerce APIs

WooCommerce provides a number of programmatic APIs to interact with WooCommerce store data.

## WC REST API

The WC REST API is a powerful part of WooCommerce which lets you read and write various parts of WooCommerce data such as orders, products, coupons, customers, and shipping zones. It based on the [WordPress REST API](https://developer.wordpress.org/rest-api/).

Explore the [WC REST API](./rest-api/) documentation.

## Store API

The Store API provides public REST API endpoints for the development of customer-facing cart, checkout, and product functionality. In contrast to the WooCommerce REST API, the Store API is unauthenticated and does not provide access to sensitive store data or other customer information.

Explore the [Store API](./store-api/README.md) documentation.

## Dual API (code + GraphQL, experimental)

The dual API is an experimental, code-first API architecture: you write plain PHP classes (the code API) and a build script generates a matching GraphQL endpoint from them. The engine is provided by the WooCommerce Dual API plugin, and any plugin can use it to build its own dual API.

Explore the [Dual API](./dual-api/README.md) documentation.

## Other Resources

... (34 lines truncated)
</file>

<file path="docs/best-practices/coding-standards/coding-standards.md">
---
post_title: WooCommerce coding standards
sidebar_label: Coding standards

---

# WooCommerce coding standards

Adhering to WooCommerce coding standards is essential for maintaining high code quality, ensuring compatibility, and facilitating easier maintenance and updates. This document outlines the recommended coding practices for developers working within the WooCommerce ecosystem, including the use of hooks, function prefixing, translatable texts, and code structure.


## Position of hooks

Position hooks below the function call to align with the common pattern in the WordPress and WooCommerce ecosystem.

Example:

```php
/**
 * Add custom message.
 */
function YOUR_PREFIX_custom_message() {
    echo 'This is a custom message';
}
add_action( 'wp_footer', 'YOUR_PREFIX_custom_message' );
```

## Prefixing function calls

Use a consistent prefix for all function calls to avoid conflicts. For the code snippets in this repo, use `YOUR_PREFIX`.
... (70 lines truncated)
</file>

<file path="docs/best-practices/coding-standards/css-sass-naming-conventions.md">
---
post_title: CSS/Sass naming conventions
---

# CSS/Sass naming conventions

## Introduction

Our guidelines are based on those used in [Calypso](https://github.com/Automattic/wp-calypso), which itself follows the [BEM methodology](https://getbem.com/).

Refer to the [Calypso CSS/Sass Coding Guidelines](https://wpcalypso.wordpress.com/devdocs/docs/coding-guidelines/css.md) for full details.

Read more about [BEM key concepts](https://en.bem.info/methodology/key-concepts/).

There are a few differences in WooCommerce which are outlined below.

## Prefixing

As a WordPress plugin WooCommerce has to play nicely with WordPress core and other plugins/themes. To minimize conflict potential, all classes should be prefixed with `.woocommerce-`.

## Class names

When naming classes, remember:

- **Block** - Standalone entity that is meaningful on its own. Such as the name of a component.
- **Element** - Parts of a block and have no standalone meaning. They are semantically tied to its block.
- **Modifier** - Flags on blocks or elements. Use them to change appearance or behavior.

### Example

... (29 lines truncated)
</file>

<file path="docs/best-practices/coding-standards/grammar-punctuation-capitalization.md">
---
post_title: WooCommerce grammar, punctuation and capitalization guide
sidebar_label: Grammar, punctuation and capitalization

---

# WooCommerce grammar, punctuation and capitalization guide

Following grammar, punctuation and style guidelines helps keep our presentation consistent. Users have a better experience if they know what to expect and where to find the information they need.

## Basics

**Be democratic**. Some people read every word. Some scan and search or prefer video. Help everyone.

**Be focused**. Lead with the most important information in sentences, paragraphs, and sections.

**Be concise**. Use plain language and brief sentences.

**Be consistent**. Follow our guidelines and style tips.

**Be specific**. Communicate crystal clear. Trim the fat.

## Guidelines

### Abbreviations and acronyms

Spell out the full version on first mention with abbreviation or acronym in parentheses. Use the short version on second and consecutive mentions.

- First use: Payment Card Industry Data Security Standard (PCI-DSS)
- Second use: PCI-DSS
... (299 lines truncated)
</file>

<file path="docs/best-practices/coding-standards/naming-conventions.md">
---
post_title: Naming conventions
sidebar_label: Naming conventions

---

# Naming conventions

## PHP

WooCommerce core generally follows [WordPress PHP naming conventions](https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#naming-conventions). 

There are some additional conventions that apply, depending on the location of the code.

### `/src`

Classes defined inside `/src` follow the [PSR-4](https://www.php-fig.org/psr/psr-4/) standard. See the [README for `/src`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/README.md) for more information.

The following conventions apply to this directory:

- No class name prefix is needed, as all classes in this location live within the `Automattic\WooCommerce` namespace.
- Classes are named using `CamelCase` convention.
- Functions are named using `snake_case` convention.
- Class file names should match the class name. They do not need a `class-` prefix.
- The namespace should match the directory structure.
- Hooks are prefixed with `woocommerce_`.
- Hooks are named using `snake_case` convention.

For example, the class defined in `src/Util/StringUtil.php` should be named `StringUtil` and should be in the `Automattic\WooCommerce\Util` namespace.  

... (57 lines truncated)
</file>

<file path="docs/best-practices/data-management/_category_.json">
{
    "position": 5,
    "label": "Data management",
    "link": {
        "type": "generated-index",
        "title": "Data management",
        "slug": "/best-practices/data-management"
    }
}
</file>

<file path="docs/best-practices/data-management/crud-objects.md">
---
post_title: Developing using WooCommerce CRUD objects
sidebar_label: Using CRUD objects

---

# Developing using WooCommerce CRUD objects

CRUD is an abbreviation of the four basic operations you can do to a database or resource - Create, Read, Update, Delete.

[WooCommerce 3.0 introduced CRUD objects](https://woocommerce.wordpress.com/2016/10/27/the-new-crud-classes-in-woocommerce-2-7/) for working with WooCommerce data. **Whenever possible these objects should be used in your code instead of directly updating metadata or using WordPress post objects.**

Each of these objects contains a schema for the data it controls (properties), a getter and setter for each property, and a save/delete method which talks to a data store. The data store handles the actual saving/reading from the database. The object itself does not need to be aware of where the data is stored.

## The benefits of CRUD

* Structure - Each object has a pre-defined structure and keeps its own data valid.
* Control - We control the flow of data, and any validation needed, so we know when changes occur.
* Ease of development - As a developer, you don't need to know the internals of the data you're working with, just the names.
* Abstraction - The data can be moved elsewhere, e.g. custom tables, without affecting existing code.
* Unification - We can use the same code for updating things in admin as we do in the REST API and CLIs. Everything is unified.
* Simplified code - Less procedural code to update objects which reduces likelihood of malfunction and adds more unit test coverage.

## CRUD object structure

The [`WC_Data`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/includes/abstracts/abstract-wc-data.php) class is the basic implementation for CRUD objects, and all CRUD objects extend it. The most important properties to note are `$data`, which is an array of props supported in each object, and `$id`, which is the object's ID.

The [coupon object class](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/includes/class-wc-coupon.php) is a good example of extending `WC_Data` and adding CRUD functions to all properties.

### Data
... (188 lines truncated)
</file>

<file path="docs/best-practices/data-management/data-storage.md">
---
post_title: Data storage primer
sidebar_label: Data storage

---

# Data storage primer

When developing for WordPress and WooCommerce, it's important to consider the nature and permanence of your data. This will help you decide the best way to store it. Here's a quick primer:

## Transients

If the data may not always be present (i.e., it expires), use a [transient](https://developer.wordpress.org/apis/handbook/transients/). Transients are a simple and standardized way of storing cached data in the database temporarily by giving it a custom name and a timeframe after which it will expire and be deleted.

## WP Cache

If the data is persistent but not always present, consider using the [WP Cache](https://developer.wordpress.org/reference/classes/wp_object_cache/). The WP Cache functions allow you to cache data that is computationally expensive to regenerate, such as complex query results.

## wp_options Table

If the data is persistent and always present, consider the [wp_options table](https://developer.wordpress.org/apis/handbook/options/). The Options API is a simple and standardized way of storing data in the wp_options table in the WordPress database.

## Post Types

If the data type is an entity with n units, consider a [post type](https://developer.wordpress.org/post_type/). Post types are "types" of content that are stored in the same way, but are easy to distinguish in the code and UI.

## Taxonomies

If the data is a means of sorting/categorizing an entity, consider a [taxonomy](https://developer.wordpress.org/taxonomy/). Taxonomies are a way of grouping things together.

... (6 lines truncated)
</file>

<file path="docs/best-practices/data-management/data-stores.md">
---
post_title: How to manage WooCommerce Data Stores
sidebar_label: Manage data stores
description: A guide to managing WooCommerce data stores, including creating new data stores, replacing core data stores, and calling data stores from your own code.
---

# How to manage WooCommerce Data Stores

## Introduction

Data store classes act as a bridge between WooCommerce's data CRUD classes (`WC_Product`, `WC_Order`, `WC_Customer`, etc) and the database layer. With the database logic separate from data, WooCommerce becomes more flexible. The data stores shipped with WooCommerce core (powered by WordPress' custom posts system and some custom tables) can be swapped out for a different database structure, type, or even be powered by an external API.

This guide will walk through the structure of a data store class, how to create a new data store, how to replace a core data store, and how to call a data store from your own code.

The examples in this guide will look at the [`WC_Coupon`](https://github.com/woocommerce/woocommerce/blob/dcecf0f22890f3cd92fbea13a98c11b2537df2a8/includes/class-wc-coupon.php#L19) CRUD data class and [`WC_Coupon_Data_Store_CPT`](https://github.com/woocommerce/woocommerce/blob/dcecf0f22890f3cd92fbea13a98c11b2537df2a8/includes/data-stores/class-wc-coupon-data-store-cpt.php), an implementation of a coupon data store using WordPress custom post types. This is how coupons are currently stored in WooCommerce.

The important thing to know about `WC_Coupon` or any other CRUD data class when working with data stores is which props (properties) they contain. This is defined in the [`data`](https://github.com/woocommerce/woocommerce/blob/dcecf0f22890f3cd92fbea13a98c11b2537df2a8/includes/class-wc-coupon.php#L26) array of each class.

## Structure

Every data store for a CRUD object should implement the `WC_Object_Data_Store_Interface` interface.

`WC_Object_Data_Store_Interface` includes the following methods:

* `create`
* `read`
* `update`
* `delete`
* `read_meta`
* `delete_meta`
... (294 lines truncated)
</file>

<file path="docs/best-practices/data-management/logging.md">
---
post_title: Logging in WooCommerce
sidebar_label: Logging
---

# Logging in WooCommerce

WooCommerce has its own robust system for logging, which can be used for debugging during development, catching errors on production, or even sending notifications when specific events occur. By default, WooCommerce uses this logger to record errors, warnings, and other notices that may be useful for troubleshooting problems with a store. Many extensions for WooCommerce also make use of the logger for similar purposes.

## Viewing logs

You can view the entries created by the logger by going to **WooCommerce > Status > Logs**. The log viewing interface depends on which log storage method is configured (see the "Configuring the logger" section below).

### File system

With the default file system storage method, the first thing you will see is the list of existing log files:

![The default log viewing interface, showing a list of log files](/img/doc_images/file-browse.png)

The name of a log file is based on the source of the entries it contains (meaning the extension or the part of the WooCommerce codebase), as well as the date the entries were generated. In this file browsing view, you can sort the files in different ways as well as filtering them to show only those from a specific source. Clicking on a file will take you to a single file view, where you can see the actual log entries:

![The contents of a log file](/img/doc_images/file-view-new.png)

Click on a line number in the file to highlight it. This can also be used to link to a specific line in a file from elsewhere.

From the file browser view, you can sort and filter a list of log files, and then search for a string within the contents of those files:

![A list of search results](/img/doc_images/search-results.png)

Clicking on a search result line number will take you to that line in the single file view.
... (187 lines truncated)
</file>

<file path="docs/best-practices/performance/_category_.json">
{
    "position": 2,
    "label": "Performance",
    "link": {
        "type": "generated-index",
        "title": "Performance",
        "slug": "/best-practices/performance"
    }
}
</file>

<file path="docs/best-practices/performance/configuring-caching-plugins.md">
---
post_title: How to configure caching plugins for WooCommerce
sidebar_label: Configure caching plugins
description: A guide to configuring caching plugins for WooCommerce to ensure proper functionality and performance.
---

# How to configure caching plugins for WooCommerce

## Excluding pages from the cache

Oftentimes if using caching plugins they'll already exclude these pages. Otherwise make sure you exclude the following pages from the cache through your caching systems respective settings.

- Cart
- My Account
- Checkout

These pages need to stay dynamic since they display information specific to the current customer and their cart.

## Excluding WooCommerce session from the cache

If the caching system you're using offers database caching, it might be helpful to exclude `_wc_session_` from being cached. This will be dependent on the plugin or host caching so refer to the specific instructions or docs for that system.

## Excluding WooCommerce cookies from the cache

Cookies in WooCommerce help track the products in your customers cart, can keep their cart in the database if they leave the site, and powers the recently viewed widget. Below is a list of the cookies WooCommerce uses for this, which you can exclude from caching.

| COOKIE NAME | DURATION | PURPOSE |
| --- | --- | --- |
| woocommerce_cart_hash | session | Helps WooCommerce determine when cart contents/data changes. |
| woocommerce_items_in_cart | session | Helps WooCommerce determine when cart contents/data changes. |
... (76 lines truncated)
</file>

<file path="docs/best-practices/performance/performance-best-practices.md">
---
post_title: WooCommerce performance best practices
sidebar_label: Performance best practices
description: Best practices for optimizing the performance of WooCommerce stores and extensions.
---

# Performance best practices for WooCommerce extensions

Optimizing the performance of WooCommerce extensions is vital for ensuring that online stores run smoothly, provide a superior user experience, and rank well in search engine results. This guide is tailored for developers looking to enhance the speed and efficiency of their WooCommerce extensions, with a focus on understanding performance impacts, benchmarking, testing, and implementing strategies for improvement.

## Performance optimization

For WooCommerce extensions, performance optimization means ensuring that your code contributes to a fast, responsive user experience without adding unnecessary load times or resource usage to the store.

### Why performance is critical

- **User Experience**: Fast-performing extensions contribute to a seamless shopping experience, encouraging customers to complete purchases.
- **Store Performance**: Extensions can significantly impact the overall speed of WooCommerce stores; optimized extensions help maintain optimal site performance.
- **SEO and Conversion Rates**: Speed is a critical factor for SEO rankings and conversion rates. Efficient extensions support better store rankings and higher conversions.

## Benchmarking performance

Setting clear performance benchmarks is essential for development and continuous improvement of WooCommerce extensions. A recommended performance standard is achieving a Chrome Core Web Vitals "Performance" score of 90 or above on a simple Woo site, using tools like the [Chrome Lighthouse](https://developer.chrome.com/docs/lighthouse/overview/).

### Using accessible tools for benchmarking

Chrome Lighthouse provides a comprehensive framework for evaluating the performance of web pages, including those impacted by your WooCommerce extension. By integrating Lighthouse testing into your development workflow, you can identify and address performance issues early on.

We recommend leveraging tools like this to assess the impact of your extension on a WooCommerce store's performance and to identify areas for improvement.

... (13 lines truncated)
</file>

<file path="docs/best-practices/performance/performance-optimization.md">
---
post_title: How to optimize performance for WooCommerce stores
sidebar_label: Optimize store performance
description: Best practices and techniques for optimizing the performance of WooCommerce stores, including caching, image optimization, database maintenance, code minification, and the use of Content Delivery Networks (CDNs).
---

# How to optimize performance for WooCommerce stores

## Introduction

This guide covers best practices and techniques for optimizing the performance of WooCommerce stores, including caching, image optimization, database maintenance, code minification, and the use of Content Delivery Networks (CDNs). By following these recommendations, developers can build high-performing WooCommerce stores that provide a better user experience and contribute to higher conversion rates.

## Audience

This guide is intended for developers who are familiar with WordPress and WooCommerce and want to improve the performance of their online stores.

## Prerequisites

To follow this guide, you should have:

1. A basic understanding of WordPress and WooCommerce.
2. Access to a WordPress website with WooCommerce installed and activated.

## Step 1 - Implement caching

Caching plays a crucial role in speeding up your WooCommerce store by serving static versions of your pages to visitors, reducing the load on your server. There are several ways to implement caching for your WooCommerce store:

### Server-Side caching

Enable server-side caching through your hosting provider or by using server-level caching solutions like Varnish, NGINX FastCGI Cache, or Redis.
... (66 lines truncated)
</file>

<file path="docs/best-practices/security/_category_.json">
{
    "position": 3,
    "label": "Security",
    "link": {
        "type": "generated-index",
        "title": "Security",
        "slug": "/best-practices/security"
    }
}
</file>

<file path="docs/best-practices/security/prevent-data-leaks.md">
---
post_title: How to prevent data leaks in WooCommerce
sidebar_label: Prevent data leaks

---

# How to Prevent Data Leaks in WooCommerce

Data leaks can expose sensitive information and compromise the security of a WooCommerce site. One common source of data leaks is direct access to PHP files. This tutorial will show you how to prevent these kinds of data leaks.

In each PHP file of your WooCommerce extension, you should check if a constant called 'ABSPATH' is defined. This constant is defined by WordPress itself, and it's not defined if a file is being accessed directly. Here's how you can do this:

```php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
```

With this code, if someone tries to access the PHP file directly, the 'ABSPATH' constant won't be defined, and the script will exit before any sensitive data can be leaked.

Remember, security is a crucial aspect of any WooCommerce site. Always take steps to prevent data leaks and protect your site's information.
</file>

<file path="docs/best-practices/security/security-best-practices.md">
---
post_title: WooCommerce security best practices
sidebar_label: Security best practices

---

# WooCommerce security best practices

## Introduction to security practices

Security is extremely important for online stores. A breach can lead to significant financial loss, reputational damage, and erosion of customer trust. Implementing robust security practices is crucial. This guide covers the best practices for securing WooCommerce stores, including hardening WordPress, keeping plugins and themes up to date, implementing secure coding practices, and protecting user data. By following these recommendations, developers can build secure and resilient WooCommerce stores that protect both their business and their customers.

### Audience

This guide is intended for developers who are familiar with WordPress and WooCommerce and want to improve the security of their online stores.

### Prerequisites

To follow this guide, you should have:

1. A basic understanding of WordPress and WooCommerce.
2. Access to a WordPress website with WooCommerce installed and activated.

## Security standards

We recommend that you maintain the following standards: 

- **PHPCS**: The PHP Code Sniffer tool helps ensure your code adheres to specific coding standards, which can prevent common security issues. Extensions shouldn't have any failure results against PHPCS.

- **SemGrep**: Focuses on identifying patterns that may indicate security vulnerabilities, allowing developers to write more secure code. Extensions shouldn't have any failure results against SemGrep.
... (92 lines truncated)
</file>

<file path="docs/best-practices/urls-and-routing/_category_.json">
{
    "position": 6,
    "label": "URLs and routing",
    "link": {
        "type": "generated-index",
        "title": "URLs and routing",
        "slug": "/best-practices/urls-and-routing"
    }
}
</file>

<file path="docs/best-practices/urls-and-routing/checkout-urls.md">
---
post_title: Shareable Checkout URLs
sidebar_label: Checkout URLs
---

# Shareable Checkout URLs

Custom checkout links automatically populate the cart with specific products and redirect customers straight to checkout with a unique session id. 

The custom checkout link path is `/checkout-link/` and is not customizable.

## Supported parameters

### Products

```plaintext
products=123:2,456:1
```

A comma-separated list of product IDs and quantities. For example, `123:2,456:1`. This feature supports simple products with no additional options. Individual variations can also be added to cart by using the correct variation ID.

### Coupon

```plaintext
coupon=SPRING10
```

A coupon code to apply to the cart. For example, `SPRING10`.

## Example
... (16 lines truncated)
</file>

<file path="docs/best-practices/urls-and-routing/customizing-endpoint-urls.md">
---
post_title: Customizing WooCommerce endpoint URLs
sidebar_label: Customizing endpoint URLs
description: A guide to customizing WooCommerce endpoint URLs, including how to change them in settings, use them in menus, and troubleshoot common issues.
---

# Customizing WooCommerce endpoint URLs

Before you start, check out [WooCommerce Endpoints](./woocommerce-endpoints.md). 

## Customizing endpoint URLs

The URL for each endpoint can be customized in **WooCommerce > Settings > Advanced** in the Page setup section.

![Endpoints](https://developer.woocommerce.com/wp-content/uploads/2023/12/endpoints.png)

Ensure that they are unique to avoid conflicts. If you encounter issues with 404s, go to **Settings > Permalinks** and save to flush the rewrite rules.

## Using endpoints in menus

If you want to include an endpoint in your menus, you need to use the Links section:

![The Links section of a menu item in WordPress](https://developer.woocommerce.com/wp-content/uploads/2023/12/2014-02-26-at-14.26.png)

Enter the full URL to the endpoint and then insert that into your menu.

Remember that some endpoints, such as view-order, require an order ID to work. In general, we don't recommend adding these endpoints to your menus. These pages can instead be accessed via the my-account page.

## Using endpoints in payment gateway plugins

... (52 lines truncated)
</file>

<file path="docs/best-practices/urls-and-routing/removing-product-product-category-or-shop-from-the-url.md">
---
post_title: Understanding the risks of removing URL bases in WooCommerce
sidebar_label: Risks of removing URL bases
description: An explanation of the risks and potential issues associated with removing `/product/`, `/product-category/`, or `/shop/` from WooCommerce URLs, including performance and SEO concerns.
---

# Understanding the risks of removing URL bases in WooCommerce

## In sum

Removing  `/product/`,  `/product-category/`, or  `/shop/`  from the URLs is not advisable due to the way WordPress resolves its URLs. It uses the  `product-category`  (or any other text for that matter) base of a URL to detect that it is a URL leading to a product category. There are SEO plugins that allow you to remove this base, but that can lead to a number of problems with performance and duplicate URLs.

## Better to avoid

You will make it harder for WordPress to detect what page you are trying to reach when you type in a product category URL. Also, understand that the standard "Page" in WordPress always has no base text in the URL. For example:

- `http://yoursite.com/about-page/` (this is the URL of a standard page)
- `http://yoursite.com/product-category/category-x/` (this is the URL leading to a product category)

What would happen if we remove that 'product-category' part?

-   `http://yoursite.com/about-page/`
-   `http://yoursite.com/category-x/`

WordPress will have to do much more work to detect what page you are looking for when entering one of the above URLs. That is why we do not recommend using any SEO plugin to achieve this.
</file>

<file path="docs/best-practices/urls-and-routing/webhooks.md">
---
post_title: Working with webhooks in WooCommerce
sidebar_label: Using webhooks
description: A guide to working with webhooks in WooCommerce, including creating, editing, deleting, and logging webhook events for integration with third-party services.
---

# Working with webhooks in WooCommerce

## What are webhooks?

A  [Webhook](http://en.wikipedia.org/wiki/Webhook)  is an event notification sent to a URL of your choice. Users can configure them to trigger events on one site to invoke behavior on another.

Webhooks are useful for integrating with third-party services and other external API that support them.

## Webhooks in WooCommerce

Webhooks were introduced in WooCommerce 2.2 and can trigger events each time you add, edit or delete orders, products, coupons or customers.

It's also possible to use webhooks with WooCommerce actions, e.g., Create a webhook to be used every time a product is added to the shopping cart, using the action  `woocommerce_add_to_cart`.

Webhooks also make it easier for third-party apps to integrate with WooCommerce.

## Creating webhooks

![WebHooks screen](https://woocommerce.com/wp-content/uploads/2013/01/woo-webhooks.png)

To create a new webhook:

1/ **Go to**: **WooCommerce > Settings > Advanced > Webhooks**.
> **Note:** Webhooks were formerly found under WooCommerce > Settings > API prior to WooCommerce 3.4.
... (41 lines truncated)
</file>

<file path="docs/best-practices/urls-and-routing/woocommerce-endpoints.md">
---
post_title: Understanding WooCommerce endpoints
sidebar_label: WooCommerce endpoints
---

# Understanding WooCommerce endpoints

Endpoints are an extra part in the website URL that is detected to show different content when present.

For example: You may have a 'my account' page shown at URL **yoursite.com/my-account**. When the endpoint 'edit-account' is appended to this URL, making it '**yoursite.com/my-account/edit-account**' then the **Edit account page** is shown instead of the **My account page**.

This allows us to show different content without the need for multiple pages and shortcodes, and reduces the amount of content that needs to be installed.

Endpoints are located at **WooCommerce > Settings > Advanced**.

## Checkout endpoints

The following endpoints are used for checkout-related functionality and are appended to the URL of the /checkout page:

-   Pay page - `/order-pay/{ORDER_ID}`
-   Order received (thanks) - `/order-received/`
-   Add payment method - `/add-payment-method/`
-   Delete payment method - `/delete-payment-method/`
-   Set default payment method - `/set-default-payment-method/`

## Account endpoints

The following endpoints are used for account-related functionality and are appended to the URL of the /my-account page:

-   Orders - `/orders/`
... (12 lines truncated)
</file>

<file path="docs/best-practices/_category_.json">
{
    "position": 5,
    "label": "Best practices"
}
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/checkout-payment-methods/_category_.json">
{
    "position": 7,
    "label": "Checkout payment methods",
    "collapsible": true,
    "collapsed": true,
    "link": {
      "type": "generated-index",
      "title": "Checkout payment methods"
    }
}
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/checkout-payment-methods/checkout-flow-and-events.md">
---
post_title: Checkout flow and events
sidebar_label: Checkout flow and events

---

# Checkout flow and events

This document gives an overview of the flow for the checkout in the WooCommerce checkout block, and some general architectural overviews.

The architecture of the Checkout Block is derived from the following principles:

-   A single source of truth for data within the checkout flow.
-   Provide a consistent interface for extension integrations (eg Payment methods). This interface protects the integrity of the checkout process and isolates extension logic from checkout logic. The checkout block handles _all_ communication with the server for processing the order. Extensions are able to react to and communicate with the checkout block via the provided interface.
-   Checkout flow state is tracked by checkout status.
-   Extensions are able to interact with the checkout flow via subscribing to emitted events.

Here's a high level overview of the flow:

![checkout flow diagram](https://user-images.githubusercontent.com/1628454/113739726-f8c9df00-96f7-11eb-80f1-78e25ccc88cb.png)

## General Concepts

### Tracking flow through status

At any point in the checkout lifecycle, components should be able to accurately detect the state of the checkout flow. This includes things like:

-   Is something loading? What is loading?
-   Is there an error? What is the error?
-   is the checkout calculating totals?
... (505 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/checkout-payment-methods/filtering-payment-methods.md">
---
post_title: Filtering payment methods in the Checkout block
sidebar_label: Filtering payment methods

---

# Filtering payment methods in the Checkout block

## The problem

You're an extension developer, and your extension is conditionally hiding payment gateways on the checkout step. You need to be able to hide payment gateways on the Checkout block using a front-end extensibility point.

### The solution

WooCommerce Blocks provides a function called `registerPaymentMethodExtensionCallbacks` which allows extensions to register callbacks for specific payment methods to determine if they can make payments.

### Importing

#### Aliased import

```js
import { registerPaymentMethodExtensionCallbacks } from '@woocommerce/blocks-registry';
```

#### `wc global`

```js
const { registerPaymentMethodExtensionCallbacks } = window.wc.wcBlocksRegistry;
```

... (127 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md">
---
post_title: Payment method integration
sidebar_label: Payment method integration

---

# Payment method integration

## Client Side integration

The client side integration consists of an API for registering both _regular_ and _express_ payment methods.

In both cases, the client side integration is done using registration methods exposed on the `blocks-registry` API. You can access this via the `wc` global in a WooCommerce environment (`wc.wcBlocksRegistry`).

> Note: The `@woocommerce/blocks-registry` import examples in this document require a build process that maps WooCommerce packages to their registered script handles. Do not install `@woocommerce/blocks-registry` from npm. Use the [`@woocommerce/dependency-extraction-webpack-plugin`](https://www.npmjs.com/package/@woocommerce/dependency-extraction-webpack-plugin) in your webpack configuration to externalize bundled WooCommerce packages such as `@woocommerce/blocks-registry` to the `wc-blocks-registry` script.

## Express Payment Methods

Express payment methods are payment methods that consist of a one-button payment process initiated by the shopper such as Stripe, ApplePay, or GooglePay.

![Express Payment Area](https://user-images.githubusercontent.com/1429108/79565636-17fed500-807f-11ea-8e5d-9af32e43b71d.png)

### Registration

To register an express payment method, you use the `registerExpressPaymentMethod` function from the blocks registry. 

```js
const { registerExpressPaymentMethod } = window.wc.wcBlocksRegistry;
```

... (537 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/filters-in-cart-and-checkout/_category_.json">
{
    "position": 6,
    "label": "Hooks and filters",
    "collapsible": true,
    "collapsed": true,
    "link": {
      "type": "doc",
      "id": "README"
    }
}
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/filters-in-cart-and-checkout/additional-cart-checkout-inner-block-types.md">
---
post_title: Inner block types
sidebar_label: Inner block types

---

# Inner block types

The following Additional Cart and Checkout inner block types filter is available:

-   `additionalCartCheckoutInnerBlockTypes`

## `additionalCartCheckoutInnerBlockTypes`

### Description

The Cart and Checkout blocks are made up of inner blocks. These inner blocks areas allow certain block types to be added as children. By default, only `core/paragraph`, `core/image`, and `core/separator` are available to add.

By using the `additionalCartCheckoutInnerBlockTypes` filter it is possible to add items to this array to control what the editor can into an inner block.

This filter is called once for each inner block area, so it is possible to be very granular when determining what blocks can be added where.

### Parameters

-   _defaultValue_ `array` (default: `[]`) - The default value of the filter.
-   _extensions_ `object` (default: `{}`) - The extensions object.
-   _args_ `object` - The arguments object with the following key:
    -   _block_ `string` - The block name of the inner block area, e.g. `woocommerce/checkout-shipping-address-block`.
-   _validation_ `boolean` or `Error` - Checks if the returned value is an array of strings. If an error occurs, it will be thrown.

... (48 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/filters-in-cart-and-checkout/cart-line-items.md">
---
post_title: Cart line items
sidebar_label: Cart Line Items

---

# Cart line items

The following Cart Line Items filters are available:

-   `cartItemClass`
-   `cartItemPrice`
-   `itemName`
-   `saleBadgePriceFormat`
-   `showRemoveItemLink`
-   `subtotalPriceFormat`

The following objects are shared between the filters:

-   Cart object
-   Cart Item object

The following screenshot shows which parts the individual filters affect:

![Cart Line Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-13.12.33.png)

## `cartItemClass`

### Description {/* omit in toc */}

... (597 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/filters-in-cart-and-checkout/checkout-and-place-order-button.md">
---
post_title: Checkout and place order button
sidebar_label: Checkout and place order button

---

# Checkout and place order button

The following Checkout and place order button filters are available:

-   `proceedToCheckoutButtonLabel`
-   `proceedToCheckoutButtonLink`
-   `placeOrderButtonLabel`

The following objects are shared between the filters:

-   Cart object
-   Cart Item object

## `proceedToCheckoutButtonLabel`

### Description 

The `proceedToCheckoutButtonLabel` filter allows change the label of the "Proceed to checkout" button.

### Parameters 

-   _defaultValue_ `string` (default: `Proceed to Checkout`) - The label of the "Proceed to checkout" button.
-   _extensions_ `object` (default: `{}`) - The extensions object.
-   _args_ `object` - The arguments object with the following keys:
... (297 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/filters-in-cart-and-checkout/coupons.md">
---
post_title: Coupons
sidebar_label: Coupons

---

# Coupons

The following Coupon filters are available:

-   `coupons`
-   `showApplyCouponNotice`
-   `showRemoveCouponNotice`

## `coupons`

### Description 

The current functionality is to display the coupon codes in the Cart and Checkout sidebars. This could be undesirable if you dynamically generate a coupon code that is not user-friendly. It may, therefore, be desirable to change the way this code is displayed. To achieve this, the filter `coupons` exists. This filter could also be used to show or hide coupons. This filter must _not_ be used to alter the value/totals of a coupon. This will not carry through to the Cart totals.

### Parameters 

-   _coupons_ `object` - The coupons object with the following keys:
    -   _code_ `string` - The coupon code.
    -   _discount_type_ `string` - The type of discount. Can be `percent` or `fixed_cart`.
    -   _totals_ `object` - The totals object with the following keys:
        -   _currency_code_ `string` - The currency code.
        -   _currency_decimal_separator_ `string` - The currency decimal separator.
        -   _currency_minor_unit_ `number` - The currency minor unit.
        -   _currency_prefix_ `string` - The currency prefix.
... (160 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/filters-in-cart-and-checkout/order-summary-items.md">
---
post_title: Order summary items
sidebar_label: Order summary items

---

# Order summary items

The following Order Summary Items filters are available:

-   `cartItemClass`
-   `cartItemPrice`
-   `cartItemScreenReaderPrice`
-   `itemName`
-   `subtotalPriceFormat`

The following objects are shared between the filters:

-   Cart object
-   Cart Item object

The following screenshot shows which parts the individual filters affect:

![Order Summary Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-16.29.45.png)

## `cartItemClass`

### Description

The `cartItemClass` filter allows to change the order summary item class.
... (518 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/filters-in-cart-and-checkout/README.md">
---
sidebar_label: Available Hooks and Filters
category_slug: cart-and-checkout-available-filters
post_title: Cart and Checkout - Available Filters
---

# Available Filters

This document lists the filters that are currently available to extensions and offers usage information for each one of them. Information on registering filters can be found on the [Checkout - Filter Registry](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/filter-registry/README.md) page.

## Cart Line Items filters

The following [Cart Line Items filters](/docs/block-development/extensible-blocks/cart-and-checkout-blocks/filters-in-cart-and-checkout/cart-line-items/) are available:

-   `cartItemClass`
-   `cartItemPrice`
-   `itemName`
-   `saleBadgePriceFormat`
-   `showRemoveItemLink`
-   `subtotalPriceFormat`

The following screenshot shows which parts the individual filters affect:

![Cart Line Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-13.12.33.png)

## Order Summary Items filters

The following [Order Summary Items filters](/docs/block-development/extensible-blocks/cart-and-checkout-blocks/filters-in-cart-and-checkout/order-summary-items/) are available:

-   `cartItemClass`
... (90 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/filters-in-cart-and-checkout/totals-footer-item.md">
---
post_title: Totals footer item
sidebar_label: Totals footer item

---

# Totals footer item

The following Totals Footer Item filter are available:

-   `totalLabel`
-   `totalValue`

## `totalLabel`

The following object is used in the filter:

-   [Cart object](#cart-object)

### Description

The `totalLabel` filter allows to change the label of the total item in the footer of the Cart and Checkout blocks.

### Parameters

-   _defaultValue_ `string` (default: `Total`) - The total label.
-   _extensions_ `object` (default: `{}`) - The extensions object.
-   _args_ `object` - The arguments object with the following keys:
    -   _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).

... (186 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/_category_.json">
{
    "position": 1,
    "label": "Cart and Checkout Blocks",
    "collapsible": true,
    "collapsed": true
}
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/additional-checkout-fields.md">
---
post_title: Additional checkout fields
sidebar_label: Additional checkout fields
sidebar_position: 4
---

# Additional checkout fields

A common use-case for developers and merchants is to add a new field to the Checkout form to collect additional data about a customer or their order.

This document will outline the steps an extension should take to register some additional checkout fields.

## Available field locations

Additional checkout fields can be registered in three different places:

| Title                                | Identifier    |
| ------------------------------------ | ------------- |
| Contact information                  | **`contact`** |
| Addresses (Shipping **and** Billing) | **`address`** |
| Order information                    | **`order`**   |

A field can only be shown in one location, it is not possible to render the same field in multiple locations in the same registration.

### Contact information

The contact information section currently renders at the top of the form. It contains the `email` field and any other additional fields.

![Showing the contact information section with two fields rendered, email and an additional checkout field (optional)](https://github.com/woocommerce/woocommerce/assets/5656702/097c2596-c629-4eab-9604-577ee7a14cfe)

... (1195 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/available-slot-fills.md">
---
post_title: Available slots
sidebar_label: Available slots
sidebar_position: 2
---

# Available slots

This document presents the list of available Slots that you can use for adding your custom content (Fill).

If you want to add a new SlotFill component, check the [Checkout - Slot Fill document](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/slot/README.md). To read more about Slot and Fill, check the [Slot and Fill document](/docs/block-development/reference/slot-fills/).

**Note About Naming:** Slots that are prefixed with `Experimental` are experimental and subject to change or remove. Once they graduate from the experimental stage, the naming would change and the `Experimental` prefix would be dropped. Check the [Feature Gating document](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md) from more information.

## ExperimentalOrderMeta

This Slot renders below the Checkout summary section and above the "Proceed to Checkout" button in the Cart.

```ts
const { __ } = window.wp.i18n;
const { registerPlugin } = window.wp.plugins;
const { ExperimentalOrderMeta } = window.wc.blocksCheckout;

const render = () => {
	return (
		<ExperimentalOrderMeta>
			<div class="wc-block-components-totals-wrapper">
				{ __( 'Yearly recurring total ...', 'YOUR-TEXTDOMAIN' ) }
			</div>
		</ExperimentalOrderMeta>
... (144 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/checkout-utilities.md">
---
post_title: Checkout Utilities
sidebar_label: Checkout Utilities
---

# Checkout Utilities

Utility functions and React hooks for checkout functionality, available from `@woocommerce/blocks-checkout`.

## `useValidateCheckout`

A hook that validates the checkout form and automatically scrolls to the first validation error if any are found.

This hook is primarily used internally by the `PlaceOrderButton` component to provide the `validate` prop to custom place order button components. However, it can also be used directly if needed.

### Usage

```jsx
// Aliased import
import { useValidateCheckout } from '@woocommerce/blocks-checkout';

// Global import
// const { useValidateCheckout } = wc.blocksCheckout;

const MyComponent = () => {
    const validateCheckout = useValidateCheckout();

    const handleClick = async () => {
        const { hasError } = await validateCheckout();

... (28 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/dom-events.md">
---
post_title: DOM events
sidebar_label: DOM Events
sidebar_position: 3
---

# DOM events

Some blocks need to react to certain events in order to display the most up to date data or behave in a certain way. That's the case of the Cart block, for example, that must listen to 'add to cart' events in order to update the cart contents; or the Mini-Cart block, that gets opened every time a product is added to the cart.

## WooCommerce core events in WooCommerce Blocks

WooCommerce core uses jQuery events to trigger and listen to certain events, like when a product is added or removed from the cart. In WooCommerce Blocks, we moved away from using jQuery, but we still need to listen to those events. To achieve that, we have a utility named [`translatejQueryEventToNative()`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/assets/js/base/utils/legacy-events.ts) that listens to those jQuery events, and every time one is triggered, it triggers an associated DOM native event (with the `wc-blocks_` prefix).

## WooCommerce Blocks events

### `wc-blocks_adding_to_cart`

This event is the equivalent to the jQuery event `adding_to_cart` triggered by WooCommerce core. It indicates that the process of adding a product to the cart was sent to the server, but there is still no indication on whether the product was successfully added or not.

_Example usage in WC Blocks:_ Mini-Cart block listens to this event to append its dependencies.

### `wc-blocks_added_to_cart`

This event is the equivalent to the jQuery event `added_to_cart` triggered by WooCommerce core. It indicates that the process of adding a product to the cart has finished with success.

_Example usage in WC Blocks:_ Cart and Mini-Cart blocks (via the `useStoreCart()` hook) listen to this event to know if they need to update their contents.

#### `detail` parameters

... (10 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/how-checkout-processes-an-order.md">
---
post_title: How the checkout block processes an order
sidebar_label: Processing an order
sidebar_position: 1
---

# How the checkout block processes an order

This document will shed some light on the inner workings of the Checkout flow. More specifically, what happens after a user hits the "Place Order" button.

## Structure

The following areas are associated with processing the checkout for a user.

### The Payment Registry [(file)](https://href.li/?https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/blocks-registry/payment-methods/registry.ts#L1)

The payment registry stores all the configuration information for each payment method. We can register a new payment method here with the `registerPaymentMethod` and `registerExpressPaymentMethod `functions, also available to other plugins.

### Data Stores

Data stores are used to keep track of data that is likely to change during a user's session, such as the active payment method, whether the checkout has an error, etc. We split these data stores by areas of concern, so we have 2 data stores related to the checkout: `wc/store/checkout` [(file)](https://href.li/?https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/checkout/index.ts#L1) and `wc/store/payment` [(file)](https://href.li/?https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/payment-methods/index.ts#L1) . Data stores live in the `assets/js/data` folder.

### Contexts

Contexts are used to make data available to the Checkout block. Each of these provide data and functions related to a specific area of concern, via the use of a hook. For example, if we wanted to use the `onPaymentSetup` handler from the `PaymentEventsContext` context, we can do it like this:

```js
const { onPaymentSetup } = usePaymentEventsContext();
```

... (115 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/README.md">
---
sidebar_label: Cart and Checkout blocks
category_slug: cart-and-checkout
post_title: Cart and Checkout blocks
---

# Getting started with Cart and Checkout extensibility

This document is a high-level overview of the moving parts required to extend the Cart and Checkout blocks.

To get started, it is recommended to first read the [Block Development Environment](https://developer.wordpress.org/block-editor/getting-started/devenv/) documentation from WordPress and follow [Tutorial: Build your first block
](https://developer.wordpress.org/block-editor/getting-started/tutorial/).

## Example block template package

There is an example block template in the WooCommerce repository. Having this template set up while reading this document may help to understand some of the concepts discussed. See the [`@woocommerce/extend-cart-checkout-block` package documentation](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/extend-cart-checkout-block/README.md) for how to install and run the example block.

(Note: the code in the repository linked above will not be very useful alone; the code there is templating code. It will be transformed into regular JS and PHP after following the README instructions.)

## Front-end extensibility

To extend the front-end of the blocks, extensions must use JavaScript. The JavaScript files must be enqueued and loaded on the page before they will have any effect.

### Build system

Some extensions may be very simple and include only a single JavaScript file, other extensions may be complex and the code may be split into multiple files. Either way, it is recommended that the files are bundled together and minified into a single output file. If your extension has several distinct parts that only load on specific pages, bundle splitting is recommended, though that is out of scope for this document.

To set up the build system, the recommended approach is to align with WordPress and use a JavaScript package called [`@wordpress/scripts`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/). This package contains a script called `build`. By default, this will build your scripts into a single output file that can be enqueued using `wp_enqueue_script`.

The base configuration of the `build` script in  `@wordpress/scripts` can be overridden by creating a `webpack.config.js` file in the root of your plugin. The example block shows how the base config can be extended.
... (154 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/cart-and-checkout-blocks/removing-checkout-fields.md">
---
post_title: Removing checkout fields
sidebar_label: Removing checkout fields
sidebar_position: 5
---

# Removing checkout fields

If you're trying to extend the new Checkout block, you might notice the previous `checkout_fields` isn't working. This is intentional as we want to offer more curated extensibility paths. With that said, one of the most common requests we get is how to disable Checkout fields for certain order types. This is not something we encourage, but we are sharing the details due to how commonly requested it is.

## Why we don't encourage removing fields

The simple reason is that Checkout is complex, and many plugins need different data, payment methods will need your address info to run fraud detection, or validate your card, tax (including core) will need your full address to calculate taxes correctly, this is something we still think about in Checkout and are looking for a universal solution. While we work on this solution, the document below will help you remove checkout fields.

## Disabling fields for a single country

Checkout fields still respect country locale, which means you can modify fields for a country via PHP and this would work fine. The following billing form has 10 fields, 7 of them are required:

![Image](https://github.com/user-attachments/assets/63d83769-c20c-4c85-aebf-da8510d1d9ae)

Let's say that in Algeria, we know for sure that postal code and city are redundant, so we can remove them:

```php
add_filter('woocommerce_get_country_locale', function( $locale ) {

	$locale['DZ']['postcode']['required'] = false;
	$locale['DZ']['postcode']['hidden'] = true;

	$locale['DZ']['city']['required'] = false;
	$locale['DZ']['city']['hidden'] = true;
... (176 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/product-collection-block/_category_.json">
{
	"label": "Product Collection Block",
	"link": {
		"type": "doc",
		"id": "README"
	}
}
</file>

<file path="docs/block-development/extensible-blocks/product-collection-block/dom-events.md">
---
post_title: DOM Events sent from product collection block
sidebar_label: DOM events

---

# DOM events sent from product collection block

## `wc-blocks_product_list_rendered`

This event is triggered when Product Collection block was rendered or re-rendered (e.g. due to page change).

### `detail` parameters

| Parameter          | Type    | Default value | Description                                                                                                                                                                                                                                                                                                                                                                                   |
| ------------------ | ------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `collection` | string | `undefined`       | Collection type. It's `undefined` for "create your own" collections as the type is not specified. For other Core collections it can be one of type: `woocommerce/product-collection/best-sellers`, `woocommerce/product-collection/featured`, `woocommerce/product-collection/new-arrivals`, `woocommerce/product-collection/on-sale`, `woocommerce/product-collection/top-rated`. For custom collections it will hold their name. |

### Example usage

```javascript
window.document.addEventListener(
  'wc-blocks_product_list_rendered',
  ( e ) => {
    const { collection } = e.detail;
    console.log( collection ) // -> collection name, e.g. woocommerce/product-collection/on-sale
  }
);
```

... (24 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/product-collection-block/README.md">
---
sidebar_label: Product Collection block
category_slug: product-collection
post_title: Product collection block
---

# Product collection block

Display a collection of products from your store.

## Start here

1. [DOM events sent from product collection block](/docs/block-development/extensible-blocks/product-collection-block/dom-events)
2. [Registering custom collections in product collection block](/docs/block-development/extensible-blocks/product-collection-block/register-product-collection)
</file>

<file path="docs/block-development/extensible-blocks/product-collection-block/register-product-collection.md">
---
post_title: Registering custom collections in product collection block
sidebar_label: Registering custom collections

---

# Registering custom collections in product collection block

The `__experimentalRegisterProductCollection` function is part of the `@woocommerce/blocks-registry` package. This function allows third party developers to register a new collection. This function accepts most of the arguments that are accepted by [Block Variation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-variations/#defining-a-block-variation).

**CAUTION:** It's experimental and may change in the future. Please use it with caution.

**There are two ways to use this function:**

1. Using `@woocommerce/dependency-extraction-webpack-plugin` in a Webpack configuration: This will allow you to import the function from the package & use it in your code. For example:

	```tsx
	import { __experimentalRegisterProductCollection } from "@woocommerce/blocks-registry";
	```

2. Using the global `wc` object: This will allow you to use the function using the global JS object without importing it. For example:

	```tsx
	wc.wcBlocksRegistry.__experimentalRegisterProductCollection({
	...
	});
	```

Be sure to add `wc-blocks-registry` as a dependency to your script if you opt to use the `wc` global.

... (309 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/product-sale-badge-block/_category_.json">
{
	"label": "On-Sale Badge Block",
	"link": {
		"type": "doc",
		"id": "README"
	}
}
</file>

<file path="docs/block-development/extensible-blocks/product-sale-badge-block/README.md">
---
sidebar_label: On-Sale Badge block
category_slug: product-sale-badge
post_title: On-Sale Badge block
---

# On-Sale Badge block

The On-Sale Badge block displays a "Sale" badge on products that are on sale.

> **Note:** This block uses the slug `woocommerce/product-sale-badge`.

## `woocommerce_sale_badge_text`

### Description {/* omit in toc */}

The `woocommerce_sale_badge_text` filter allows customization of the sale badge text based on product context.

### Parameters {/* omit in toc */}

-   _$sale_text_ `string` (default: `'Sale'`) - The sale badge text.
-   _$product_ `WC_Product` - The product object.

### Returns {/* omit in toc */}

-   `string` - The filtered sale badge text.

### Code examples {/* omit in toc */}

#### Basic example {/* omit in toc */}
... (107 lines truncated)
</file>

<file path="docs/block-development/extensible-blocks/_category_.json">
{
  "label": "Extensible Blocks",
  "position": 3,
  "link": {
    "type": "generated-index",
    "title": "Extensible Blocks"
  }
}
</file>

<file path="docs/block-development/getting-started/_category_.json">
{
  "label": "Getting Started",
  "position": 1,
  "link": {
    "type": "doc",
    "id": "block-development/getting-started/extensibility-overview"
  }
}
</file>

<file path="docs/block-development/getting-started/extensibility-overview.md">
---
sidebar_label: Extensibility in blocks
category_slug: extensibility-in-blocks
post_title: Extensibility in blocks
---

# Extensibility in blocks

These documents are all dealing with extensibility in the various WooCommerce Blocks.

## Imports and dependency extraction

The documentation in this section will use window globals in code examples, for example:

```js
const { registerCheckoutFilters } = window.wc.blocksCheckout;
```

However, if you're using `@woocommerce/dependency-extraction-webpack-plugin` for enhanced dependency management you can instead use ES module syntax:

```js
import { registerCheckoutFilters } from '@woocommerce/blocks-checkout';
```

See [@woocommerce/dependency-extraction-webpack-plugin](https://www.npmjs.com/package/@woocommerce/dependency-extraction-webpack-plugin) for more information.

## Hooks (actions and filters)

| Document | Description |
| --- | --- |
... (36 lines truncated)
</file>

<file path="docs/block-development/getting-started/faq.md">
---
post_title: Frequently asked questions
sidebar_label: Frequently asked questions

---

# Frequently Asked Questions

This document aims to answer some of the frequently asked questions we see from developers extending WooCommerce Blocks.

We will add to the FAQ document as we receive questions, this isn't the document's final form.

If you have questions that aren't addressed here, we invite you to ask them on [GitHub Discussions](https://github.com/woocommerce/woocommerce/discussions) or in the [WooCommerce Community Slack](https://woocommerce.com/community-slack/)

## General questions

### How do I react to changes to the Cart or Checkout e.g. shipping method selection, or address changes?

The Cart and Checkout blocks read all their data from [`@wordpress/data` data stores](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/). We also have [documentation for the data stores WooCommerce Blocks uses](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/data-store).

It is common for developers to want to react to changes in the cart or checkout. For example, if a user changes their shipping method, or changes a line of their address.

There are two ways to do this, depending on how your code is running.

#### If your code is running in a React component

If your component is an inner block of the Cart/Checkout, or rendered in a [Slot/Fill](/docs/block-development/reference/slot-fills/), you can directly select the data you need from the relevant data store and perform any necessary actions when the data changes. For more information on available selectors, refer to the [documentation for the relevant data store](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/data-store).

```js
/**
... (207 lines truncated)
</file>

<file path="docs/block-development/reference/data-store/cart.md">
---
sidebar_label: Cart store
---

# Cart Store (`wc/store/cart`) 

> 💡 What's the difference between the Cart Store and the Checkout Store?
>
> The **Cart Store (`wc/store/cart`)** manages and retrieves data about the shopping cart, including items, customer data, and interactions like coupons.
>
> The **Checkout Store (`wc/store/checkout`)** manages and retrieves data related to the checkout process, customer IDs, order IDs, and checkout status.


## Overview

The Cart Store provides a collection of selectors and methods to manage and retrieve cart-related data for WooCommerce Blocks. It offers functionality ranging from fetching cart details to managing customer interactions, such as applying coupons or updating shipping information.

## Usage

To utilize this store you will import the `cartStore` `StoreDescriptor` in any module referencing it. Assuming `@woocommerce/block-data` is registered as an external pointing to `wc.wcBlocksData` you can import the `StoreDescriptor` via:

```js
const { cartStore } = window.wc.wcBlocksData;
```

## Actions

### setCartData

This action is used to set the cart data in the store.
... (925 lines truncated)
</file>

<file path="docs/block-development/reference/data-store/checkout.md">
---
sidebar_label: Checkout Store 
---

# Checkout Store (`wc/store/checkout`) 

> 💡 What's the difference between the Cart Store and the Checkout Store?
>
> The **Cart Store (`wc/store/cart`)** manages and retrieves data about the shopping cart, including items, customer data, and interactions like coupons.
>
> The **Checkout Store (`wc/store/checkout`)** manages and retrieves data related to the checkout process, customer IDs, order IDs, and checkout status.

## Overview

The Checkout Store provides a collection of selectors to access and manage data during the checkout process. These selectors enable developers to fetch key details such as customer information, order status, and other checkout-related data.

## Usage

To utilize this store you will import the `checkoutStore` `StoreDescriptor` in any module referencing it. Assuming `@woocommerce/block-data` is registered as an external pointing to `wc.wcBlocksData` you can import the `StoreDescriptor` via:

```js
const { checkoutStore } = '@woocommerce/block-data'
```

If it is not you can import it via:

```js
const { checkoutStore } = window.wc.wcBlocksData
```

... (408 lines truncated)
</file>

<file path="docs/block-development/reference/data-store/collections.md">
---
sidebar_label: Collections Store
---

# Collections Store (`wc/store/collections`) 

## Overview

The Collections Store allows to retrieve product-related collections within WooCommerce Blocks.

## Usage

To utilize this store you will import the COLLECTIONS_STORE_KEY in any module referencing it. Assuming `@woocommerce/block-data` is registered as an external pointing to `wc.wcBlocksData` you can import the key via:

```js
const { COLLECTIONS_STORE_KEY } = window.wc.wcBlocksData;
```

## Actions

### receiveCollection( namespace, resourceName, queryString, ids = [], items = [], replace = false )

This will return an action object for the given arguments used in dispatching the collection results to the store.

> ⚠️ You should rarely have to dispatch this action directly as it is used by the resolver for the `getCollection` selector.

#### _Parameters_ 

-   _namespace_ `string`: The route namespace for the collection, eg. `/wc/blocks`.
-   _resourceName_ `string`: The resource name for the collection (eg. `products/attributes`.
... (152 lines truncated)
</file>

<file path="docs/block-development/reference/data-store/payment.md">
---
sidebar_label: Payment Store
---

# Payment Store (`wc/store/payment`) 

## Overview

The payment data store is used to store payment method data and payment processing information. When the payment status changes, the data store will reflect this.

**⚠️ Currently, all the actions are internal-only while we determine which ones will be useful for extensions to interact with. We do not encourage extensions to dispatch actions onto this data store yet.**

An example of data held within the Payment Data Store is shown below. This example shows the state with several Payment Gateways active, and a saved token.

```js
{
    status: 'idle',
    activePaymentMethod: 'stripe',
    activeSavedToken: '1',
    availablePaymentMethods: {
      bacs: {
        name: 'bacs'
      },
      cheque: {
        name: 'cheque'
      },
      cod: {
        name: 'cod'
      },
      stripe: {
... (532 lines truncated)
</file>

<file path="docs/block-development/reference/data-store/query-state.md">
---
sidebar_label: Query State Store
---

# Query State Store (`wc/store/query-state`) 

## Overview

The Query State Store offers actions to handle and manipulate query-related data within specific contexts, such as individual blocks. This facilitates the dynamic updating and retrieval of query-state values, ensuring accurate and context-specific data management within WooCommerce Blocks.

## Usage

To utilize this store you will import the `QUERY_STATE_STORE_KEY` in any module referencing it. Assuming `@woocommerce/block-data` is registered as an external pointing to `wc.wcBlocksData` you can import the key via:

```js
const { QUERY_STATE_STORE_KEY } = window.wc.wcBlocksData;
```

## Actions

> ⚠️ New values will always overwrite any existing entry in the store.

### setQueryValue( context, queryKey, value )

This will set a single query-state value for a given context.

#### _Parameters_ 

-   _context_ `string`: The context for the query state being stored, eg. the block name so you can keep query-state specific per block.
-   _queryKey_ `string`: The reference for the value being stored.
... (11 lines truncated)
</file>

<file path="docs/block-development/reference/data-store/README.md">
# Data Store

This document provides an overview of the data stores registered with `wp.data` for use by various blocks. Store descriptions are exported as constants on the `wc.wcBlocksData` export (externally registered as `@woocommerce/block-data` and enqueued via handle `wc-blocks-data-store`). For any block using the store, it's recommended to import the store description rather than using the reference directly to ensure dependencies are extracted correctly. It is assumed readers have some familiarity with the `wp.data` API. You can read more about that [in the @wordpress/data reference guide](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/).

## [Cart Store (wc/store/cart)](cart.md)

The **[Cart Store (wc/store/cart)](cart.md)** is responsible for handling cart-related data and operations. To access this store using a constant, you can use:

```ts
const { cartStore } = window.wc.wcBlocksData;
```

## [Checkout Store (wc/store/checkout)](checkout.md)

The **[Checkout Store (wc/store/checkout)](checkout.md)** manages the checkout process, ensuring a seamless experience for users. To access this store using a constant, you can use:

```ts
const { checkoutStore } = window.wc.wcBlocksData;
```

## [Collections Store (wc/store/collections)](collections.md)

The **[Collections Store (wc/store/collections)](collections.md)** holds data indexed by namespace, model name, and query string. To access this store using a constant, you can use:

```ts
const { COLLECTIONS_STORE_KEY } = window.wc.wcBlocksData;
```

## [Payment Store (wc/store/payment)](payment.md)

... (40 lines truncated)
</file>

<file path="docs/block-development/reference/data-store/schema.md">
---
sidebar_label: Schema Store
---
# Schema Store (`wc/store/schema`) 

## Overview

The Schema Store manages the routes associated with WooCommerce Blocks, enabling efficient retrieval and updating of route data for a given namespace. This store streamlines the interaction with resource routes, ensuring that modules can easily access endpoint paths as needed.

## Usage

To utilize this store you will import the `SCHEMA_STORE_KEY` in any module referencing it. Assuming `@woocommerce/block-data` is registered as an external pointing to `wc.wcBlocksData` you can import the key via:

```js
const { SCHEMA_STORE_KEY } = window.wc.wcBlocksData;
```

## Actions

> ⚠️ You should rarely need to use any of these actions directly as they are mostly used internally by the resolvers.

### receiveRoutes( routes, namespace)

This returns an action object used to update the store with the provided list of resource routes.

#### _Parameters_ 

-   _routes_ `array`: An array of routes attached for the given namespace, eg. `[ '/wc/blocks/products', '/wc/blocks/products/attributes/(?P<id>[\d]+)' ]`.
-   _namespace_ `string`: The namespace the routes belong to, eg. `/wc/blocks`.

... (87 lines truncated)
</file>

<file path="docs/block-development/reference/data-store/store-notices.md">
---
sidebar_label: Store Notices Store
---
# Store Notices Store (`wc/store/store-notices`) 

## Overview

The Store Notices Store allows to register and unregister containers for notices. This is useful for displaying notices in a specific location, such as a custom block.

## Usage

To utilize this store you will import the `storeNoticesStore` `StoreDescriptor` in any module referencing it. Assuming `@woocommerce/block-data` is registered as an external pointing to `wc.wcBlocksData` you can import the `StoreDescriptor` via:

```js
import { storeNoticesStore } from '@woocommerce/block-data';
```

If it's not, then access it from the window like so:

```js
const { storeNoticesStore } = window.wc.wcBlocksData;
```

## Example

The following code snippet demonstrates how to register a container for notices.

```js
import { store as noticesStore } from '@wordpress/notices';

... (87 lines truncated)
</file>

<file path="docs/block-development/reference/data-store/validation.md">
---
sidebar_label: Validation Store
---

# Validation Store (`wc/store/validation`) 

## Overview

The validation data store provides a way to show errors for fields in the Cart or Checkout blocks.

The data in the store should be a single object, the keys of which are the _error IDs_ and values are the data associated with that error message. The values in the object should contain _message_ and _hidden_. The _message_ is the error message to display and _hidden_ is a boolean indicating whether the error should be shown or not.

An example of how the data should be structured:

```js
{
    "error-id-1": {
        message: "This is an error message",
        hidden: false,
    },
    "error-id-2": {
        message: "This is another error message",
        hidden: true,
    },
}
```

When the checkout process begins, it will check if this data store has any entries, and if so, it will stop the checkout process from proceeding. It will also show any errors that are hidden. Setting an error to hidden will not clear it from the data store!

## Usage
... (314 lines truncated)
</file>

<file path="docs/block-development/reference/hooks/hook-alternatives.md">
---
sidebar_label: Hook alternatives
---

# Hook alternatives

These are the hooks that run when loading the Cart/Checkout shortcodes and blocks. Some are general WooCommerce lifecycle hooks, some are specific to the Cart and Checkout pages. These were generated by logging each call to `do_action` and `apply_filters` and reviewing the issues mentioning "hooks" and "filter(s)" in the old [WooCommerce Blocks repository](https://github.com/woocommerce/woocommerce-blocks/).

## Legend

| Icon | Description |
| --- | --- |
| ✅ | Fully supported |
| 🔶 | Partially supported |
| ❌ | Not supported |
| ❓ | Unknown |

If a hook is marked as Unknown ❓(Unknown) it means we were not able to verify whether the hook is supported for some reason. As time goes on, we will attempt to validate more of these hooks. The goal is to have no hooks with an Unknown ❓status remaining in any of the tables.

### WooCommerce lifecycle _actions_

These hooks run on every Woo page load, some affect the blocks, some don't, some only affect them partially.

| Old hook | Works in blocks? | Notes |
| --- | --- | --- |
| `woocommerce_load_cart_from_session` | Fully supported ✅ | |
| `woocommerce_cart_loaded_from_session` | Fully supported ✅ | |
| `woocommerce_set_cart_cookies` | Fully supported ✅ | |
| `woocommerce_shipping_zone_loaded` | Fully supported ✅ | |
| `woocommerce_check_cart_items` | Fully supported ✅ | May be better to use `woocommerce_store_api_validate_cart_item` |
... (420 lines truncated)
</file>

<file path="docs/block-development/reference/hooks/migrated-hooks.md">
---
sidebar_label:  Migrated legacy hooks
---

# Migrated legacy hooks

Below are the hooks that exist in WooCommerce core and that were brought over to WooCommerce Blocks.

Please note that the actions and filters here run on the server side. The client-side blocks won't necessarily change based on a callback added to a server side hook. [Please see our documentation relating to APIs for manipulating the blocks on the client-side](./README.md).

## Legacy Filters

- [wc_session_expiration](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#wc_session_expiration)
- [woocommerce_add_cart_item](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_add_cart_item)
- [woocommerce_add_cart_item_data](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_add_cart_item_data)
- [woocommerce_add_to_cart_quantity](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_add_to_cart_quantity)
- [woocommerce_add_to_cart_sold_individually_quantity](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_add_to_cart_sold_individually_quantity)
- [woocommerce_add_to_cart_validation](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_add_to_cart_validation)
- [woocommerce_adjust_non_base_location_prices](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_adjust_non_base_location_prices)
- [woocommerce_apply_individual_use_coupon](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_apply_individual_use_coupon)
- [woocommerce_apply_with_individual_use_coupon](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_apply_with_individual_use_coupon)
- [woocommerce_cart_contents_changed](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_cart_contents_changed)
- [woocommerce_cart_item_permalink](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_cart_item_permalink)
- [woocommerce_get_item_data](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_get_item_data)
- [woocommerce_loop_add_to_cart_args](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_loop_add_to_cart_args)
- [woocommerce_loop_add_to_cart_link](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_loop_add_to_cart_link)
- [woocommerce_pay_order_product_has_enough_stock](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_pay_order_product_has_enough_stock)
- [woocommerce_pay_order_product_in_stock](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_pay_order_product_in_stock)
- [woocommerce_show_page_title](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_show_page_title)

... (13 lines truncated)
</file>

<file path="docs/block-development/reference/hooks/README.md">
# Hooks

We have several hooks that can be used by extensions, some are new and some are hooks that already exist in WooCommerce core.

- [Filters](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md)
- [Actions](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/actions.md)

We also have a list of hooks that have been migrated from WooCommerce Core, but that have been renamed.

- [List of migrated hooks](./migrated-hooks.md)
</file>

<file path="docs/block-development/reference/_category_.json">
{
  "label": "Reference",
  "position": 5,
  "link": {
    "type": "generated-index",
    "title": "Reference"
  }
}
</file>

<file path="docs/block-development/reference/block-references.md">
---
post_title: Blocks reference
sidebar_label: Blocks reference
---

# Blocks reference

This page lists the Woo blocks included in the package. (Incomplete as there are still blocks that are not using block.json definition).

{/* START Autogenerated - DO NOT EDIT */}

## Product Average Rating (Beta) - woocommerce/product-average-rating

Display the average rating of a product

- **Name:** woocommerce/product-average-rating
- **Category:** woocommerce-product-elements
- **Ancestor:** woocommerce/single-product
- **Supports:** color (background, text), interactivity (clientNavigation), spacing (margin, padding), typography (fontSize)
- **Attributes:** textAlign

## Add to Cart Button - woocommerce/product-button

Display a call to action button which either adds the product to the cart, or links to the product page.

- **Name:** woocommerce/product-button
- **Category:** woocommerce-product-elements
- **Ancestor:** woocommerce/all-products, woocommerce/single-product, core/post-template, woocommerce/product-template
- **Supports:** align (full, wide), color (background, text, ~~link~~), email, interactivity, spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~
- **Attributes:** isDescendentOfQueryLoop, isDescendentOfSingleProductBlock, productId, textAlign, width
... (1626 lines truncated)
</file>

<file path="docs/block-development/reference/integration-interface.md">
---
post_title: Handling scripts, styles, and data
sidebar_label: Script, styles, and data handling

---

# Handling scripts, styles, and data

## The problem

You are an extension developer, and to allow users to interact with your extension on the client-side, you have written some CSS and JavaScript that you would like to be included on the page. Your JavaScript also relies on some server-side data, and you'd like this to be available to your scripts.

## The solution

You may use the `IntegrationRegistry` to register an `IntegrationInterface` this will be a class that will handle the enqueuing of scripts, styles, and data. You may have a different `IntegrationInterface` for each block (Mini-Cart, Cart and Checkout), or you may use the same one, it is entirely dependent on your use case.

You should use the hooks: `woocommerce_blocks_mini-cart_block_registration`. `woocommerce_blocks_cart_block_registration` and `woocommerce_blocks_checkout_block_registration`. These hooks pass an instance of [`IntegrationRegistry`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Blocks/Integrations/IntegrationRegistry.php) to the callback.

You may then use the `register` method on this object to register your `IntegrationInterface`.

## `IntegrationInterface` methods

To begin, we'll need to create our integration class, our `IntegrationInterface`. This will be a class that implements WooCommerce Blocks' interface named [`IntegrationInterface`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Blocks/Integrations/IntegrationInterface.php).

In this section, we will step through the interface's members and discuss what they are used for.

### `get_name()`

This is the `IntegrationInterface`'s way of namespacing your integration. The name chosen here should be unique to your extension. This method should return a string.

... (177 lines truncated)
</file>

<file path="docs/block-development/reference/overview-of-data-flow.md">
---
post_title: Overview of data flow between client and server
sidebar_label: Data flow overview

---

# Overview of data flow between client and server

In the WooCommerce Cart and Checkout blocks, the server is the source of truth for critical transactional and persistent data. This includes:

-   Cart item details (items, quantities, and prices)
-   Cart totals (e.g. taxes, fees, subtotals)
-   Customer information (shipping and billing addresses, other customer data)
    -   Additional fields added using the [Additional Checkout Fields API](/docs/block-development/extensible-blocks/cart-and-checkout-blocks/additional-checkout-fields/) are also persisted server-side.
-   Shipping methods and rates
-   Other cart details, such as applied coupons

Such data must be persisted server-side to ensure accuracy, consistency, and reliability across different user sessions and devices.
Ephemeral UI state—such as temporary validation states, or UI-specific interactions like expanded/collapsed sections should remain client-side and not be automatically persisted on the server, unless the specific state needs to be maintained across page loads or is critical to the user's checkout process.

You may wish to get data from the server into the client, and vice/versa. This document will outline the general concepts and data flow in the Cart/Checkout blocks, and provide links, or guidance on some common use cases.

## Where is data stored?

All the data relating to a cart, customer, and order is stored on the server, either in the database or in the customer's session. When it is sent to the client, it is stored in [`@wordpress/data`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/) data stores.

## How do I get my Server-side (PHP) data into the client (JavaScript) and vice/versa

Since the server is the source of truth, all data from the client should eventually make its way there if it needs to be persisted with the order.

... (105 lines truncated)
</file>

<file path="docs/block-development/reference/slot-fills.md">
---
post_title: Slot and fill
sidebar_label: Slot and fill

---

# Slot and fill

## The problem

You added custom data to the [Store API](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-add-data.md). You changed several strings using [Checkout filters](/docs/block-development/extensible-blocks/cart-and-checkout-blocks/filters-in-cart-and-checkout/). Now you want to render your own components in specific places in the Cart and Checkout.

## Solution

Slot and Fill are a pair of components that add the possibility to render your own HTML in pre-defined places in the Cart and Checkout. Your component will get access to contextual data and will get re-rendered when needed.

A _Slot_ is a place in the Cart and Checkout that can render an indefinite number of external components.

A _Fill_ is the component provided by third-party developers to render inside a _Slot_.

Slot and Fill use WordPress' API, and you can learn more about how they work in [the Slot and Fill documentation.](https://github.com/WordPress/gutenberg/tree/trunk/packages/components/src/slot-fill).

## Basic Usage

`ExperimentalOrderMeta` is a fill that will render in a slot below the Order summary section in the Cart and Checkout blocks.
The `ExperimentalOrderMeta` will automatically pass props to its top level child:

-   `cart` which contains cart data
-   `extensions` which contains data registered with `ExtendSchema::class` in `wc/store/cart` endpoint
-   `context`, equal to the name of the Block in which the fill is rendered: `woocommerce/cart` or `woocommerce/checkout`
... (33 lines truncated)
</file>

<file path="docs/block-development/tutorials/_category_.json">
{
	"label": "Tutorials",
	"position": 6,
	"link": {
		"type": "generated-index",
		"title": "Tutorials"
	}
}
</file>

<file path="docs/block-development/tutorials/how-to-additional-checkout-fields-guide.md">
---
post_title: How to Add Additional Fields
sidebar_label: How to add additional fields in checkout
---

# How to Add Additional Fields to the WooCommerce Checkout Block

This feature requires a minimum version of WooCommerce 8.9.0

The WooCommerce Checkout Block provides a powerful API for developers to add additional fields to collect information from customers during the checkout process. Whether you need to gather special delivery instructions, business details, or marketing preferences, additional checkout fields make it easy to extend your store’s functionality.

In this guide, we’ll walk through the process of adding your own additional fields to your checkout form and show you practical examples you can implement right away.

## Getting Started

To add additional checkout fields, you’ll use the `woocommerce_register_additional_checkout_field()` function. This should be called after the `woocommerce_init` action to ensure WooCommerce is fully loaded.

Here's the basic structure:

```php
add_action( 'woocommerce_init', function() {
    if ( ! function_exists( 'woocommerce_register_additional_checkout_field' ) ) {
        return;
    }
    
    woocommerce_register_additional_checkout_field(
        array(
            'id'       => 'your-namespace/field-name',
            'label'    => __( 'Your Field Label', 'your-text-domain'),
            'location' => 'contact', // or 'address' or 'order'
... (312 lines truncated)
</file>

<file path="docs/block-development/tutorials/how-to-conditional-additional-fields.md">
---
post_title: How to Add Conditional Additional Checkout Fields
sidebar_label: How to add additional conditional fields in checkout
---

# How to Make Your WooCommerce Additional Checkout Fields Conditionally Visible in the Checkout Block

This feature requires a minimum version of WooCommerce 9.9.0

Conditional visibility allows you to create smart, adaptive checkout forms that only show relevant fields when needed, reducing form clutter and improving the customer experience.

## Why Use Conditional Visibility?

Conditional fields help you:

* Reduce form complexity by hiding irrelevant fields
* Create dynamic checkout flows based on customer selections
* Show specialized fields only for specific products or customer types
* Improve conversion rates with cleaner, more focused forms
* Collect contextual information that's only relevant in certain situations

## Understanding JSON Schema for Conditions

WooCommerce’s additional checkout fields use JSON Schema to define conditional logic. Don’t worry if you’re not familiar with JSON Schema – we’ll walk through practical examples that you can adapt for your needs.

The basic structure looks like this:

```php
'required' => [
    // Define when the field must be filled in here
... (410 lines truncated)
</file>

<file path="docs/block-development/tutorials/integrating-protection-checkout-block.md">
---
sidebar_label: Integrating Protection with the Checkout Block
sidebar_position: 6
---

# Integrating Protection with the Checkout Block

If you're a developer of a Captcha or fraud protection plugin, make sure your solution is hooking into the [Store API](/docs/apis/store-api/) and integrating with the Checkout block. This tutorial will guide you through the process of adding protection mechanisms to the WooCommerce Checkout block.

## Overview

The WooCommerce Checkout block uses the [Store API](/docs/apis/store-api/) for processing orders, which provides a secure, unauthenticated API for customer-facing functionality. To integrate protection mechanisms like CAPTCHA or fraud detection, you'll need to:

1. **Render your protection element** in the checkout block using WordPress block filters
2. **Handle client-side validation** using the checkout data store
3. **Validate on the server-side** using the Store API authentication hooks

## Step 1: Rendering Your Protection Element

The first step is to render your CAPTCHA or protection element in the checkout block. You can use the `render_block` filter to inject your HTML before or after specific checkout blocks.

### Using the render_block Filter

The `render_block` filter allows you to modify the output of any WordPress block. For the checkout block, you'll want to target the `woocommerce/checkout-actions-block` which contains the "Place order" button.

```php
add_filter(
    'render_block_woocommerce/checkout-actions-block',
    function( $block_content ) {
        ob_start();
... (153 lines truncated)
</file>

<file path="docs/block-development/_category_.json">
{
    "position": 4,
    "label": "Block development"
}
</file>

<file path="docs/block-development/README.md">
# WooCommerce Block Development

Welcome to the WooCommerce Block Development documentation!  
This section is your starting point for learning how to build, customize, and extend blocks for WooCommerce.

Whether you’re new to block development or looking to deepen your expertise, this guide will walk you through the process step by step, from the basics to advanced extensibility.

## Start Here

- **[Getting Started](/docs/block-development/getting-started/extensibility-overview/)**: Set up your environment and create your first block.
- **[Tutorials](/docs/category/tutorials/)**: Follow hands-on guides to build and enhance your blocks.
- **[Reference](/docs/category/reference/)**: Look up APIs, filters, and block details as you build.
- **[Extensibility](/docs/category/extensible-blocks/)**: Learn to extend and customize blocks for advanced use cases.
- **[Cart & Checkout](/docs/block-development/extensible-blocks/cart-and-checkout-blocks/)** and **[Product Collection](/docs/block-development/extensible-blocks/product-collection-block/)**: Explore specialized block documentation.

Happy building!
</file>

<file path="docs/code-snippets/_category_.json">
{
    "position": 7,
    "label": "Code snippets"
}
</file>

<file path="docs/code-snippets/add-a-country.md">
---
post_title: Add a country
sidebar_label: Add a country

---

# Add a country

Add a country using to your countries list using this code snippet:

```php
if ( ! function_exists( 'YOUR_PREFIX_add_country_to_countries_list' ) ) {
  /**
   * Add a country to countries list
   * 
   * @param array $countries Existing country list.
   * @return array $countries Modified country list.
   */
  function YOUR_PREFIX_add_country_to_countries_list( $countries ) {
    $new_countries = array(
      'NIRE'  => __( 'Northern Ireland', 'YOUR-TEXTDOMAIN' ),
    );

    return array_merge( $countries, $new_countries );
  }
  add_filter( 'woocommerce_countries',  'YOUR_PREFIX_add_country_to_countries_list' );
}

if ( ! function_exists( 'YOUR_PREFIX_add_country_to_continents_list' ) ) {
  /**
... (14 lines truncated)
</file>

<file path="docs/code-snippets/add-a-currency-symbol.md">
---
post_title: Add currencies and symbols
sidebar_label: Add currencies and symbols

---

# Add currencies and symbols

Add custom currencies to your currencies list:

```php
if ( ! function_exists( 'YOUR_PREFIX_add_currency_name' ) ) {
  /**
   * Add custom currency
   * 
   * @param array $currencies Existing currencies.
   * @return array $currencies Updated currencies.
   */
  function YOUR_PREFIX_add_currency_name( $currencies ) {
    $currencies['ABC'] = __( 'Currency name', 'YOUR-TEXTDOMAIN' );

    return $currencies;
  }
  add_filter( 'woocommerce_currencies', 'YOUR_PREFIX_add_currency_name' );
}

if ( ! function_exists( 'YOUR_PREFIX_add_currency_symbol' ) ) {
  /**
   * Add custom currency symbol
   * 
... (15 lines truncated)
</file>

<file path="docs/code-snippets/add-or-modify-states.md">
---
post_title: Add or modify states

---

# Add or modify states

Add your own or modify shipping states in WooCommerce.

> Note: you **must** replace both instances of XX with your country code. This means each state id in the array must have your two letter country code before the number you assign to the state.

```php
if ( ! function_exists( 'YOUR_PREFIX_add_or_modify_states' ) ) {
  /**
   * Add or modify States
   * 
   * @param array $states Existing country states.
   * @return array $states Modified country states.
   */
  function YOUR_PREFIX_add_or_modify_states( $states ) {
    $states['XX'] = array(
      'XX1' => __( 'State 1', 'YOUR-TEXTDOMAIN' ),
      'XX2' => __( 'State 2', 'YOUR-TEXTDOMAIN' ),
    );

    return $states;
  }
  add_filter( 'woocommerce_states', 'YOUR_PREFIX_add_or_modify_states' );
}
```
... (1 lines truncated)
</file>

<file path="docs/code-snippets/adjust-quantity-input-values.md">
---
post_title: Adjust the quantity input values

---

# Adjust the quantity input values

Set the starting value, maximum value, minimum value, and increment amount for quantity input fields on product pages.

```php
if ( ! function_exists( 'YOUR_PREFIX_woocommerce_quantity_input_args' ) ) {
	/**
	 * Adjust the quantity input values for simple products
	 */
	function YOUR_PREFIX_woocommerce_quantity_input_args( $args, $product ) {
		// Only affect the starting value on product pages, not the cart
		if ( is_singular( 'product' ) ) {
			$args['input_value'] = 4;
		}

		$args['max_value'] 	= 10; // Maximum value
		$args['min_value'] 	= 2;  // Minimum value
		$args['step'] 		= 2;  // Quantity steps

		return $args;
	}

	add_filter( 'woocommerce_quantity_input_args', 'YOUR_PREFIX_woocommerce_quantity_input_args', 10, 2 );
}

... (21 lines truncated)
</file>

<file path="docs/code-snippets/before-login--register-form.md">
---
post_title: Add a message above the login / register form

---

# Add a message above the login / register form

This code will add a custom message above the login/register form on the user's my-account page.

```php
if ( ! function_exists( 'YOUR_PREFIX_login_message' ) ) {
    /**
     * Add a message above the login / register form on my-account page
     */
    function YOUR_PREFIX_login_message() {
        if ( get_option( 'woocommerce_enable_myaccount_registration' ) == 'yes' ) {
            ?>
            <div class="woocommerce-info">
            <p><?php _e( 'Returning customers login. New users register for next time so you can:', 'YOUR-TEXTDOMAIN' ); ?></p>
            <ul>
                <li><?php _e( 'View your order history', 'YOUR-TEXTDOMAIN' ); ?></li>
                <li><?php _e( 'Check on your orders', 'YOUR-TEXTDOMAIN' ); ?></li>
                <li><?php _e( 'Edit your addresses', 'YOUR-TEXTDOMAIN' ); ?></li>
                <li><?php _e( 'Change your password', 'YOUR-TEXTDOMAIN' ); ?></li>
            </ul>
            </div>
            <?php
        }
    }
    add_action( 'woocommerce_before_customer_login_form', 'YOUR_PREFIX_login_message' );
... (8 lines truncated)
</file>

<file path="docs/code-snippets/change-a-currency-symbol.md">
---
post_title: Change a currency symbol

---

# Change a currency symbol

In WooCommerce, each currency is associated with a code and a symbol. For example, the Australian dollar has the code `AUD` and the symbol `$` (if you are interested, you can see a full list of codes and symbols in the [source code](https://github.com/woocommerce/woocommerce/blob/9.6.1/plugins/woocommerce/includes/wc-core-functions.php#L682)). 

However, there may be situations where you wish to change the symbol. Taking our example of the Australian dollar, it uses the same symbol as many other dollar currencies and so, in certain situations where this could lead to confusion, it might be useful to change it to `AUD$`. The following snippet outlines how this might be done:

```php
if ( ! function_exists( 'YOUR_PREFIX_change_currency_symbol' ) ) {
  /**
   * Change a currency symbol
   * 
   * @param string $currency_symbol Existing currency symbols.
   * @param string $currency Currency code.
   * @return string $currency_symbol Updated currency symbol(s).
   */  
  function YOUR_PREFIX_change_currency_symbol( $currency_symbol, $currency ) {
    switch ( $currency ) {
      case 'AUD': $currency_symbol = 'AUD$'; break;
    }

    return $currency_symbol;       
  }
  add_filter( 'woocommerce_currency_symbol', 'YOUR_PREFIX_change_currency_symbol', 10, 2 );  
}
```
... (3 lines truncated)
</file>

<file path="docs/code-snippets/check_payment_method_support.md">
---
post_title: Check if a payment method support refunds, subscriptions or pre-orders
sidebar_label: Payment method support for refunds, subscriptions, pre-orders

current wccom url: https://woocommerce.com/document/check-if-payment-gateway-supports-refunds-subscriptions-preorders/
---

# Check if a Payment Method Support Refunds, Subscriptions or Pre-orders

If a payment method's documentation doesn’t clearly outline the supported features, you can often find what features are supported by looking at payment methods code.

Payment methods can add support for certain features from WooCommerce and its extensions. For example, a payment method can support refunds, subscriptions or pre-orders functionality.

## Simplify Commerce example

Taking the Simplify Commerce payment method as an example, open the plugin files in your favorite editor and search for `$this->supports`. You'll find the supported features:

```php
class WC_Gateway_Simplify_Commerce extends WC_Payment_Gateway {    

/**      * Constructor   */
    public function __construct() {
        $this->id
                 = 'simplify_commerce';
        $this->method_title
       = __( 'Simplify Commerce', 'woocommerce' );
        $this->method_description = __( 'Take payments via Simplify Commerce - uses simplify.js to create card tokens and the Simplify Commerce SDK. Requires SSL when sandbox is disabled.', 'woocommerce' );
        $this->has_fields         = true;
        $this->supports           = array(
            'subscriptions',
... (15 lines truncated)
</file>

<file path="docs/code-snippets/configuring_special_tax_scenarios.md">
---
post_title: Code snippets for configuring special tax scenarios
sidebar_label: Configuring special tax scenarios

current wccom url: https://woocommerce.com/document/setting-up-taxes-in-woocommerce/configuring-specific-tax-setups-in-woocommerce/#configuring-special-tax-setups
---

# Code snippets for configuring special tax scenarios

## Scenario A: Charge the same price regardless of location and taxes

If a store enters product prices including taxes, but levies various location-based tax rates, the prices will appear to change depending on which tax rate is applied. In reality, the base price remains the same, but the taxes influence the total. [Follow this link for a detailed explanation](https://woocommerce.com/document/how-taxes-work-in-woocommerce/#cross-border-taxes).

Some merchants prefer to dynamically change product base prices to account for the changes in taxes and so keep the total price consistent regardless of tax rate. Enable that functionality by adding the following snippet to your child theme's functions.php file or via a code snippet plugin.

```php
<?php

add_filter( 'woocommerce_adjust_non_base_location_prices', '__return_false' );
```

## Scenario B: Charge tax based on the subtotal amount

The following snippet is useful in case where a store only ads taxes when the subtotal reaches a specified minimum. In the code snippet below that minimum is 110 of the store's currency. Adjust the snippet according to your requirements. 

```php
<?php

add_filter( 'woocommerce_product_get_tax_class', 'big_apple_get_tax_class', 1, 2 );

... (48 lines truncated)
</file>

<file path="docs/code-snippets/customising-checkout-fields.md">
---
post_title: Customizing checkout fields using actions and filters

---

# Customizing checkout fields using actions and filters

If you are unfamiliar with code and resolving potential conflicts, we have an extension that can help: [WooCommerce Checkout Field Editor](https://woocommerce.com/products/woocommerce-checkout-field-editor/). Installing and activating this extension overrides any code below that you try to implement; and you cannot have custom checkout field code in your functions.php file when the extension is activated.

Custom code should be copied into your child theme's **functions.php** file.

## Note

Some parts of this document only applies to the shortcode Checkout, for adding fields to the Checkout block, consult [the additional checkout fields documentation](/docs/block-development/extensible-blocks/cart-and-checkout-blocks/additional-checkout-fields/).

## How Are Checkout Fields Loaded to WooCommerce?

The billing and shipping fields for checkout pull from the countries class `class-wc-countries.php` and the **`get_address_fields`** function. This allows WooCommerce to enable/disable fields based on the user's location.

Before returning these fields, WooCommerce puts the fields through a _filter_. This allows them to be edited by third-party plugins, themes and your own custom code.

Billing:

```php
$address_fields = apply_filters( 'woocommerce_billing_fields', $address_fields );
```

Shipping:

```php
... (380 lines truncated)
</file>

<file path="docs/code-snippets/customize-failed-order-message.md">
---
post_title: Customize the failed order message
sidebar_label: Customize the failed order message
---

# Customize the failed order message

WooCommerce displays a message on the order confirmation page when an order fails. In WooCommerce 11.2 and later, use the `woocommerce_thankyou_order_failed_text` filter to customize this message in both the classic and block-based order confirmation pages.

The filter receives the current message and the failed order, so the message can include order details:

When packaging this snippet in a plugin or theme, replace `your-text-domain` with the plugin or theme's text domain so its translation catalog can include the message.

```php
/**
 * Customize the message shown for failed orders.
 *
 * @param string   $message Current failed order message.
 * @param WC_Order $order   Failed order.
 * @return string
 */
function your_prefix_customize_failed_order_message( $message, $order ) {
	return sprintf(
		/* translators: %s: Order number. */
		__( 'We could not process order #%s. Please try again or contact us for help.', 'your-text-domain' ),
		esc_html( $order->get_order_number() )
	);
}
add_filter( 'woocommerce_thankyou_order_failed_text', 'your_prefix_customize_failed_order_message', 10, 2 );
```
... (3 lines truncated)
</file>

<file path="docs/code-snippets/disabling_marketplace_suggestions_programmatically.md">
---
post_title: Disabling Marketplace Suggestions Programmatically
sidebar_label: Disabling marketplace suggestions
current wccom url: https://woocommerce.com/document/woocommerce-marketplace-suggestions-settings/#section-6
---

# Disabling Marketplace Suggestions Programmatically


For those who prefer to programmatically disable marketplace suggestions that are fetched from woocommerce.com, add the `woocommerce_allow_marketplace_suggestions` filter to your theme’s `functions.php` or a custom plugin. 

For example: 

```php
add_filter( 'woocommerce_allow_marketplace_suggestions', '__return_false' );
```

This filter will completely remove Marketplace Suggestions from your WooCommerce admin.
</file>

<file path="docs/code-snippets/displaying_custom_fields_in_your_theme_or_site.md">
---
post_title: Displaying custom fields in your theme or site
sidebar_label: Displaying custom fields in theme

current wccom url: https://woocommerce.com/document/custom-product-fields/
---

# Displaying custom fields in your theme or site

You can use the metadata from custom fields you add to your products to display the added information within your theme or site.

To display the custom fields for each product, you have to edit your theme’s files. Here’s an example of how you might display a custom field within the single product pages after the short description:

![image](./_media/custom-field-value.png)

```php
<?php

// Display a product custom field within single product pages after the short description 

function woocommerce_custom_field_example() {

    if ( ! is_product() ) {
        return;
    }
   
    global $product;

    if ( ! is_object( $product ) ) {
        $product = wc_get_product( get_the_ID() );
... (12 lines truncated)
</file>

<file path="docs/code-snippets/free_shipping_customization.md">
---
post_title: Free Shipping Customizations
sidebar_label: Free shipping customizations

current wccom url: https://woocommerce.com/document/free-shipping/#advanced-settings-customization
combined with: https://woocommerce.com/document/hide-other-shipping-methods-when-free-shipping-is-available/#use-a-plugin
---

# Free Shipping Customizations

## Free Shipping: Advanced Settings/Customization

### Overview

By default, WooCommerce shows all shipping methods that match the customer and the cart contents. This means Free Shipping also shows along with Flat Rate and other Shipping Methods. 

The functionality to hide all other methods, and only show Free Shipping, requires either custom PHP code or a plugin/extension.

### Adding code

Before adding snippets, clear your WooCommerce cache. Go to WooCommerce > System Status > Tools > WooCommerce Transients > Clear transients.

## Code Snippets

### How do I only show Free Shipping?

The following snippet will hide all other shipping methods if Free Shipping is available for the customer.

```php
/**
... (93 lines truncated)
</file>

<file path="docs/code-snippets/legacy_local_pickup_advanced_settings_and_customization.md">
---
post_title: Advanced settings and customization for legacy Local Pickup

current wccom url: https://woocommerce.com/document/local-pickup/#advanced-settings-customization
note: Docs links out to Skyverge's site for howto add a custom email - do we have our own alternative?
---

# Advanced settings and customization for legacy Local Pickup

## Disable local taxes when using local pickup

Local Pickup calculates taxes based on your store's location (address) by default, and not the customer's address. Add this snippet at the end of your theme's `functions.php` to use your standard tax configuration instead:

```php
add_filter( 'woocommerce_apply_base_tax_for_local_pickup', '__return_false' );
```

Regular taxes is then used when local pickup is selected, instead of store-location-based taxes. 

## Changing the location for local taxes

To charge local taxes based on the postcode and city of the local pickup location, you need to define the shop's base city and post code using this example code:

```php
add_filter( 'woocommerce_countries_base_postcode', create_function( '', 'return "80903";' ) );
add_filter( 'woocommerce_countries_base_city', create_function( '', 'return "COLORADO SPRINGS";' ) );
```

Update `80903` to reflect your preferred postcode/zip, and `COLORADO SPRINGS` with your preferred town or city.

... (7 lines truncated)
</file>

<file path="docs/code-snippets/link-to-logged-data.md">
---
post_title: Add link to logged data
sidebar_label: Add link to logged data

---

# Add link to logged data

[Logging](/docs/best-practices/data-management/logging) is a crucial part of any WooCommerce extension. It helps you track errors and debug issues. A common pattern is to have a setting in your extension to enable logging when the user needs to troubleshoot an issue. The following code snippet shows an example of how to add this setting, as well as a link to the log viewer, in the context of the [Settings API](/docs/extensions/settings-and-config/settings-api).

```php
use Automattic\WooCommerce\Utilities\LoggingUtil;

// Define the label and description for the logging option
$label = __( 'Enable logging', 'your-textdomain-here' );
$description = __( 'Log events and errors to help with troubleshooting.', 'your-textdomain-here' );

// Check if WooCommerce's logging feature is enabled.
if ( LoggingUtil::logging_is_enabled() ) {
    // The source value you use for your extension's log entries. Could be the same as your text domain.
    $source = 'yourpluginslug';
    
    $logs_url = add_query_arg(
        'source',
        $source,
        LoggingUtil::get_logs_tab_url()
    );
    
    $label .= ' | ' . sprintf(
        __( '<a href="%s">View logs</a>', 'your-textdomain-here' ),
... (14 lines truncated)
</file>

<file path="docs/code-snippets/making_translations_upgrade_safe.md">
---
post_title: Making your translation upgrade safe
sidebar_label: Translation upgrade safety

current wccom url: https://woocommerce.com/document/woocommerce-localization/#making-your-translation-upgrade-safe
---

# Making your translation upgrade safe

Like all other plugins, WooCommerce keeps translations in `wp-content/languages/plugins`. 

However, if you want to include a custom translation, you can add them to `wp-content/languages/woocommerce`, or you can use a snippet to load a custom translation stored elsewhere:

```php
// Code to be placed in functions.php of your theme or a custom plugin file.
add_filter( 'load_textdomain_mofile', 'load_custom_plugin_translation_file', 10, 2 );

/*
 * Replace 'textdomain' with your plugin's textdomain. e.g. 'woocommerce'. 
 * File to be named, for example, yourtranslationfile-en_GB.mo
 * File to be placed, for example, wp-content/lanaguages/textdomain/yourtranslationfile-en_GB.mo
 */
function load_custom_plugin_translation_file( $mofile, $domain ) {
  if ( 'textdomain' === $domain ) {
    $mofile = WP_LANG_DIR . '/textdomain/yourtranslationfile-' . get_locale() . '.mo';
  }
  return $mofile;
}
```
</file>

<file path="docs/code-snippets/number-of-products-per-row.md">
---
post_title: Change number of related products displayed

---

# Change number of related products displayed

Add code to your child theme's functions.php file or via a plugin that allows custom functions to be added, such as the [Code snippets](https://wordpress.org/plugins/code-snippets/) plugin. Avoid adding custom code directly to your parent theme's `functions.php` file as this will be wiped entirely when you update the theme.

Please note that it does not work for all themes because of the way they're coded.

```php
if ( ! function_exists( 'YOUR_PREFIX_related_products_args' ) ) {
	/**
	 * Change number of related products output.
	 *
	 * @param  array $args The related products args.
	 * @return array The modified related products args.
	 */
	function YOUR_PREFIX_related_products_args( $args ) {
		if ( ! is_array( $args ) ) {
			$args = array();
		}

		$args['posts_per_page'] = 4; // 4 related products.
		$args['columns']        = 2; // Arranged in 2 columns.

		return $args;
	}
}
... (3 lines truncated)
</file>

<file path="docs/code-snippets/override-loop-template-show-quantities-next-add-cart.md">
---
post_title: Override loop template and show quantities next to add to cart buttons

---

# Override loop template and show quantities next to add to cart buttons

Add this code to your child theme’s `functions.php` file or via a plugin that allows custom functions to be added, such as the [Code Snippets](https://wordpress.org/plugins/code-snippets/) plugin. Avoid adding custom code directly to your parent theme’s functions.php file, as this will be wiped entirely when you update the theme.

```php
if ( ! function_exists( 'YOUR_PREFIX_quantity_inputs_for_woocommerce_loop_add_to_cart_link' ) ) {
  /**
   * Override loop template and show quantities next to add to cart buttons
   * @param  string $html    Default loop template.
   * @param  object $product Product data.
   * @return string          Modified loop template.
   */
	function YOUR_PREFIX_quantity_inputs_for_woocommerce_loop_add_to_cart_link( $html, $product ) {
		if ( $product && $product->is_type( 'simple' ) && $product->is_purchasable() && $product->is_in_stock() && ! $product->is_sold_individually() ) {
			$html  = '<form action="' . esc_url( $product->add_to_cart_url() ) . '" class="cart" method="post" enctype="multipart/form-data">';
			$html .= woocommerce_quantity_input( array(), $product, false );
			$html .= '<button type="submit" class="button alt">' . esc_html( $product->add_to_cart_text() ) . '</button>';
			$html .= '</form>';
		}

		return $html;
	}
	add_filter( 'woocommerce_loop_add_to_cart_link', 'YOUR_PREFIX_quantity_inputs_for_woocommerce_loop_add_to_cart_link', 10, 2 );
}
```
... (1 lines truncated)
</file>

<file path="docs/code-snippets/prevent-po-box-addresses-in-checkout-block.md">
---
post_title: Prevent PO Box addresses in the Checkout block
sidebar_label: Prevent PO Box addresses in Checkout block
---

# Prevent PO Box addresses in the Checkout block

The Checkout block uses the Store API checkout flow, so shortcode checkout hooks such as `woocommerce_after_checkout_validation` do not run there. To validate orders submitted through the Checkout block, use the `woocommerce_checkout_validate_order_before_payment` hook.

The following snippet checks the shipping address when one exists, and falls back to billing details when checkout does not include a separate shipping address. Add it with the Code Snippets plugin and set it to run everywhere.

```php
/**
 * Prevent Checkout block orders from using PO Box addresses.
 *
 * @param WC_Order $order  Checkout order.
 * @param WP_Error $errors Validation errors.
 */
function wc_prevent_checkout_block_po_box_addresses( $order, $errors ) {
	$address = $order->has_shipping_address()
		? $order->get_shipping_address_1() . ' ' . $order->get_shipping_address_2()
		: $order->get_billing_address_1() . ' ' . $order->get_billing_address_2();

	$postcode = $order->has_shipping_address()
		? $order->get_shipping_postcode()
		: $order->get_billing_postcode();

	$normalized_address = strtolower( str_replace( array( ' ', '.', ',' ), '', $address . ' ' . $postcode ) );

	if ( false !== strpos( $normalized_address, 'pobox' ) ) {
... (11 lines truncated)
</file>

<file path="docs/code-snippets/README.md">
---
sidebar_label: Code Snippets
category_slug: code-snippets
post_title: Using the Code Snippets Plugin for WooCommerce Customizations
sidebar_position: 1
---

# Using the Code Snippets Plugin

## What is a Code Snippet?  

Customizing WooCommerce functionality often requires adding code snippets to modify behavior, enhance features, or integrate with third-party tools. Instead of editing theme files or the `functions.php` file directly, we recommend using the **Code Snippets** plugin from the WordPress.org repository. This approach ensures a safer, more manageable, and more organized way to add custom code to your WooCommerce store.  

## Why Use the Code Snippets Plugin?  

Editing your theme’s `functions.php` file or adding custom code directly to WooCommerce files can lead to several issues:  

- **Loss of Custom Code on Theme Updates:** When you update your theme, modifications made in `functions.php` are lost.  
- **Potential for Errors and Site Breakage:** A single syntax error can make your website inaccessible.  
- **Difficult Debugging:** Managing multiple customizations in a single `functions.php` file can become unorganized.  

The **Code Snippets** plugin addresses these issues by allowing you to:  

- Add, activate, and deactivate snippets without modifying core files.  
- Organize custom snippets with descriptions and tags.  
- Avoid losing changes when updating your theme or WooCommerce.  
- Debug and test code safely before deploying to a live site.  

## How to Install the Code Snippets Plugin  

... (35 lines truncated)
</file>

<file path="docs/code-snippets/rename-a-country.md">
---
post_title: Rename a country

---

# Rename a country

Rename a country in your countries list:

```php
if ( ! function_exists( 'YOUR_PREFIX_rename_country' ) ) {
  /**
   * Rename a country
   *
   * @param array $countries Existing country names
   * @return array $countries Updated country name(s)
   */
  function YOUR_PREFIX_rename_country( $countries ) {
     $countries['IE'] = __( 'Ireland (Changed)', 'YOUR-TEXTDOMAIN' );

     return $countries;
  }
  add_filter( 'woocommerce_countries', 'YOUR_PREFIX_rename_country' );
}
```
</file>

<file path="docs/code-snippets/ssl_and_https_and_woocommerce_websites_behind_load_balanacers_or_reverse_proxies.md">
---
post_title: SSL and HTTPS and WooCommerce
sidebar_label: SSL and HTTPS and WooCommerce

current wccom url: https://woocommerce.com/document/ssl-and-https/#websites-behind-load-balancers-or-reverse-proxies
---

# SSL and HTTPS and WooCommerce

## Websites behind load balancers or reverse proxies

WooCommerce uses the `is_ssl()` WordPress function to verify if your website using SSL or not.

`is_ssl()` checks if the connection is via HTTPS or on Port 443. However, this won't work for websites behind load balancers, especially websites hosted at Network Solutions. For details, read [WordPress is_ssl() function reference notes](https://codex.wordpress.org/Function_Reference/is_ssl#Notes).

Websites behind load balancers or reverse proxies that support `HTTP_X_FORWARDED_PROTO` can be fixed by adding the following code to the `wp-config.php` file, above the require_once call:

```php
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
    $_SERVER['HTTPS'] = 'on';
}
```

**Note:** If you use CloudFlare, you need to configure it. Check their documentation.
</file>

<file path="docs/code-snippets/unhook--remove-woocommerce-emails.md">
---
post_title: Unhook and remove WooCommerce emails

---

# Unhook and remove WooCommerce emails

This code allows you to unhook and remove the default WooCommerce emails.

```php
if ( ! function_exists( 'YOUR_PREFIX_unhook_woocommerce_emails' ) ) {
	/**
	 * Callback for woocommerce_email action hook
	 *
	 * @param WC_Email $email_class An Email class instance.
	 * @return void
	 */
	function YOUR_PREFIX_unhook_woocommerce_emails( $email_class ) {
		/**
		 * Hooks for sending emails during store events.
		 */
		remove_action( 'woocommerce_low_stock_notification', array( $email_class, 'low_stock' ) );
		remove_action( 'woocommerce_no_stock_notification', array( $email_class, 'no_stock' ) );
		remove_action( 'woocommerce_product_on_backorder_notification', array( $email_class, 'backorder' ) );

		// New order emails.
		remove_action( 'woocommerce_order_status_pending_to_processing_notification', array( $email_class->emails['WC_Email_New_Order'], 'trigger' ) );
		remove_action( 'woocommerce_order_status_pending_to_completed_notification', array( $email_class->emails['WC_Email_New_Order'], 'trigger' ) );
		remove_action( 'woocommerce_order_status_pending_to_on-hold_notification', array( $email_class->emails['WC_Email_New_Order'], 'trigger' ) );
		remove_action( 'woocommerce_order_status_failed_to_processing_notification', array( $email_class->emails['WC_Email_New_Order'], 'trigger' ) );
... (17 lines truncated)
</file>

<file path="docs/code-snippets/uninstall_remove_all_woocommerce_data.md">
---
post_title: Uninstall and remove all WooCommerce Data
sidebar_label: Uninstalling and removing data

current wccom url: https://woocommerce.com/document/installing-uninstalling-woocommerce/#uninstalling-woocommerce
---

# Uninstall and remove all WooCommerce Data

The WooCommerce plugin can be uninstalled like any other WordPress plugin. By default, the WooCommerce data is left in place though. 

If you need to remove *all* WooCommerce data as well, including products, order data, coupons, etc., you need to to modify the site's `wp-config.php` *before* deactivating and deleting the WooCommerce plugin.

As this action is destructive and permanent, the information is provided as is. WooCommerce Support cannot help with this process or anything that happens as a result. 

To fully remove all WooCommerce data from your WordPress site, open `wp-config.php`, scroll down to the bottom of the file, and add the following constant on its own line above `/* That's all, stop editing. */`.

```php
define( 'WC_REMOVE_ALL_DATA', true );

/* That's all, stop editing! Happy publishing. */ 
```

Then, once the changes are saved to the file, when you deactivate and delete WooCommerce, all of its data is removed from your WordPress site database.

![Uninstall WooCommerce WPConfig](https://woocommerce.com/wp-content/uploads/2020/03/uninstall_wocommerce_plugin_wpconfig.png)

## Removing the Action Scheduler tables

WooCommerce uses [Action Scheduler](https://actionscheduler.org/) to run background tasks. Action Scheduler is a shared library that other plugins can also bundle, so its database tables (`actionscheduler_actions`, `actionscheduler_claims`, `actionscheduler_groups` and `actionscheduler_logs`) are **not** removed by `WC_REMOVE_ALL_DATA`, even when the constant is set to `true`. Keeping them avoids deleting scheduled tasks that another active plugin might still rely on.
... (12 lines truncated)
</file>

<file path="docs/code-snippets/useful-functions.md">
---
post_title: Useful core functions

---

# Useful core functions

WooCommerce core functions are available on both front-end and admin. They can be found in `includes/wc-core-functions.php` and can be used by themes in plugins.

## Conditional Functions

WooCommerce conditional functions help determine the current query/page.

### is_woocommerce

Returns true if on a page which uses WooCommerce templates (cart and checkout are standard pages with shortcodes and thus are not included).

```php
is_woocommerce()
```

### is_shop

Returns true when viewing the product type archive (shop).

```php
is_shop()
```

### is_product
... (285 lines truncated)
</file>

<file path="docs/code-snippets/using_nginx_server_to_protect_your_uploads_directory.md">
---
post_title: Using NGINX server to protect your upload directory
sidebar_label: NGINX server to protect upload directory

current wccom url: https://woocommerce.com/document/digital-downloadable-product-handling/#protecting-your-uploads-directory
---

# Using NGINX server to protect your upload directory

If you using NGINX server for your site along with **X-Accel-Redirect/X-Sendfile** or **Force Downloads** download method, it is necessary that you add this configuration for better security:

```php
# Protect WooCommerce upload folder from being accessed directly.
# You may want to change this config if you are using "X-Accel-Redirect/X-Sendfile" or "Force Downloads" method for downloadable products.
# Place this config towards the end of "server" block in NGINX configuration.
location ~* /wp-content/uploads/woocommerce_uploads/ {
    if ( $upstream_http_x_accel_redirect = "" ) {
        return 403;
    }
    internal;
}
```

And this the configuration in case you are using **Redirect only** download method:

```php
# Protect WooCommerce upload folder from being accessed directly.
# You may want to change this config if you are using "Redirect Only" method for downloadable products.
# Place this config towards the end of "server" block in NGINX configuration.
location ~* /wp-content/uploads/woocommerce_uploads/ {
... (6 lines truncated)
</file>

<file path="docs/contribution/contributing/common-issues.md">
---
post_title: Common issues
sidebar_label: Common issues

---

# Common issues

This page aims to document a comprehensive list of known issues, commonly encountered problems, and their solutions or workarounds. If you have encountered an issue that is not mentioned here and should be, please don't hesitate to add to the list.

## Composer error on `Automattic\Jetpack\Autoloader\AutoloadGenerator`

```bash
[ErrorException]
  Declaration of Automattic\Jetpack\Autoloader\AutoloadGenerator::dump(Composer\Config $config, Composer\Repository\Inst
  alledRepositoryInterface $localRepo, Composer\Package\PackageInterface $mainPackage, Composer\Installer\InstallationMa
  nager $installationManager, $targetDir, $scanPsrPackages = false, $suffix = NULL) should be compatible with Composer\A
  utoload\AutoloadGenerator::dump(Composer\Config $config, Composer\Repository\InstalledRepositoryInterface $localRepo,
  Composer\Package\RootPackageInterface $rootPackage, Composer\Installer\InstallationManager $installationManager, $targ
  etDir, $scanPsrPackages = false, $suffix = '')
```

A recent [change](https://github.com/composer/composer/commit/b574f10d9d68acfeb8e36cad0b0b25a090140a3b#diff-67d1dfefa9c7b1c7e0b04b07274628d812f82cd82fae635c0aeba643c02e8cd8) in composer 2.0.7 made our autoloader incompatible with the new `AutoloadGenerator` signature. Try to downgrading to composer 2.0.6 by using `composer self-update 2.0.6`.

## VVV: HostsUpdater vagrant plugin error

```bash
...vagrant-hostsupdater/HostsUpdater.rb:126:in ``digest': no implicit conversion of nil into String (TypeError)
```

... (90 lines truncated)
</file>

<file path="docs/contribution/contributing/community-contributions.md">
---
sidebar_label: Community contributions
category_slug: contributing
post_title: Community contributions
---

# Community contributions

WooCommerce is open-source software that welcomes community contributions. To help us review your contribution quickly, please follow these guidelines.

## Before you submit

1. **Link to a related issue** - If one exists, reference it in your PR. Before starting work, comment on the issue (particularly when it already has an assignee) to avoid duplicate effort and check that it's been triaged by the maintainers. If you're proposing a new feature or significant change, [open an issue](https://github.com/woocommerce/woocommerce/issues/new/choose) first to discuss it.

2. **Run tests locally** - Some of the CI workflows are not automatically triggered for community contributions, so please verify your changes pass relevant tests and linting locally before submitting.

3. **Consolidate related changes** - If you have multiple similar fixes (e.g., typos, documentation updates), combine them into a single PR when appropriate.

## PR requirements

When you open a PR, you'll receive an immediate review from our AI code reviewer. Before a maintainer reviews your PR, please:

1. **Fill out the entire PR template** - Include a clear description of your changes and test steps.
2. **Respond to all AI review feedback** - Review automated feedback and either address it, or explain why it does not apply.
3. **Confirm tests pass** - Note in your PR that you've run the test suite locally.

## AI-assisted contributions

We welcome AI-assisted contributions, but the same quality standards apply whether code is written by hand or with AI tools. As the contributor, you are responsible for:

... (20 lines truncated)
</file>

<file path="docs/contribution/contributing/CSS-SASS-coding-guidelines-and-naming-conventions.md">
---
post_title: CSS SASS coding guidelines and naming conventions

---

# CSS SASS coding guidelines and naming conventions

Our guidelines are based on those used in [Calypso](https://github.com/Automattic/wp-calypso) which itself follows the BEM methodology. Refer to [this doc](https://wpcalypso.wordpress.com/devdocs/docs/coding-guidelines/css.md?term=css) for full details. There are a few differences in WooCommerce however which are outlined below;

## Prefixing

As a WordPress plugin WooCommerce has to play nicely with WordPress core and other plugins / themes. To minimise conflict potential all classes should be prefixed with `.woocommerce-`.

## Class names

Calypso is built in React and uses component names to formulate CSS class names. WooCommerce Core has none of these components so uses a more traditional [BEM](http://getbem.com/) approach to [naming classes](http://cssguidelin.es/#bem-like-naming). 

When adding classes just remember;

* **Block** - Standalone entity that is meaningful on its own.
* **Element** - Parts of a block and have no standalone meaning. They are semantically tied to its block.
* **Modifier** - Flags on blocks or elements. Use them to change appearance or behaviour.

### Example

* `.woocommerce-loop {}` (block).
* `.woocommerce-loop-product {}` (nested block).
* `.woocommerce-loop-product--sale {}` (modifier).
* `.woocommerce-loop-product__link {}` (element).
* `.woocommerce-loop-product__title {}` (element).
... (16 lines truncated)
</file>

<file path="docs/contribution/contributing/deciding-pr-high-impact.md">
---
post_title: How to assess the impact of a pull request
sidebar_label: Assessing PR impact

---

# How to assess the impact of a pull request

Deciding if a Pull Request should be declared High-Impact is a complex task. To achieve it, we need to assess and estimate the impact that the changes introduced in the Pull Request have in WooCommerce, which is usually a subjective task and sometimes inaccurate, due to the huge knowledge it demands of the WooCommerce product details, technical details and even customers issues history.

On this page, we will share some guidelines to help you assess the impact degree of a Pull Request.

## You should mark a Pull Request as High-Impact if

- It adds a **new feature** to WooCommerce, except if it's behind a feature flag.
- Modifies **critical functionality** that shoppers or merchants rely on to run a store.
- It fixes a **high-priority bug** (this includes Blocks fix releases core version bumps).
- It contains a **security fix**.
- Changes affecting **privacy** (how personal or store data is collected, stored, or shared).
- Updates **SQL queries**.
- Touches any of the **$_REQUEST** family of variables.
- Any kind of **data migration/update**, or other changes affecting **data integrity**.
- Changes affecting **backward compatibility** (public APIs, hook signatures or timing, templates, or anything third-party code consumes).
- Changes to **performance-sensitive paths**.
- Changes to **emails** sent from WooCommerce.
- Changes to WooCommerce **hooks/actions/filters**.
- Changes to **REST API endpoints**.
- It's a **big PR** (i.e. adds several changes in many files).
- It has **i18n changes** (for example, any file from `woocommerce/i18n` is modified).

... (36 lines truncated)
</file>

<file path="docs/contribution/contributing/deprecation-in-core.md">
---
post_title: Deprecation in core
sidebar_label: Deprecation in core

---

# Deprecation in core

Deprecation is a method of discouraging usage of a feature or practice in favour of something else without breaking backwards compatibility or totally prohibiting its usage. To quote the Wikipedia article on Deprecation:

> While a deprecated software feature remains in the software, its use may raise warning messages recommending alternative practices; deprecated status may also indicate the feature will be removed in the future. Features are deprecated rather than immediately removed, to provide backward compatibility and give programmers time to bring affected code into compliance with the new standard.

There are various reasons why a function, method, or feature may be deprecated. To name a few:

- We may want to remove a function we do not use any longer.
- We may decide to change or improve how a function works, but due to breaking backwards compatibility we need to deprecate the old function instead.
- We may want to standardise naming conventions.
- We may find opportunities to merge similar functions to avoid reusing the same code in difference places.

Whilst deprecation notices are not ideal or attractive, they are just _warnings_ - not errors. 

_*Store owners:* deprecation warnings do not mean your store is broken, it just serves as a reminder that code will need to be updated._

## How do we deprecate functions?

When we deprecate something in WooCommerce, we take a few actions to make it clear to developers and to maintain backwards compatibility.

1. We add a docblock to the function or method showing what version the function was deprecated in, e.g., `@deprecated 2.x.x`.
2. We add a warning notice using our own `wc_deprecated_function` function that shows what version, what function, and what replacement is available. More on that in a bit.
3. We remove usage of the deprecated function throughout the codebase.
... (54 lines truncated)
</file>

<file path="docs/contribution/contributing/minification-of-SCSS-and-JS.md">
---
post_title: Handling SCSS and JS minification in WooCommerce
sidebar_label: Minification of SCSS and JS

---

# Handling SCSS and JS minification in WooCommerce

## SCSS

When updating SCSS files in the WooCommerce project, please **commit only your changes to unminified SCSS files**. The minification will be handled as part of the release process.

To get the minified CSS files, run `pnpm --filter='@woocommerce/classic-assets' build` from the repository root directory. To set up the development environment from scratch, see the section on [how to install dependencies and generate assets](https://github.com/woocommerce/woocommerce/blob/trunk/DEVELOPMENT.md) in the guide to set up a WooCommerce development environment.

## Javascript

When changing the JS files, please **commit only unminified files** (i.e. the readable JS files). The minification will be handled as part of the release process.

To ensure you can test your changes, run with `SCRIPT_DEBUG` turned on, i.e. add `define( 'SCRIPT_DEBUG', true );` to your wp-config.php file.
</file>

<file path="docs/contribution/contributing/naming-conventions.md">
---
post_title: Naming conventions
sidebar_label: Naming conventions

---

# Naming conventions

## PHP

WooCommerce core generally follows [WordPress PHP naming conventions](https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#naming-conventions). On top of that, function, class, and hook names should be prefixed. For functions the prefix is `wc_`, for classes is `WC_` and for hooks is `woocommerce_`.

Function name examples:

- `wc_get_product()`
- `wc_is_active_theme()`

Class name examples:

- `WC_Breadcrumb`
- `WC_Cart`

Hook name examples (actions or filters):

- `woocommerce_after_checkout_validation`
- `woocommerce_get_formatted_order_total`

There are however some exceptions which apply to classes defined inside `src/`. Within this directory:

- We do not use the `WC_` prefix for class names (the prefix is not needed, because all of the classes in this location live within the `Automattic\WooCommerce` namespace)
... (23 lines truncated)
</file>

<file path="docs/contribution/contributing/README.md">
---
sidebar_label: Contribute to Woo 
category_slug: contributing
post_title: Contribute to Woo
---

# Contribute to Woo

Interested in joining the Woo contributor community? The links in this doc summarize and direct you to the order of operations you will need to make your first contribution. If you are a seasoned WooCommerce developer, feel free to skip ahead and utilize the template links, or the reference docs and guides below.

## Contributing to WooCommerce Core

The WooCommerce core plugin code can be found in our [monorepo](https://github.com/woocommerce/woocommerce). Here you can contribute to: 

- [WooCommerce Core Plugin](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce)
- [WooCommerce Blocks](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks) 

## Setting up your development environment

Please check out [our getting started guide](https://github.com/woocommerce/woocommerce#getting-started) for information about prerequisites and initial setup.

We also have [more in-depth documentation](https://github.com/woocommerce/woocommerce/blob/trunk/DEVELOPMENT.md) on how to develop in our repository. This also includes information about how to set up the development environment.

## Code of Conduct

Contributing to an open source project requires cooperation amongst individuals and organizations all working to make our project a stable and safe place to build and ask questions. Please thoroughly read our [Code of Conduct](https://github.com/woocommerce/woocommerce/blob/trunk/CODE_OF_CONDUCT.md) to get familiar with our standards and processes.

## Contributor Guidelines

Our [contributor guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/.github/CONTRIBUTING.md) layout the first steps to contributing.
... (21 lines truncated)
</file>

<file path="docs/contribution/contributing/reporting-security-issues.md">
---
post_title: Reporting security issues
sidebar_label: Reporting security issues

---

# Reporting security issues

WooCommerce cares deeply about security and works hard to keep our merchants and their customers safe. 

You can find our security policy [over here](https://github.com/woocommerce/woocommerce/security/policy) and, if you believe you have discovered a vulnerability, we encourage you to follow it and submit your findings via [HackerOne](https://hackerone.com/automattic?type=team)-a trusted third party service that facilitates reporting of security issues. Please refer to the policy for more details, however some key points are as follows:

- We operate a [bug bounty program](https://hackerone.com/automattic?type=team), so you can be rewarded for valid reports, but not everything is in scope. Please check the guidance before posting.
- We strongly encourage [responsible disclosure](https://www.hackerone.com/disclosure-guidelines). To better protect everyone, please use HackerOne and **do not** post your findings in a public forum.

Thank you for being a responsible reporter!
</file>

<file path="docs/contribution/contributing/string-localisation-guidelines.md">
---
post_title: String localization
sidebar_label: String localization
---

# String localization

WooCommerce is translation-ready out of the box. This page covers how to write localizable strings, contribute translations, create custom translations, and update locale-specific data such as countries and subdivisions.

## Translating WooCommerce

WooCommerce is already translated into several languages and only needs a translation file for your language. In most cases, you can contribute translations on [translate.wordpress.org](https://translate.wordpress.org/projects/wp-plugins/woocommerce/).

To create custom translations, you can also use a tool such as [Poedit](https://poedit.net/).

### Set up WordPress in your language

To set your WordPress site's language:

1. Go to `WP Admin > Settings > General` and adjust the `Site Language`.
2. Go to `WP Admin > Dashboard > Updates` and click the `Update Translations` button.

Once this has been done, the shop displays in your locale if the language file exists. Otherwise, you need to create the language files.

### Writing localizable strings

1. Use the `woocommerce` textdomain in all strings.
2. When using dynamic strings in `printf()` or `sprintf()`, use numbered arguments if you are replacing more than one string. For example, `Test %s string %s.` should be `Test %1$s string %2$s.`
3. Use sentence case. For example, `Some Thing` should be `Some thing`.
4. Avoid HTML. If needed, insert the HTML using `sprintf()`.
... (147 lines truncated)
</file>

<file path="docs/contribution/contributing/version-support-policy.md">
---
sidebar_label: Version support policy
category_slug: contributing
post_title: WordPress and WooCommerce version support policy
---

# WordPress and WooCommerce version support policy

Woo uses a latest-minus-one (L-1) policy for WordPress and WooCommerce version
compatibility. This policy defines the versions that we officially test and
support as dependencies; it is separate from entitlement to customer support services.

L-1 includes:

- The current stable release series (latest).
- The stable release series immediately before it (latest minus one).

Within each release series, only the latest patch release is officially
supported. For example, if `6.8` and `6.7` are the two supported release
series, testing should use the latest available `6.8.x` and `6.7.x` releases.

## How the policy applies

| Project | Supported versions |
| --- | --- |
| WooCommerce Core | The latest and immediately previous WordPress release series. |
| Woo-owned extensions | The latest and immediately previous release series of both WordPress and WooCommerce. |

The policy for WooCommerce Core refers to the versions of WordPress on which
Core runs. Woo-owned extensions also depend on WooCommerce, so they apply L-1
... (36 lines truncated)
</file>

<file path="docs/contribution/contributing/woocommerce-git-flow.md">
---
post_title: WooCommerce Git Flow
sidebar_label: WooCommerce Git Flow

---

# WooCommerce Git Flow

## Conventions

### Branch Naming

While we don't enforce any naming conventions except for release branches (which always start with `release/`), prefixes help indicate the type of branch or change they refer to. Some common prefixes include `fix/`, `feature/`, `add/`, and `update/`.

In particular, when creating a **fix branch**, use the correct prefix and the issue number (e.g., `fix/12345`) or summarize the change (e.g., `fix/12345-shipping-tax-rate-saving`).

## Releases

For core development, we use the following structure and flow.

![Release Cycle flow chart](/img/doc_images/release-branches.png)

Refer to the [release schedule](/docs/contribution/releases/schedule) document for more details.
</file>

<file path="docs/contribution/contributing-docs/contributing-docs.md">
---
post_title: Contributing technical documentation
sidebar_label: Contributing docs
---

# Contributing technical documentation

Thanks for helping improve WooCommerce's developer documentation. Our docs are powered by Docusaurus, and live inside the [`woocommerce/docs/`](https://github.com/woocommerce/woocommerce/tree/trunk/docs) folder of the monorepo.

This guide walks you through the structure, tooling, and process for contributing effectively.

## Getting started 

> This guide presumes that you're familiar with basic Git and GitHub functionality, that you're signed into a GitHub account, and that you have Git setup locally. If you're new to GitHub, we recommend reading their [quickstart](https://docs.github.com/en/get-started/quickstart/hello-world) and [working with forks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) guides before getting started.

### Initial setup

1. Fork the [WooCommerce monorepo](https://github.com/woocommerce/woocommerce) on GitHub. If asked, you can safely check the `copy the trunk branch only` option.
2. [Clone the fork that you just created](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository). This will allow you to edit it locally.

### Making changes

1. Prior to making any changes, ensure your `trunk` branch is up to date with the monorepo's `trunk` [by syncing it](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork).
2. For each modification you'd like to make, create a new branch off `trunk` in your fork that starts with `docs/`. For example, if you're adding a doc about improving extension performance, you could call your branch `docs/improve-extension-performance`.
3. Create or edit markdown files inside the appropriate folder under `docs/`.
4. If needed, update the folder's `_category_.json` (for sidebar label/position).
5. Run a build to verify changes, confirm that the sitemaps and llms-txt files are updated, and detect markdown linting errors and broken links (link checking only happens on build):

    ```bash
    npm run build
... (72 lines truncated)
</file>

<file path="docs/contribution/contributing-docs/style-guide.md">
---
post_title: Technical documentation style guide
sidebar_label: Style guide
---

# Technical Documentation Style Guide

This style guide is intended to provide guidelines for creating effective and user-friendly tutorials and how-to guides for WooCommerce technical documentation that will live in repo and be editable and iterative by open source contributors and WooCommerce teams.

## Writing style

### Language style

- It's important to use clear and concise language that is easy to understand. Use active voice and avoid using jargon or technical terms that may be unfamiliar to the user. The tone should be friendly and approachable, and should encourage the user to take action.

- Articles are written in the 3rd-person voice.
  Example: "Add an embed block to your page."

- Use American English for spelling and punctuation styles, or consider using a different word that doesn't have a different spelling in other English variants.

- Use sentence case (not title case) for docs titles and subheadings.
  Example: "Introduction to the launch experience" rather than "Introduction to the Launch Experience."

- When referring to files or directories, the text formatting eliminates the need to include articles such as "the" and clarifying nouns such as "file" or "directory".
  Example: "files stored in ~~the~~ `/wp-content/uploads/` ~~directory~~" or "edit ~~the~~ `/config/config.yml` ~~file~~ with"

### Writing tips

- Our target audience has a range of roles and abilities. When creating a tutorial or how-to guide, it's important to consider the intended audience. Are they beginners or advanced users? What is their technical background? Understanding the audience can help guide the level of detail and the choice of language used in the guide.

... (144 lines truncated)
</file>

<file path="docs/contribution/releases/backporting.md">
---
post_title: Cherry-picking in WooCommerce
sidebar_label: Cherry-picking
sidebar_position: 3
---

# Cherry-picking in WooCommerce

Cherry-picking is the process of applying changes between `trunk` and a release branch (in either direction). This page is the canonical reference for the cherry-pick mechanics used by both pre-release stabilization (beta, RC) and patch releases.

For the patch-release-specific process (when a patch is warranted, who creates the tracking issue, and how it ships), see the [Point Releases guide](/docs/contribution/releases/point-releases).

## Release Branch Lifecycle

When a release branch is created, it is copied from `trunk` at the time of feature freeze. After creation:

- The release branch no longer receives new feature updates.
- Only critical changes are allowed.
- Because we do not merge release branches back into `trunk`, any fix landed on a release branch must also be applied to `trunk` (and, when applicable, to the next frozen release branch).

### What "frozen release" means

A frozen release branch is the most recent `release/x.y` cut from `trunk` for the next upcoming version. While the previous release is still in maintenance, this branch is the one feature work has already moved on to. The `cherry pick to frozen release` label forward-ports a fix from the current maintenance branch to this branch so the same fix also ships in the next major version. Frozen releases only accept critical bug fixes, the same bar as any other release branch.

## Qualifying Changes for Cherry-picking

Changes qualify for cherry-picking only if they are:

- **Bug fixes** that affect the release.
- **Performance improvements** that impact WooCommerce functionality.
... (30 lines truncated)
</file>

<file path="docs/contribution/releases/building-and-publishing.md">
---
post_title: Building and Publishing a Release
sidebar_label: Building and Publishing
sidebar_position: 1
---

# Building and Publishing a Release

:::important

While this guide can be used as reference, keep in mind that version-specific instructions are provided in the [release tracking issues](https://github.com/woocommerce/woocommerce/issues?q=state%3Aopen%20label%3A%22Release%22%20author%3Aapp%2Flinear%20tracking) created ahead of the release cycle, and should be preferred.

:::

This page provides an overview of the steps required to build any WooCommerce release from the release branch. Review the flowchart to understand the overall process and the decision table. Step-by-step instructions are provided below.

## Overview

![Release Process flow chart](/img/doc_images/release-process.png)

## Instructions

Perform all the steps below in order. When running _any_ GitHub workflow, ensure you do it from the `trunk` branch (the default) and input the release version or branch as indicated.

Keep the _[Release Troubleshooting & Recovery](/docs/contribution/releases/troubleshooting)_ guide handy, in case you encounter any issues.

### Steps

#### 1. Pre-build checks

... (49 lines truncated)
</file>

<file path="docs/contribution/releases/decision-matrix.md">
---
post_title: Release Decision Matrix
sidebar_label: Decision Matrix
sidebar_position: 5
---

# Release Decision Matrix

Every finding against a release gets a verdict - at the readiness review, at the go/no-go, and when weighing whether an already-shipped issue warrants a point release. This page is the criteria for picking that verdict. The decision points themselves are described in [Readiness and Go/No-Go](/docs/contribution/releases/readiness); the criteria apply to Core and Woo-owned extension releases, for all release types.

The matrix guides the people making the call - the release lead and the Product DRI. It does not change which automated checks gate a build.

## Verdicts

| Verdict | Meaning |
| --- | --- |
| **Release-blocking** | The release does not ship with this issue in it: hold the date or remove the change. Found after shipping: point release now. |
| **Fix in a point release** | Ship on schedule. The fix has an issue, an owner, and a target release *before* the go decision - without those, it re-enters as release-blocking. |
| **Next release** | Ship. The fix rides the next scheduled release. |
| **Not a bug** | Expected behavior, or an invalid finding. |

A finding no one can reproduce - tried on at least two independent stacks - gets **Next release, with a named owner**: it does not block the release, and the issue stays open rather than being closed as not a bug. A finding that reproduces anywhere keeps its impact-class verdict.

## Default verdict by impact class

| Impact class | Default verdict | Example |
| --- | --- | --- |
| Checkout or revenue interruption - a store cannot take payments | Release-blocking; no modifiers apply | - |
| Site down or fatal on load, in Core or any Woo-owned extension - including older extension versions running with the new Core | Release-blocking | [#64394](https://github.com/woocommerce/woocommerce/pull/64394) forced the revert after 10.9.0; [#65957](https://github.com/woocommerce/woocommerce/pull/65957) rescheduled 11.0.0 after a fatal surfaced on an early deployment |
| Data loss or corruption | Release-blocking | - |
... (37 lines truncated)
</file>

<file path="docs/contribution/releases/monitoring.md">
---
post_title: WooCommerce Release Monitoring
sidebar_label: Release Monitoring
sidebar_position: 7
---

# WooCommerce Release Monitoring

After the release, the release lead should continue to monitor the following for any bugs directly related to the latest version.  Monitoring should continue for 3 days after a major release and 1 day for a point release.

If there are questions whether a specific issue is critical enough to warrant a new point release, check the [release decision matrix](/docs/contribution/releases/decision-matrix) first; for genuine ties, start a discussion in the `#woo-core-releases` Slack channel.

## WordPress.org Forums

Check newly created threads on the [WordPress.org Forums](https://wordpress.org/support/plugin/woocommerce/) for any issues that appear to be caused by the latest update.

## WooCommerce GitHub Repository Issues

Watch the [Newest Created Issues](https://github.com/woocommerce/woocommerce/issues?q=is%3Aissue%20state%3Aopen%20sort%3Acreated-desc) and verify that none are critical.

## Extension Fatal-Error Alerts

Every Woo-owned extension has a Grafana fatal-error alert on WP Cloud, backed by the internal *Woo\* Fatals on WP Cloud* dashboard. Alerts post to the owning team's channel and to `#woo-core-releases-notifications`. Watch that channel during the monitoring window.

When an alert fires, open the linked dashboard panel to see how many sites are affected, then reply on the alert to ping the owning team - triage is theirs. If the fatal traces back to the release, treat it as a candidate critical issue (see below).

An old extension version can point to a compatibility issue, but it does not prove the release caused the fatal. Compare the affected WooCommerce and extension versions before calling it a non-regression.

## Handling Critical Issues

... (4 lines truncated)
</file>

<file path="docs/contribution/releases/package-releases.md">
---
post_title: WooCommerce Package Releases
sidebar_label: Package Releases
sidebar_position: 8
---

# JavaScript Package Releases

The WooCommerce monorepo includes numerous JavaScript packages to support WooCommerce development, such as `@woocommerce/components`, distributed via NPM. This release process is managed via GitHub Actions.

For the full documentation on how to release a JavaScript package, see the [package release tool documentation](https://github.com/woocommerce/woocommerce/tree/trunk/tools/package-release).
</file>

<file path="docs/contribution/releases/point-releases.md">
---
post_title: WooCommerce Point Releases
sidebar_label: Point Releases
sidebar_position: 2
---

# Point Releases

:::important
The formal Point Release Request (PRR) issue template ([`new-prr-template.yml`](https://github.com/woocommerce/woocommerce/blob/trunk/.github/ISSUE_TEMPLATE/new-prr-template.yml)) is no longer required for point release fixes; it is preserved only for reference. In practice, coordinating directly with the release lead is sufficient to get fixes included in a point release, and is the most important step. The rest of this document covers what types of fixes qualify for point releases and how to prepare them in the repository.
:::

Point releases are patch releases that address specific issues in an already-shipped WooCommerce version (for example `9.9.0 → 9.9.1`) without adding new functionality. They apply only to versions that are already in customer production environments.

## What qualifies as a point release

Changes appropriate for a point release are:

- **Critical bug fixes** affecting store functionality (checkout, orders, payments, product visibility).
- **Security patches** for urgent vulnerabilities ([which versions receive them](/docs/contribution/releases/security-support)).
- **Severe performance regressions** introduced by the shipped release.
- **Compliance fixes** required for regulatory or legal reasons.
- **Compatibility fixes** for WordPress, theme, or plugin conflicts that are breaking stores.

The following are **not** point release material and should ride the next regular release instead:

- New features or enhancements.
- Non-critical bug fixes.
- Code refactoring or cleanup.
- Documentation updates.
... (42 lines truncated)
</file>

<file path="docs/contribution/releases/prereleases.md">
---
post_title: WooCommerce Pre-releases
sidebar_label: WooCommerce Pre-releases
sidebar_position: 5
---

# WooCommerce Pre-releases

WooCommerce pre-releases provide early access to upcoming features and improvements, allowing developers, testers, and the community to prepare for future releases.

This document outlines the different types of pre-releases available, their timing, and how they fit into the overall release cycle.

| Release Name      | Estimated Timing                                                |
|-------------------|-----------------------------------------------------------------|
| `nightly`         | Every night                                                     |
| `-dev`            | At feature freeze                                               |
| `-beta.1`         | 1 week after feature freeze                                     |
| `-beta.2`, ...    | At least 1 more, as needed before `-rc.1`                       |
| `-rc.1`           | Shortly (~1 day) before final release                           |
| `-rc.2`, ...      | As needed, when a critical bug is detected during RC monitoring |

## Nightlies

Regenerated every night based on the current contents of `trunk`. Found [under the `nightly` tag on GitHub](https://github.com/woocommerce/woocommerce/releases/tag/nightly).

These are only available in the GitHub repository, and are neither announced publicly nor uploaded to WordPress.org.

## Release cycle pre-releases

Once the feature freeze for the upcoming main version (`X.Y.0`) happens, a release-specific branch is created (named `release/x.y`) which is used for stabilization, fixing regressions, and building all the pre-releases tied to that release cycle.
... (31 lines truncated)
</file>

<file path="docs/contribution/releases/readiness.md">
---
post_title: Release Readiness and Go/No-Go
sidebar_label: Readiness and Go/No-Go
sidebar_position: 4
---

# Release Readiness and Go/No-Go

Two explicit decision points anchor every release cycle. Both live as checklists in the release tracking sub-issues, so each release leaves a written trail of what was checked, what was decided, and by whom. This page explains what each point is for; the checklists themselves are in the sub-issues the [Release: Assignment workflow](/docs/contribution/releases/workflows) creates.

## Release roles

Each cycle has two named owners, listed on the parent tracking issue:

* **Release lead** (engineering) - runs the release process end to end: builds, publishes, monitors, and executes the run-books.
* **Product DRI** - the product-side counterpart. Joins the readiness review at RC and the go/no-go before stable, and owns the product read on open findings: what blocks the release, what waits for a point release, and what ships with a known-issues note.

The release lead is assigned by rotation via the [Release: Assignment workflow](/docs/contribution/releases/workflows). The Product DRI role is covered by two standing Product seats in Slack's `@woo-core-release` group. Their names are on the tracking issue. If you're unsure who to loop in, ping the handle.

The handle also holds a standing set of engineering members and the current and previous release leads, who rotate at each feature freeze.

## Readiness review (at RC)

The RC is the last point where finding a problem is cheap: nothing has shipped, and delaying costs a day, not a revert. The review runs before the RC build starts and answers one question - is there anything we know about that should stop this release?

The checklist covers four areas:

* **Compatibility evidence.** The QIT compatibility regression sweep runs automatically against each prerelease and reports which extension versions the release would break. Introduced issues need a verdict, not just a look.
* **Open findings.** Bug reports, testing threads, and monitoring alerts against the release each get a linked issue and a verdict per the [release decision matrix](/docs/contribution/releases/decision-matrix): release-blocking, fix in a point release, next release, or not a bug.
* **Rollback path.** Who reverts, how, and what revert means for this version - answered before it's needed, not during an incident.
... (12 lines truncated)
</file>

<file path="docs/contribution/releases/README.md">
---
post_title: Releasing WooCommerce
sidebar_label: Releases
---

# Releasing WooCommerce

The WooCommerce release process is managed by a rotating release lead, alongside two standing Product DRI seats in `@woo-core-release` (see [release roles](/docs/contribution/releases/readiness#release-roles)).  The documentation below outlines the process for managing releases.  To get started with a new release, see [Building and Publishing WooCommerce](/docs/contribution/releases/building-and-publishing).

## Process Overview

* [Building and Publishing](/docs/contribution/releases/building-and-publishing)
* [Readiness and Go/No-Go](/docs/contribution/releases/readiness)
* [Decision Matrix](/docs/contribution/releases/decision-matrix)
* [Troubleshooting](/docs/contribution/releases/troubleshooting)
* [Point Releases](/docs/contribution/releases/point-releases)
* [Security Support](/docs/contribution/releases/security-support)
* [Cherry-picking](/docs/contribution/releases/backporting)
* [Pre-releases](/docs/contribution/releases/prereleases)
* [Release Schedule](/docs/contribution/releases/schedule)
* [Release Monitoring](/docs/contribution/releases/monitoring)
* [Package Releases](/docs/contribution/releases/package-releases)
* [Workflows](/docs/contribution/releases/workflows)
</file>

<file path="docs/contribution/releases/schedule.md">
---
post_title: WooCommerce Release Schedule
sidebar_label: Release Schedule
sidebar_position: 6
---

# WooCommerce Release Schedule

WooCommerce operates on a predictable release schedule, delivering updates with new features, enhancements, and bug fixes roughly every five weeks.
This page summarizes the main stages of our release process, such as feature freeze, beta and release candidate periods, and the timing of final and patch releases.

Additional details on how the release cycle looks inside the monorepo can be found on our [Git Flow docs](/docs/contribution/contributing/woocommerce-git-flow)

:::tip

To view the actual schedule for current and upcoming releases, see our [release calendar](https://developer.woocommerce.com/release-calendar/).

:::

![Release Cycle flow chart](/img/doc_images/release-cycle.png)

## Milestones

### Feature Freeze & `-dev` release (day 1)

As a result of the feature freeze automation, a few things happen:

- A dedicated release branch is created (`release/x.y`), where the future release undergoes testing and stabilization. No new features are included on this branch, only bug fixes.
- A `-dev` release is built and made available on GitHub.
- Development of new features continues on `trunk`.
... (41 lines truncated)
</file>

<file path="docs/contribution/releases/security-support.md">
---
post_title: WooCommerce Security Patch Support Policy
sidebar_label: Security Support
sidebar_position: 10
---

# Security Patch Support Policy

When a security fix warrants it (CVSS score >=9), WooCommerce will provide security patches for the **last 21 major versions**. If the current stable WooCommerce version is 11.1, that means version **9.1 and newer**. Otherwise, we publish fixes for the latest version.

"Major version" follows WooCommerce's release numbering (`10.8`, `10.9`, `11.0`, ...), not semantic versioning. At the current release cadence, 21 major versions correspond to roughly two years of releases.

## What this means

- When the impact of a security issue warrants it (CVSS score >=9) - security fixes are backported to every supported major version affected by the vulnerability (within the established support window), and ship as [point releases](/docs/contribution/releases/point-releases).
- Versions older than the support window do not receive security patches. Stores on unsupported versions must update to a supported version to receive fixes.
- The window is a rolling count: each new major release moves the floor up by one version.

## Exceptions

For some classes of critical vulnerabilities, we may as a courtesy, backport outside the established policy.

## Reporting

Security vulnerabilities must be reported privately through Automattic's HackerOne program: [https://hackerone.com/automattic/](https://hackerone.com/automattic/). Never report them in public issues.

## Keeping this page current

When the stable release of a new major version is published, an automated workflow opens a pull request that bumps the minimum supported version on this page. The release DRI reviews and merges it as part of the post-release tasks.
</file>

<file path="docs/contribution/releases/troubleshooting.md">
---
post_title: Release Troubleshooting
sidebar_label: Troubleshooting
sidebar_position: 7
---

# Release Troubleshooting & Recovery

This page provides guidance for troubleshooting and recovering from issues that may arise during the WooCommerce release process. It covers common scenarios, recommended actions, and best practices to help ensure releases are handled smoothly and any problems are resolved efficiently.

:::tip

`@woo-core-release` in `#woo-core-releases` is the point of contact for release-process questions in general, not just the scenarios below. Use it for escalations, second opinions, or anything this doc doesn't answer.

:::

## Scenarios / FAQ

### A workflow failed while building the release

1. **Open the workflow run details** in GitHub (under the **Actions** tab) to see exactly where and why the failure occurred. Most of the time, the workflow will display a clear error message.
2. **Read the error message carefully.** Sometimes the problem is as simple as a missing workflow configuration or skipped step.
3. **If you're unsure what the error means or how to proceed,** don't hesitate to ask for help in the release Slack channel. It's better to get a second opinion than to guess.

⚠️ _Do not re-run any workflows until you understand the cause of the failure._ Re-running without fixing the root issue can make things more complicated.

### CI is failing on a release-related PR

During the release process, you may encounter CI test failures on release-related PRs. These failures sometimes occur because test fixes were merged to trunk but not backported to the release branch before it was cut.

... (89 lines truncated)
</file>

<file path="docs/contribution/releases/workflows.md">
---
post_title: Release Workflows
sidebar_label: Workflows
sidebar_position: 9
---

# Release Workflows

The WooCommerce release process is supported by a set of GitHub Actions workflows that automate repetitive tasks, enforce process guardrails, and send notifications. This page provides a reference of all release-related workflows, organized by how they are triggered.

All workflows are defined in the [`.github/workflows/`](https://github.com/woocommerce/woocommerce/tree/trunk/.github/workflows) directory.

## Scheduled workflows

These workflows run automatically on a daily schedule.

| Workflow | Schedule | What it does | When it acts |
| -------- | -------- | ------------ | ------------ |
| [Release: Assignment](https://github.com/woocommerce/woocommerce/blob/trunk/.github/workflows/release-assignment.yml) | Daily at 18:00 UTC | Checks the [release calendar](https://developer.woocommerce.com/release-calendar/), assigns the release lead, and creates the parent tracking issue along with the four standard sub-issues for the cycle: `beta.1`, `beta.2`, `rc.1`, and the final `.0` release. Calls *Create Tracking Issue* for each sub-issue. Also triggers an internal post announcing the new release lead to the team. Tracking issues for patch releases, extra RCs, or extra betas are **not** created by this workflow; see the note below the "Tracking and analysis" table. | ~8 weeks before feature freeze. |
| [Release: Enforce Feature Freeze](https://github.com/woocommerce/woocommerce/blob/trunk/.github/workflows/release-code-freeze.yml) | Daily at 18:00 UTC | Checks the [release calendar](https://developer.woocommerce.com/release-calendar/) and creates the release branch from `trunk`, bumps `trunk` to the next dev version, publishes a dev release, cleans up old milestones, and sends Slack notifications. Calls *Bump version number* and *Build ZIP file*. Also triggers an internal call for testing to canonical extension teams. | On the feature freeze date. |
| [Release: Feature highlight notification](https://github.com/woocommerce/woocommerce/blob/trunk/.github/workflows/release-feature-highlights-notification.yml) | Daily at 09:00 UTC | Checks the [release calendar](https://developer.woocommerce.com/release-calendar/) and sends a Slack reminder to teams about the upcoming feature freeze deadline. | ~1 week before feature freeze. |
| [Release: Open Issue Warning](https://github.com/woocommerce/woocommerce/blob/trunk/.github/workflows/release-open-issue-warning.yml) | Daily at 18:00 UTC | Checks the [release calendar](https://developer.woocommerce.com/release-calendar/) and looks for open items in release milestones, sending a Slack notification listing them with assignees. | Within 72 hours of a release date. |
| [Nightly builds](https://github.com/woocommerce/woocommerce/blob/trunk/.github/workflows/nightly-builds.yml) | Daily at 00:00 UTC | Builds a nightly ZIP from `trunk` and uploads it to a GitHub release. Runs every day, independent of the release calendar. | Every day. |

## Event-driven workflows

These workflows are triggered automatically by GitHub events such as pull requests being merged, releases being published, or issues being labeled.

### Cherry-pick and backport

... (53 lines truncated)
</file>

<file path="docs/contribution/testing/beta-testing.md">
---
post_title: Beta Testing

---

# Beta Testing

Beta testing is vital to ensuring our releases are as bug free as possible and to ensure we hear user feedback before putting changes live. Anyone can beta test; shop owners, plugin developers, theme developers, translators, any and all help is welcome.

We do understand however that the process of testing can be a little bit of a hassle since you need to download a tagged release and then upload it to your testing site manually. Sometimes this can also cause issues with plugin directory naming as well, because tagged releases will not have a directory named `woocommerce`. This can break extensions.

To make this process easier, we have released a beta testing plugin to help install the WooCommerce beta versions, and to ensure the directory names are kept correct.

Please ensure you test responsibly, it is not a good idea to run beta versions on a production site unless you have experience and can anticipate changes and failures.

## Installing the Beta Tester Plugin

To get started, go to Plugins > Add New > Upload plugin, and install the beta tester plugin which you can download from:

[WooCommerce Beta Tester](https://woocommerce.com/products/woocommerce-beta-tester/)

This plugin will give you access to all of the WooCommerce versions uploaded to [WordPress.org]. This includes beta releases and release candidates.

## Giving Feedback

During testing, if you come across a bug or want to propose or contribute an enhancement, [submit an issue on GitHub](https://github.com/woocommerce/woocommerce/issues/new?assignees=&labels=type%3A+enhancement%2Cstatus%3A+awaiting+triage&template=2-enhancement.yml&title=%5BEnhancement%5D%3A+). Ensure you read our guidelines on contributing and note which version you are using specifically. It is also possible to easily submit a new GitHub issue through the [beta tester plugin](https://woocommerce.com/products/woocommerce-beta-tester/).

Sometimes we may also ask for feedback via other means, such as the surveys and calls for testing on the [developer blog](https://developer.woocommerce.com/blog/). We appreciate immediate feedback, comments, and responses to surveys as it helps us judge how well received our releases and betas are and will help us shape future versions.

Thanks for testing WooCommerce!
... (1 lines truncated)
</file>

<file path="docs/contribution/testing/core-critical-flows.md">
---
post_title: WooCommerce core critical flows
sidebar_label: Core critical flows
---

# WooCommerce core critical flows

We have identified what we consider to be our most critical user flows within WooCommerce Core. These flows will help us focus and prioritize our testing efforts. They will also help us consider the impact of changes and priority of issues.

These flows will continually evolve as the platform evolves with flows updated, added or re-prioritised.

## Shopper critical flow areas

-   [Shopper > Shop](#shopper---shop)
-   [Shopper > Product](#shopper---product)
-   [Shopper > Cart](#shopper---cart)
-   [Shopper > Checkout](#shopper---checkout)
-   [Shopper > Email](#shopper---email)
-   [Shopper > My Account](#shopper---my-account)

## Merchant critical flow areas

-   [Merchant > Onboarding](#merchant---onboarding)
-   [Merchant > Dashboard](#merchant---dashboard)
-   [Merchant > Settings](#merchant---settings)
-   [Merchant > Coupons](#merchant---coupons)
-   [Merchant > Marketing](#merchant---marketing)
-   [Merchant > Analytics](#merchant---analytics)
-   [Merchant > Products](#merchant---products)
-   [Merchant > Orders](#merchant---orders)
... (248 lines truncated)
</file>

<file path="docs/contribution/testing/README.md">
---
sidebar_label: Testing
category_slug: testing
post_title: Testing
---

# Testing

Setting up your test environment and writing tests when contributing to WooCommerce Core are essential parts of our development pipeline. The links below are also included in our [Contributing Guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/.github/CONTRIBUTING.md) on GitHub.

If you have questions about testing, reach out to the developer community in our public channels: [Developer Blog](https://developer.woocommerce.com/blog/), [GitHub Discussions](https://github.com/woocommerce/woocommerce/discussions), or [Community Slack](https://woocommerce.com/community-slack/).

## Unit testing

[Unit tests](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/tests/README.md) run against the WooCommerce PHP test suite. The recommended local setup uses `wp-env`.

## End-to-end testing

[End-to-end tests](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/tests/e2e) are powered by Playwright. The test site is spun up using `wp-env`.

## API testing

[API tests](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/tests/e2e/tests/api-tests) are part of the Playwright suite and use the same `wp-env` test environment as end-to-end tests.

## Testing instructions

When opening a pull request, use the [testing instructions guide](/docs/contribution/testing/writing-high-quality-testing-instructions/) to write clear steps that cover the behavior changed in the PR.

## Calls for testing

... (2 lines truncated)
</file>

<file path="docs/contribution/testing/writing-high-quality-testing-instructions.md">
---
post_title: Writing high quality testing instructions
sidebar_label: Writing testing instructions

---

# Writing high quality testing instructions

## Introduction

Having clear testing Instructions on pull requests is the first level of quality engineering in WooCommerce, which is key for testing early and minimizing the impact of unexpected effects in the upcoming versions of WooCommerce.

This page contains the following sections:

-   [What is a test?](#what-is-a-test)
-   [What to cover with the testing instructions](#what-to-cover-with-the-testing-instructions)
-   [Flow to write good testing instructions](#flow-to-write-good-testing-instructions)
-   [Examples](#examples)

## What is a test?

A test is a method that we can use to check that something meets certain criteria. It is typically defined as a procedure which contains the steps required to put the system under test in a certain state before executing the action to be checked. Therefore, a test consists of the following stages:

-   **Preconditions:** All the steps that need to be performed to put the system in the desired state before executing the action we want to check. A test could have many preconditions.
-   **Action:** This is the exact step that causes the change we want to check in the system. It should be only one because each test should ideally cover one thing at a time.
-   **Validation:** Relates to the steps to be performed in order to validate the result of performing the action in the system. A test could validate more than one thing.

For example, in the process of adding an item to the cart:

-   The **preconditions** would be all the steps involved in:
... (103 lines truncated)
</file>

<file path="docs/contribution/_category_.json">
{
    "position": 8,
    "label": "Contribution"
}
</file>

<file path="docs/extensions/best-practices-extensions/_category_.json">
{
    "position": 5,
    "label": "Best practices",
    "link": {
        "type": "generated-index",
        "title": "Best practices",
        "slug": "/extensions/best-practices-extensions"
    }
}
</file>

<file path="docs/extensions/best-practices-extensions/accessibility.md">
---
post_title: Accessibility Standards for WooCommerce extensions
sidebar_label: Accessibility
sidebar_position: 1
---

# Accessibility Best Practices

In many places around the world, ecommerce stores are required to be accessible to people with disabilities. As a WooCommerce extension developer, your code directly impacts the accessibility of the shops that use it and can impact merchants’ compliance with accessibility laws.

This page is a resource for developers who want to ensure their extensions comply with accessibility standards and best practices. It is recommended that all WooCommerce extensions follow accessibility best practices to provide the best experience for merchants and their customers.

## Accessibility Laws

Two examples of laws that require ecommerce websites to be accessible include the [Americans with Disabilities Act (ADA)](https://ada.gov/) in the United States and the [European Accessibility Act (EAA)](https://employment-social-affairs.ec.europa.eu/policies-and-activities/social-protection-social-inclusion/persons-disabilities/union-equality-strategy-rights-persons-disabilities-2021-2030/european-accessibility-act_en), a directive that applies to all EU member countries. There are also laws requiring website accessibility in Australia, Canada, Israel, and many other countries. The W3C maintains a list of [web accessibility laws worldwide](https://www.w3.org/WAI/policies/) if you want to research laws in your country.

Most laws require websites to conform to Web Content Accessibility Guidelines (WCAG) as a measure of accessibility. To ensure that merchants can use your extension on their websites, it should also be WCAG conformant. 

If your extension is not WCAG conformant, you may receive complaints about accessibility issues from merchants. You may also be included in lawsuits or legal cases about accessibility problems caused by your extension. 

## Web Content Accessibility Guidelines (WCAG)

The [Web Content Accessibility Guidelines (WCAG)](https://www.w3.org/TR/WCAG22) are internationally recognized standards designed to make websites accessible to everyone, including people with disabilities. WCAG is made up of *success criteria* (specific, testable rules) that fall under four key principles:

### Four Key Principles

- **Perceivable**  
  Content should be available in ways users can perceive, even if they do not have all five senses. Information should be transformable from one form to another (e.g., text alternatives for images or captions for videos).

- **Operable**  
... (136 lines truncated)
</file>

<file path="docs/extensions/best-practices-extensions/compatibility.md">
---
post_title: Compatibility and interoperability for WooCommerce extensions
sidebar_label: Compatibility

---

# Compatibility and interoperability for WooCommerce extensions

Ensuring your WooCommerce extension is compatible and interoperable with the core platform, various components, and other extensions is fundamental to providing a seamless experience for users. This document covers the importance of compatibility, the process for self-declared compatibility checks, manual testing for compatibility issues, and troubleshooting common problems.

## Compatibility importance

Compatibility ensures that your extension works as expected across different environments, including various versions of WordPress and WooCommerce, as well as with other plugins and themes. Ensuring compatibility is crucial for:

- **User experience**: Preventing conflicts that can lead to functionality issues or site downtime.
- **Adoption and retention**: Users are more likely to install and keep updates if they're assured of compatibility.
- **Security and performance**: Compatible extensions are less likely to introduce vulnerabilities or degrade site performance.

## Self-declared compatibility checks

Developers should declare their extension's compatibility with the latest versions of WordPress and WooCommerce, as well as with specific components like Cart & Checkout blocks, High Performance Order Storage (HPOS), Product Editor, and Site Editor. This process involves:

1. **Testing**: Before release, thoroughly test the extension with the latest versions of WordPress and WooCommerce, as well as the specified components.
2. **Declaration**: Update the extension's documentation and metadata to reflect its compatibility with these platforms and components.
3. **Communication**: Inform users of the compatible versions in the extension's change log, website, or repository.

## Manual compatibility testing

Manual testing is essential to identify and resolve potential compatibility issues. Follow these steps for effective manual compatibility testing:

... (32 lines truncated)
</file>

<file path="docs/extensions/best-practices-extensions/extension-development-best-practices.md">
---
post_title: WooCommerce extension development best practices
sidebar_label: Best practices
sidebar_position: 3
---

# WooCommerce extension development best practices

Want to create a plugin to extend WooCommerce? You're in the right place.

WooCommerce extensions are the same as regular WordPress plugins. For more information, visit [Writing a plugin](https://developer.wordpress.org/plugins/).

Your WooCommerce extension should:

- Adhere to all WordPress plugin coding standards, as well as [best practice guidelines](https://developer.wordpress.org/plugins/plugin-basics/best-practices/) for harmonious existence within WordPress and alongside other WordPress plugins.
- Have a single core purpose and use WooCommerce features as much as possible.
- Not do anything malicious, illegal, or dishonest - for example, inserting spam links or executable code via third-party systems if not part of the service or  explicitly permitted in the service's terms of use.
- Not subvert or override Marketplace connections in core — for example, extensions cannot create branded top-level menu items or introduce their own telemetry.
- Adhere to WooCommerce [compatibility and interoperability guidelines](https://woocommerce.com/document/marketplace-overview/#section-9).

Merchants make use of WooCommerce extensions daily, and should have a unified and pleasant experience while doing so without advertising invading their WP Admin or store.

## Best Practices

1. **Check if WooCommerce is active**. Most WooCommerce plugins do not need to run unless WooCommerce is already active. [Learn how to check if WooCommerce is active](/docs/extensions/core-concepts/check-if-woo-is-active).
2. **The main plugin file should adopt the name of the plugin**. For example: A plugin with the directory name `plugin-name` would have its main file named `plugin-name.php`.
3. **The text domain should match your plugin directory name**. For example: A plugin with a directory name of `plugin-name` would have the text domain `plugin-name`. Do not use underscores. 
4. **Internationalization**: Follow guidelines for [Internationalization for WordPress Developers](https://codex.wordpress.org/I18n_for_WordPress_Developers)
5. **Localization**: All text strings within the plugin code should be in English. This is the WordPress default locale, and English should always be the first language. If your plugin is intended for a specific market (e.g., Spain or Italy), include appropriate translation files for those languages within your plugin package. Learn more at [Using Makepot to translate your plugin](https://codex.wordpress.org/I18n_for_WordPress_Developers#Translating_Plugins_and_Themes).
6. **Follow WordPress PHP Guidelines**. WordPress has a [set of guidelines](http://make.wordpress.org/core/handbook/coding-standards/php/) to keep all WordPress code consistent and easy to read. This includes quotes, indentation, brace style, shorthand php tags, yoda conditions, naming conventions, and more. Please review the guidelines.
... (18 lines truncated)
</file>

<file path="docs/extensions/best-practices-extensions/gdpr-compliance.md">
---
post_title: GDPR compliance guidelines for WooCommerce extensions
sidebar_label: GDPR compliance

---

# GDPR compliance guidelines for WooCommerce extensions

## Introduction

The General Data Protection Regulation (GDPR) is in effect, granting EU residents increased rights over their personal data. Developers must ensure that WooCommerce extensions are compliant with these regulations.

## Data sharing and collection

### Third-party data sharing

- Assess and document any third-party data sharing.
- Obtain and manage user consent for data sharing.
- Link to third-party privacy policies in your plugin settings.

### Data collection

- List the personal data your plugin collects.
- Secure consent for data collection and manage user preferences.
- Safeguard data storage and restrict access to authorized personnel.

## Data access and storage

### Accessing personal data

... (51 lines truncated)
</file>

<file path="docs/extensions/best-practices-extensions/privacy-standards.md">
---
post_title: Privacy standards for WooCommerce extensions
sidebar_label: Privacy standards

---

# Privacy Standards for WooCommerce extensions

Privacy and data protection are becoming increasingly important online, and WooCommerce extensions are no exception. This document outlines the key markers of quality regarding privacy for WooCommerce extensions, the current methods for testing compliance, and the standards developers should adhere to ensure user trust and legal compliance.

## Standards for privacy

To maintain high privacy standards, developers of WooCommerce extensions should adhere to the following:

### Presence of privacy policy page

- A privacy policy should be readily available and easy to understand. It must clearly describe the types of data collected by the extension, the purpose of data collection, how data is processed and stored, and the users' rights concerning their data.

### No unauthorized external requests

- All resources required by the extension should be hosted within the plugin folder/zip file unless there's a clear, justified reason for external requests, which should then be disclosed in the privacy policy.
- Unauthorized or undisclosed external requests, especially those that could expose user data to third-party services without consent, are strictly against privacy standards.

### GDPR compliance

For guidance on ensuring your WooCommerce extension complies with the General Data Protection Regulation (GDPR), please refer to our detailed documentation on [GDPR compliance](./gdpr-compliance.md).

## Conclusion

Adhering to privacy standards is essential for WooCommerce extension developers to build trust with users and ensure compliance with legal requirements. By establishing a clear privacy policy and avoiding unauthorized external requests, developers can demonstrate their commitment to privacy and data protection. Regular testing and compliance checks will help maintain these standards and protect user data effectively.
... (1 lines truncated)
</file>

<file path="docs/extensions/best-practices-extensions/support-and-documentation.md">
---
post_title: Support and documentation for WooCommerce extensions
sidebar_label: Support and documentation

---

# Support and documentation for WooCommerce extensions

Effective support and comprehensive documentation are fundamental to the success of any WooCommerce extension. They not only enhance the user experience but also facilitate easier maintenance and development. This document outlines the best practices for creating documentation, providing support, and establishing feedback mechanisms.

## Creating effective documentation

Good documentation serves as a guide, helping users understand and utilize your extension to its full potential. It can significantly reduce the volume of support requests by answering common questions and troubleshooting typical issues.

### Importance of good documentation

- **User Autonomy**: Allows users to solve problems independently.
- **Reduced Support Load**: Comprehensive documentation can answer many user questions, reducing the need for direct support.
- **Improved User Satisfaction**: Users are more satisfied with the product when they can easily find information.

### How to create effective documentation

- **User-friendly language**: Write in clear, simple language accessible to users of all skill levels.
- **Comprehensive coverage**: Cover all features of your extension, including setup, configuration, troubleshooting, and FAQs.
- **Accessibility**: Ensure documentation is easy to navigate with a clear structure and search functionality.
- **Regular updates**: Keep the documentation up to date with the latest version of the extension.

### Standards for documentation

- **Presence of public documentation**: Ensure that users have access to basic documentation that covers essential information about the extension.
... (39 lines truncated)
</file>

<file path="docs/extensions/core-concepts/_category_.json">
{
    "position": 2,
    "label": "Core concepts",
    "link": {
      "type": "doc",
      "id": "README"
    }
}
</file>

<file path="docs/extensions/core-concepts/adding-actions-and-filters.md">
---
post_title: How to add actions and filters
sidebar_label: Actions and filters
sidebar_position: 2

---

# How to add actions and filters

Like many WordPress plugins, WooCommerce provides a range of actions and filters through which developers can extend and modify the platform.

Often, when writing new code or revising existing code, there is a desire to add new hooks-but this should always be done with thoughtfulness and care. This document aims to provide high-level guidance on the matter.

Practices we generally allow, support and encourage include:

* [Using existing hooks (or other alternatives) in preference to adding new hooks](#prefer-existing-hooks-or-other-alternatives)
* [Adding lifecycle hooks](#adding-lifecycle-hooks)
* [Optional escape hooks](#escape-hooks)
* [Modifying the inputs and outputs of global rendering functions](#modifying-function-input-and-output-global-rendering-functions)
* [Preferring the passing of objects over IDs](#prefer-passing-objects-over-ids)

On the flip side, there are several practices we discourage:

* [Tying lifecycle hooks to methods of execution](#tying-lifecycle-hooks-to-methods-of-execution)
* [Using filters as feature flags](#using-filters-as-feature-flags)
* [Placing filter hooks inside templates and data stores](#placement-of-filter-hooks)
* [Enumeration values within hook names](#enumeration-values-inside-hook-names)

Beyond those items, we generally otherwise adhere to WordPress coding standards. In regards to hooks, that specifically means following the:

... (171 lines truncated)
</file>

<file path="docs/extensions/core-concepts/changelog-txt.md">
---
post_title: Formatting for Changelog.txt
sidebar_label: Changelog.txt
---

# Formatting for Changelog.txt

## The changelog.txt file

WooCommerce extensions use a standard changelog format. A changelog.txt file is required for extensions on the WooCommerce Marketplace.

Your `changelog.txt` file should look like this:

```php
*** WooCommerce Extension Name Changelog ***

YYYY-MM-DD - version 1.1.0
* Added - Useful new feature
    * A second new feature
    * A third new feature
* Fixed - Important bug fix
* Update - Compatibility with latest version

YYYY-MM-DD - version 1.0.1
* Fixed a bug

YYYY-MM-DD - version 1.0.0
* Initial release
```

... (28 lines truncated)
</file>

<file path="docs/extensions/core-concepts/check-if-woo-is-active.md">
---
post_title: How to check if WooCommerce is active
sidebar_label: Check if WooCommerce is active

---

# How to check if WooCommerce is active

When developing for WooCommerce, ensuring that WooCommerce is installed and active before your code runs is crucial. This prevents errors related to missing WooCommerce functions or classes.

There are a few methods to achieve this. The first is to execute your code on the `woocommerce_loaded` action. This approach guarantees that WooCommerce and its functionalities are fully loaded and available for use. This is fired around the same time as the core `plugins_loaded` action. 

```php
add_action( 'woocommerce_loaded', 'prefix_woocommerce_loaded' );

function prefix_woocommerce_loaded() {
	// Custom code here. WooCommerce is active and all plugins have been loaded...
}
```

**Note**: At this stage, WordPress has not yet initialized the current user data.

Another method is to execute your code on the `woocommerce_init` action. This is executed right _after_ WooCommerce is active and initialized. This action (and the `before_woocommerce_init` action) fires in the context of the WordPress `init` action so at this point current user data has been initialized.

```php
add_action( 'woocommerce_init', 'prefix_woocommerce_init' );

function prefix_woocommerce_init() {
	// Custom code here. WooCommerce is active and initialized...
}
... (21 lines truncated)
</file>

<file path="docs/extensions/core-concepts/class-reference.md">
---
post_title: Classes in WooCommerce
sidebar_label: Classes
sidebar_position: 1

---

# Classes in WooCommerce

## List of Classes in WooCommerce

For a list of Classes in WooCommerce, please see the [WooCommerce Code Reference](https://woocommerce.github.io/code-reference/packages/WooCommerce-Classes.html).

## Common Classes

### WooCommerce

The main class is `woocommerce` which is available globally via the `$woocommerce` variable. This handles the main functions of WooCommerce and init's other classes, stores site-wide variables, and handles error/success messages. The woocommerce class initializes the following classes when constructed:

-   `WC_Query` - stored in `$woocommerce->query`
-   `WC_Customer` - stored in `$woocommerce->customer`
-   `WC_Shipping` - stored in `$woocommerce->shipping`
-   `WC_Payment_Gateways` - stored in `$woocommerce->payment_gateways`
-   `WC_Countries` - stored in `$woocommerce->countries`

Other classes are auto-loaded on demand.

View the [WooCommerce Class Code Reference](https://woocommerce.github.io/code-reference/classes/WooCommerce.html) for a full list of methods contained in this class.

### WC_Product
... (42 lines truncated)
</file>

<file path="docs/extensions/core-concepts/example-header-plugin-comment.md">
---
post_title: Example WordPress plugin header comment for WooCommerce extensions
sidebar_label: Plugin header comments

---

# Example WordPress plugin header comment for WooCommerce extensions

This is a WordPress plugin header comment. It's used to provide WordPress with metadata about a plugin. 

```php
/**
* Plugin Name: WooCommerce Extension
* Plugin URI: https://woocommerce.com/products/woocommerce-extension/
* Description: Your extension's description text.
* Version: 1.0.0
* Author: Your Name
* Author URI: http://yourdomain.com/
* Developer: Your Name
* Developer URI: http://yourdomain.com/
* Text Domain: woocommerce-extension
* Domain Path: /languages
*
* WC requires at least: 8.0
* WC tested up to: 8.3
*
* License: GNU General Public License v3.0
* License URI: http://www.gnu.org/licenses/gpl-3.0.html
* Woo: 12345:342928dfsfhsf8429842374wdf4234sfd
*/
... (22 lines truncated)
</file>

<file path="docs/extensions/core-concepts/handling-deactivation-and-uninstallation.md">
---
post_title: Managing extension deactivation and uninstallation
sidebar_label: Deactivation and uninstallation

---

# Managing extension deactivation and uninstallation

## Introduction

There are a number of cleanup tasks you'll need to handle when a merchant deactivates or uninstalls your extension. This guide provides a brief overview of WooCommerce-specific items you'll want to make sure you account for when defining your extension's deactivation and uninstallation logic.

## Removing Scheduled Actions

If your extension uses Action Scheduler to queue any background jobs, it's important to unschedule those actions when your extension is uninstalled or deactivated.

`as_unschedule_all_actions( $hook, $args, $group );`

You can read more about using Action Scheduler for managing background processing in the [Action Scheduler API Reference](https://actionscheduler.org/api/).

## Removing Admin Notes

If you have created any Notes for merchants, you should delete those notes when your extension is deactivated or, at the very least, when it is uninstalled.

```php
function my_great_extension_deactivate() {
    ExampleNote::possibly_delete_note();
}
register_deactivation_hook( __FILE__, 'my_great_extension_deactivate' );

... (27 lines truncated)
</file>

<file path="docs/extensions/core-concepts/maintainability.md">
---
post_title: Maintaining and updating WooCommerce extensions
sidebar_label: Maintainability and updates

---

# Maintaining and updating WooCommerce extensions

Maintaining and updating WooCommerce extensions is crucial for ensuring they remain compatible, secure, and functional within the ever-evolving WordPress ecosystem. This document outlines best practices for ensuring easy maintainability, adhering to update frequency and process, and conducting manual update checks.

## Ensuring easy maintainability

Maintainable code is essential for the long-term success of any WooCommerce extension. It ensures that your extension can be easily updated, debugged, and extended, both by you and others in the future.

### Importance of writing maintainable code

- **Future-proofing**: Maintainable code helps in adapting to future WooCommerce and WordPress updates.
- **Collaboration**: Makes it easier for teams to work together on the extension.
- **Cost-effective**: Reduces the time and resources required for adding new features or fixing issues.

### Strategies to achieve maintainability

- **Modular code**: Break down your extension into smaller, focused modules or components.
- **Coding standards**: Follow the [WordPress Coding Standards](https://developer.wordpress.org/coding-standards/) to ensure consistency.
- **Documentation**: Document your code extensively to explain "why" behind the code, not just "how" to use it.
- **Refactoring**: Regularly refactor your code to improve its structure without altering the external behavior.

## Update frequency and process

Keeping your extension up-to-date is vital for security, compatibility, and performance. Regular updates also signal to users that the extension is actively maintained.
... (27 lines truncated)
</file>

<file path="docs/extensions/core-concepts/README.md">
# Core concepts

This section covers the fundamental principles, best practices, and essential knowledge you need to develop robust, maintainable WooCommerce extensions.

Learn about everything from basic setup and architecture to advanced development patterns. Whether you're building your first WooCommerce extension or maintaining existing ones, these guides will help you follow best practices and create high-quality code.

## Getting started

[Check if WooCommerce is active](./check-if-woo-is-active.md) to learn the proper way to ensure WooCommerce is installed and active before your code runs. This prevents errors and ensures your extension works reliably. You'll also want to understand the [core WooCommerce classes](./class-reference.md) and how to work with them, from the main `WooCommerce` class to `WC_Product`, `WC_Customer`, and `WC_Cart`.

## Internal code boundaries

WooCommerce contains both public APIs intended for extension use and internal infrastructure code. **Extensions must not use internal code**, as backwards compatibility between WooCommerce releases is not guaranteed:

- **Internal namespace**: All classes under `Automattic\WooCommerce\Internal` are internal infrastructure.
- **@internal annotations**: Code entities (classes, methods, hooks) marked with `@internal` in their docblocks.

Using internal code may cause your extension to break when merchants update WooCommerce. See the [extension development best practices](../best-practices-extensions/extension-development-best-practices.md) and the [Internal namespace documentation](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Internal/README.md) for details.

## Development patterns

[Adding actions and filters](./adding-actions-and-filters.md) to master the art of extending WooCommerce through hooks. Learn when and how to add actions and filters, following WordPress and WooCommerce standards. For long-term success, discover strategies for [writing maintainable code](./maintainability.md) and establishing update processes that keep your extensions current and secure. You'll also need to [manage deactivation and uninstallation](./handling-deactivation-and-uninstallation.md) to ensure your extension cleans up properly when deactivated or uninstalled, including scheduled actions, admin notes, and tasks.

## Plugin structure and standards

See the [example header plugin comment](./example-header-plugin-comment.md) format for your extension's main plugin file header, including all required metadata. You'll also want to learn the standard [changelog format](./changelog-txt.md) for documenting changes in your extension's changelog file, and understand the [WooCommerce plugin API callback](./woocommerce-plugin-api-callback.md) for proper integration with WooCommerce's plugin API for seamless functionality.
</file>

<file path="docs/extensions/core-concepts/woocommerce-plugin-api-callback.md">
---
post_title: WooCommerce Plugin API callbacks
sidebar_label: Plugin API callbacks

---

# WooCommerce Plugin API callbacks

## Overview

This document provides a guide on how to use the WooCommerce Plugin API to initiate callbacks for plugin actions, especially for gateways and classes not initialized by default.

## Callback URL Structure

Before WooCommerce 2.0, use:

`https://example.com/?wc-api=CALLBACK`

In WooCommerce 2.0 or later, use the endpoint:

`https://example.com/wc-api/CALLBACK/`

## Behavior

When the callback URL is accessed, WooCommerce will:

- Initialize the `CALLBACK` class, if available
- Trigger the `woocommerce_api_callback` action
- Exit WordPress

... (12 lines truncated)
</file>

<file path="docs/extensions/extension-onboarding/_category_.json">
{
    "label": "Onboarding",
    "position": 4,
    "link": {
      "type": "generated-index",
      "title": "Onboarding"
    }
}
</file>

<file path="docs/extensions/extension-onboarding/adding-custom-products-to-add-products-onboarding-list.md">
---
post_title: How to add custom product types to Add Products onboarding list
sidebar_label: Add custom product types to Add Products onboarding list

---

# How to add custom product types to Add Products onboarding list

## Introduction

WooCommerce allows developers to extend the product type onboarding list, offering a more customizable and engaging experience during the Add Products onboarding task. This tutorial will guide you through adding custom product types to your WooCommerce store using the `experimental_woocommerce_tasklist_product_types` JavaScript filter.

## Prerequisites

- A basic understanding of JavaScript and PHP.
- WooCommerce 8.8 or later installed on your WordPress site.

## Step 1: Adding a JavaScript Filter

To add a new product type to the onboarding list, we'll utilize the `@wordpress/hooks` package, specifically the addFilter function. If you're not already familiar, `@wordpress/hooks` allows you to modify or extend features within the WordPress and WooCommerce ecosystem without altering the core code.

First, ensure you have the `@wordpress/hooks` package installed. If not, you can add it to your project using `npm` or `yarn`:

`npm install @wordpress/hooks`

or:

`yarn add @wordpress/hooks`

Next, add the following JavaScript code to your project. This code snippet demonstrates how to add a "custom product" type to the onboarding list:
... (49 lines truncated)
</file>

<file path="docs/extensions/extension-onboarding/creating-custom-product-tours.md">
---
post_title: How to create custom product tours
sidebar_label: How to create custom product tours

---

# How to create custom product tours

## Introduction

WooCommerce allows developers to extend or replace the product tour, offering a more customizable and engaging experience during product creation. This tutorial will guide you through adding a custom product tour to your WooCommerce store using the `experimental_woocommerce_admin_product_tour_steps` JavaScript filter.

This works in conjunction with the ability to customize the product type onboarding list.

## Prerequisites

- A basic understanding of JavaScript and PHP.
- WooCommerce 8.8 or later installed on your WordPress site.

## Adding a JavaScript Filter

To alter or create a product tour, we'll utilize the `@wordpress/hooks` package, specifically the `addFilter` function. If you're not already familiar, `@wordpress/hooks` allows you to modify or extend features within the WordPress and WooCommerce ecosystem without altering the core code.

First, ensure you have the `@wordpress/hooks` package installed. If not, you can add it to your project using `npm` or `yarn`:

`npm install @wordpress/hooks`

or:

`yarn add @wordpress/hooks`
... (50 lines truncated)
</file>

<file path="docs/extensions/extension-onboarding/handling-merchant-onboarding.md">
---
post_title: How to implement merchant onboarding
sidebar_label: Implement merchant onboarding
sidebar_position: 1
---

# How to implement merchant onboarding

## Introduction

Onboarding is a critical part of the merchant's user experience. It helps set them up for success and ensures they're not only using your extension correctly but also getting the most out of it. There are a few especially useful features that you can take advantage of as a developer to help onboard merchants who are using your extension:

- Setup tasks
- Store management links
- Admin notes

---

## Getting started

We'll be using `@woocommerce/create-woo-extension` to scaffold a modern WordPress JavaScript environment for plugins. This tool creates a fully functional development environment for integrating with WooCommerce.

In this example, we'll be using the `add-task` variant to create a basic onboarding extension that we can build upon.

In your `wp-content/plugins` directory, run the following command to create your extension:

```sh
npx @wordpress/create-block -t @woocommerce/create-woo-extension --variant=add-task my-extension-name
```

... (641 lines truncated)
</file>

<file path="docs/extensions/extension-onboarding/integrating-coming-soon-mode.md">
---
post_title: Integrating with coming soon mode

---

# Integrating with coming soon mode

This guide provides examples for third-party developers and hosting providers on how to integrate their systems with WooCommerce's coming soon mode. For more details, please read the [developer blog post](https://developer.woocommerce.com/2024/06/18/introducing-coming-soon-mode/). For site visibility settings, please refer to the [admin documentation](https://woocommerce.com/document/configuring-woocommerce-settings/coming-soon-mode/).

## Introduction

WooCommerce's coming soon mode allows you to temporarily make your site invisible to the public while you work on it. This guide will show you how to integrate this feature with your system, clear server cache when site visibility settings change, and sync coming soon mode with other plugins.

## Prerequisites

-   Familiarity with PHP and WordPress development.

## Step-by-step instructions

### Clear server cache on site visibility settings change

When the site's visibility settings change, it may be necessary to clear a server cache to apply the changes and re-cache customer-facing pages. The [`update_option`](https://developer.wordpress.org/reference/hooks/update_option/) hook can be used to achieve this.

```php
add_action( 'update_option_woocommerce_coming_soon', 'clear_server_cache', 10, 3 );
add_action( 'update_option_woocommerce_store_pages_only', 'clear_server_cache', 10, 3 );

function clear_server_cache( $old_value, $new_value, $option ) {
    // Implement your logic to clear the server cache.
    if ( function_exists( 'your_cache_clear_function' ) ) {
... (197 lines truncated)
</file>

<file path="docs/extensions/getting-started-extensions/_category_.json">
{
    "position": 1,
    "collapsed": false,
    "label": "Getting started",
    "link": {
      "type": "doc",
      "id": "README"
    }
}
</file>

<file path="docs/extensions/getting-started-extensions/building-your-first-extension.md">
---
post_title: How to build your first extension
sidebar_label: Build your first extension
sidebar_position: 2
---

# How to build your first extension

This guide will teach you how to use [create-woo-extension](https://www.npmjs.com/package/@woocommerce/create-woo-extension) to scaffold a WooCommerce extension. There are various benefits to using create-woo-extension over manually creating one from scratch, including:

There is less boilerplate code to write, and fewer dependencies to manually setup.

Modern features such as Blocks are automatically supported, and unit testing, linting, and Prettier IDE configuration are ready to use.

Once your extension is set up, we will show you how to instantly spin up a development environment using [wp-env](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/).

## Requirements

Before getting started, you will need the following tools installed on your device:

- [Node.js](https://nodejs.org/en/learn/getting-started/how-to-install-nodejs) with NPM
- [Docker](https://docs.docker.com/engine/install/) (must be running to use wp-env)
- [Composer](https://getcomposer.org/doc/00-intro.md)

This guide also presumes that you are familiar with working with the command line.

## Bootstrapping Your Extension

Open your terminal and run

... (55 lines truncated)
</file>

<file path="docs/extensions/getting-started-extensions/how-to-design-a-simple-extension.md">
---
post_title: How to design a simple extension
sidebar_label: Design a simple extension
sidebar_position: 1
---

# How to design a simple extension

## Introduction

Building a WooCommerce extension that provides a first-class experience for merchants and shoppers requires a hybrid development approach combining PHP and modern JavaScript. The PHP handles the lifecycle and server-side operations of your extension, while the modern JavaScript lets you shape the appearance and behavior of its user interface.

## The main plugin file

Your extension's main PHP file is a bootstrapping file. It contains important metadata about your extension that WordPress and WooCommerce use for a number of ecosystem integration processes, and it serves as the primary entry point for your extension's functionality. While there is not a particular rule enforced around naming this file, using a hyphenated version of the plugin name is a common best practice. (i.e. my-extension.php)

## Declaring extension metadata

Your extension's main plugin file should have a header comment that includes a number of important pieces of metadata about your extension. WordPress has a list of [header requirements](https://developer.wordpress.org/plugins/plugin-basics/header-requirements/) to which all plugins must adhere, but there are additional considerations for WooCommerce extensions:

- The `Author` and `Developer` fields are required and should be set to  
  either your name or your company name.

- The `Developer URI` field should be your official webpage URL.

- The `Plugin URI` field should contain the URL of the extension's product page in the WooCommerce Marketplace or the extension's official landing page on your website.

- The `Requires Plugins` field should list the slugs of any required plugins, separated by commas. WooCommerce extensions should require WooCommerce to activate. 

- The `Woo` field is used for extensions listed in the WooCommerce Marketplace. This code is automatically added upon deployment for products sold on WooCommerce.com to facilitate updates. Please don't add it manually, and refrain from adding it to products offered outside of the WooCommerce Marketplace. Including this header in other versions will prevent updates from working.
... (376 lines truncated)
</file>

<file path="docs/extensions/getting-started-extensions/README.md">
# Get started building extensions

This section provides guides and resources for building, testing, and distributing WooCommerce extensions.

## Important: Internal vs public code

Not all WooCommerce code is intended for use by extensions. Classes in the `Automattic\WooCommerce\Internal` namespace and code marked with `@internal` are for WooCommerce core use only: backwards compatibility between WooCommerce releases is not guaranteed and your extension may break if you use them. See the [extension development best practices](../best-practices-extensions/extension-development-best-practices.md) and the [Internal namespace documentation](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Internal/README.md).

## Getting started

- [Design a simple extension](/extensions/getting-started-extensions/how-to-design-a-simple-extension) - Learn extension architecture and best practices
- [Build your first extension](/extensions/getting-started-extensions/building-your-first-extension) - Create your first WooCommerce extension
- [Core concepts](/extensions/core-concepts/) - Master fundamental concepts like plugin headers, lifecycle management, and security

## Submit to the WooCommerce Marketplace

Join the WooCommerce Marketplace and get your extension in front of 3.6M+ active stores worldwide.

Learn more about [why extension developers are choosing the WooCommerce Marketplace](https://woocommerce.com/partners/) and [submit your extension](https://woocommerce.com/document/submitting-your-product-to-the-woo-marketplace/)


### Quality Insights Toolkit (QIT)

#### Available to all developers with a WooCommerce.com vendor profile

QIT (Quality Insights Toolkit) is a testing platform developed by WooCommerce for plugins and themes. It allows developers to quickly run a variety of managed tests out-of-the-box, as well as integrate their own custom E2E tests to ensure their extensions are reliable, secure, and compatible.

#### Key features

- **Managed test suites:** Run pre-configured end-to-end tests, activation tests, security scans, PHPStan analysis, API tests, and more
... (11 lines truncated)
</file>

<file path="docs/extensions/review-guidelines/how-to-request-reviews.md">
---
post_title: How to request WooCommerce extension reviews
sidebar_label: Requesting reviews
---

# How to request WooCommerce extension reviews

## Methods of requesting reviews

### Admin notices

Admin notices are an industry standard method of requesting reviews, but bombarding the admin dashboard with admin notices is not effective. We recommend using restraint in the design of a notice, as well as limiting to a single notice at a time. It's very easy to overwhelm merchants with too many notices, or too intrusive notices.

#### Recommendations

* A good place for an admin notice to review an extension would be to show on the `Plugins` page and extension's settings pages.
* Include a snooze option (or multiple) on your notices with a clear expectation of when the notice will reappear.
* Admin notices should always be always be completely dismissable. They cannot only have a snooze option.
* The options presented in the notice must be phrased carefully to avoid manipulative language.
* Use consistently designed notices so the request for reviews feels like a part of your extension, and looks consistent with WooCommerce's design.

### Direct contact

#### Recommendations

* The most direct route to requesting reviews with the highest chance of being positive is to contact the customer when they are the happiest with the product.
* This can be milestone or time based, following the timing guidelines below.
* The best method for this is either an email or other direct exchange (support chat, call, etc.). This has the highest conversion rate, especially when timed properly so that the customer is happiest.
* This is also extremely effective when you are able to request feedback from specifically qualified merchants, such as merchants that have processed a certain amount with your platform, or who have shipped their first 100 orders using your fulfillment extension, or similar.
* Direct outreach is most likely to be successful if you have ways of targeting users for review requests (merchant account / usage info, etc.), as well as ways to gather the reviews, like sales or marketing teams able to email/call/chat with merchants.
... (12 lines truncated)
</file>

<file path="docs/extensions/review-guidelines/misc-guidelines.md">
---
post_title: Miscellaneous guidelines and advice
sidebar_label: Miscellaneous guidelines
---

# Miscellaneous guidelines and advice

Contributors' names matching search terms directly will rank extremely highly on the WordPress.org plugin repo, which means that having a WordPress.org user named after your business (if that's a search term for your plugin) could tilt the scales over a competing plugin.

Constant nags and overwhelming the admin dashboard with unnecessary alerts detract from your user experience.

You can request to have reviews that are not actually feedback removed. Where this might be applicable is if the request is a simple support request, where it's obviously in the wrong spot. 1 star reviews, even if aggressive or angry, are not usually removed.

Reply to reviews! Thank the giver for offering feedback, acknowledge the issue if needed, ask for more specific feedback, or provide an update when that feedback is addressed! Your reviews are a great window into what your extension's users are actually thinking.

Having folks close to the extension's development (think developers and project managers) looking at reviews on a regular basis is a good way to ensure the customers voice is heard. 1 star reviews are among the most useful, as long as the issue is understood and addressed (if needed).
</file>

<file path="docs/extensions/review-guidelines/notifying-users-about-important-events.md">
---
post_title: Notifying users about bug fixes and feature requests
sidebar_label: Notifying users about bug fixes and feature requests
---

# Notifying users about bug fixes and feature requests

A bug or a missing feature can be a showstopper for merchants. Bugs that pile up or popular features that are not implemented can lead to negative reviews and/or merchants churning and looking at a competitive solution.

Bugs are usually reported via support or GitHub, or you can discover them yourselves in testing.

When a critical bug is found, resolve it within a couple of days (most critical bugs should be resolved within 24 hours) and release a new plugin version promptly. Part of your release process should be to notify all stakeholders (the support team and the merchant affected) about the upcoming release.

Even though a critical bug is a great source of stress for merchants, a quick resolution makes merchants feel heard and supported - having a reliable business partner, who is keen to help in the most difficult situation, helps build a stronger relationship. Therefore, we usually ask merchants for a 5* review when we deliver a fast solution.

When you implement a new feature request and ship a new plugin version, you can follow a similar approach to bugs:

* Notify all stakeholders.
* Update the relevant request in the Feature Requests board, by sharing a public update and marking it as 'Completed'.
* For breaking releases: communicating with your marketing/relations teams to publish updates/newsletters before the release.
</file>

<file path="docs/extensions/review-guidelines/README.md">
---
sidebar_position: 7
sidebar_label: Review guidelines  
category_slug: review-guidelines
post_title: Review guidelines
---

# Review guidelines

Reviews are an integral part of the online shopping experience, and people installing software pay attention to them. Prospective users of your extensions will likely consider average ratings when making software choices.

Many of today's most popular online review platforms - from Yelp business reviews, to Amazon product reviews - have a range of opinion that can be polarized, with many extremely positive and/or negative reviews, and fewer moderate opinions. This creates a "J-shaped" distribution of reviews that isn't as accurate or as helpful as could be.

WooCommerce.com and WordPress.org both feature reviews heavily, and competing extensions having a higher rating likely have the edge in user choice. 

## Primary considerations around reviews

Requesting more reviews for a extension with major issues will not generate good reviews, and analyzing existing reviews will help surface areas to address before soliciting reviews.

It is extremely rare for users of WordPress plugins to leave reviews organically (.2% of users for WordPress.org leave reviews), which means that there's an untapped market of 99.8% of users of the average plugin.

These plugins are competing with other plugins on the same search terms in the WordPress.org plugin directory, and ratings are a large factor in the ranking algorithm. This is not usually a factor to the same extent on the WooCommerce Marketplace. For instance, WooCommerce's PayPal extension directly competes on all possible keywords with other PayPal extensions on the WordPress.org repository, while it does not compete with other PayPal payments extensions on the Marketplace.
</file>

<file path="docs/extensions/review-guidelines/responding-to-negative-reviews.md">
---
post_title: How to respond to negative WooCommerce extension reviews
sidebar_label: Responding to negative reviews
---

# How to respond to negative WooCommerce extension reviews

An unpleasant event in the merchant's journey can lead them to leave a public, negative review. These events usually are:

* a problem with the product,
* a missing product feature,
* an unhelpful reply,
* long wait times to receive a reply, or;
* combinations of the above.

When receiving a negative review, your goal should always be to turn this review around - this sounds tough, but it is really rewarding.

In the majority of cases, merchants who leave a negative review have first tried contacting support for help. This is useful knowledge, as we can read through the conversation history, understand the issue the merchant experienced and share more details with them when we reach out, even from our first reply.

The process we have seen work well is:

* Create a new response (via email, or on a public review) with subject: Regarding your recent review for xxx.
* Start by introducing yourself, for example: "Hey there, This is Andrew from the team that develops xxx".
* Use empathetic language and make it clear that this negative review had an impact on you. For example, "I read your recent review for xxx and I am worried to hear that an issue is preventing you from using this plugin as you had in mind. I'd be happy to help you resolve this!".

Compare the above sentence with: "I am sorry to hear that you experienced an issue with xxx". "I am sorry to" indicates that you are saddened by an event, but don't necessarily plan to do something about it. In comparison, in "I am worried to hear", worry indicates action. Additionally, "That you experienced an issue" can be interpreted as if the problem is mainly the merchant's fault, whereas language like "an issue is preventing you from using this plugin as you had in mind. I'd be happy to help you resolve this!" implies you and the merchant are on the same team.

* Share more details, a solution, an idea, a suggestion or an explanation.
* Urge the merchant to update the review, by highlighting how important reviews are for our team and for other merchants. Example language to do this is "We would appreciate it if you could take a couple of minutes to update your review and describe your experience with our product and support. Honest reviews are extremely helpful for other merchants who try to decide if a plugin is a right fit for them. Thank you for your contribution!".
* Include a direct link to the reviews section, so merchants can easily navigate there and change their review.
... (6 lines truncated)
</file>

<file path="docs/extensions/review-guidelines/utilizing-feature-requests.md">
---
post_title: Utilizing WooCommerce extension feature requests
sidebar_label: Utilizing feature requests
---

# Utilizing WooCommerce extension feature requests

It is important to keep track of all feature requests, and have some sort of system of record where anyone can see what kind of feedback the product is receiving over time. 

We recommend a daily or bi-daily check-in, where you:

* triage new feature requests,
* celebrate positive reviews and;
* act upon negative reviews.

Carefully maintaining feature request boards (or similar system) is key, as the average board contains a lot of duplicate/spam content, requests about features that have been implemented and requests about features that will likely never be implemented. Poorly maintained boards make merchants feel unheard/neglected.

This results in more negative reviews on the premise that the product teams were not reading/listening to their feedback.

We've seen good results with the following procedures:

Starting with the most affected products, go through all open requests, reply to most/all of them and categorize them as:

* "Open", for requests that we still want more feedback,
* "Planned", for requests that we plan to implement,
* "Completed", for requests that have already been implemented and;
* "Closed", for requests that we do not plan to implement, as they are not a good fit for the product, for duplicate/spam requests and for requests that were actually support questions.

Replying to all "Open" requests is the goal, but if that's not attainable currently, make sure to reply to 100% of the requests that are closed.

... (4 lines truncated)
</file>

<file path="docs/extensions/review-guidelines/utilizing-your-support-team.md">
---
post_title: Utilizing your support team to respond to feedback
sidebar_label: Utilizing your support team
---

# Utilizing your support team to respond to feedback

Your support team is usually the primary contact point of merchants when they contact you. Tickets and chats are the best tools we have to converse with merchants, understand pain-points about our software, listen to their feedback and analyze their feature requests. Collectively, support teams have a great understanding of the products and how people use them. This information is essential to be transferred over to product and engineering teams.

We recommend that you take the following steps to best utilize your support team:

* Create a strict internal SLA where support team requests are answered by product or engineering teams.
* Ensure you have a way for your support team to effectively report bugs to your product and engineering teams.
* When responding to your support team, avoid super-short answers, and try to explain the answer simply and concisely. This will allow the support agent to copy/paste your answer to the merchant.
* Avoid replying with statements like "no, this is not possible" or "no, this feature will not be implemented" without providing additional context about technical or product limitations.
* Regularly dedicate additional time to implement a short custom code snippets or to provide in-depth technical details about how a custom project would be implemented so that merchants can reach a solution faster if they decide to hire a dedicated WooCommerce developer. A small effort can go a long way to amaze merchants and reveal an opportunity to request a 5 star review.
* Keep support in the loop when they report a bug or request a new feature. When you release a new product version, we always consider the impact it can have on support.  
* Work closely with your support team. For example, consider having a feedback hangout call every month where you can discuss product feedback and planned improvements.

With these kinds of practices in place, support teams are more willing to share feedback, issues, concerns, and questions with us. This helps maintain a closer relationship with merchants and identify pain-points early, before they become a reason for them to churn.
</file>

<file path="docs/extensions/review-guidelines/when-to-request-reviews.md">
---
post_title: When to request WooCommerce extension reviews
sidebar_label: When to request reviews
---

# When to request WooCommerce extension reviews

The best approach to increasing our top-star reviews is to identify key moments in the merchant's journey, when they are more likely to leave a review and actively request for it.

The most distinct moments for most of our use cases are: 

* When merchants feel helpless, lost, frustrated and we are able to help,
* When merchants find a bug in our code and we quickly ship a fix,
* When merchants need a feature and we notify them when it is shipped,
* When merchants feel alone and we make them feel heard and;
* When merchants contact with a question and we go out of our way to provide them with top-notch support, even if this means slightly stepping outside the official boundaries of a support policy.

Think about who is seeing the review request, and what they are doing at that time. Showing a request to a fulfillment worker just trying to ship an order isn't likely going to work well.

Outreach after a milestone works really well. Some language we've used before is "Congratulations on your xxth sale! We're delighted that WooPayments facilitated this milestone. Would you consider sharing your experience and encouraging others by reviewing our extension?".

Another way to optimally time a review request would be to setup a prompt that aligns with use patterns. For instance, if you know that most of your merchants use your extension daily, you would likely send a review request sooner than a extension that most merchants interact very sparingly with.

SaaS/Connector extensions need to be particularly careful about requesting ratings correctly, as they are the most likely to be overlooked unless there is an issue, leading to skewed ratings not representative of the actual extension.

Consider requesting feedback at the end of every single support interaction, especially in the WordPress.org support forums. One of the largest barriers to leaving a review is the requirement of a user being logged into WooCommerce.com (or WordPress.org), and the WordPress.org support forums present a good opportunity to gather these reviews. By being highly responsive in the public support forum and solving issues there, users are already logged in and able to immediately leave a review (after being requested to!).
</file>

<file path="docs/extensions/settings-and-config/_category_.json">
{
    "label": "Settings and config",
    "position": 3,
    "link": {
        "type": "doc",
        "id": "README"
    }
}
</file>

<file path="docs/extensions/settings-and-config/adding-a-section-to-a-settings-tab.md">
---
post_title: How to add a section to a settings tab
sidebar_label: Settings tab sections
sidebar_position: 3

---

# How to add a section to a settings tab

When you're building an extension for WooCommerce that requires settings of some kind, it's important to ask yourself:  **Where do they belong?**  If your extension just has a couple of simple settings, do you really need to create a new tab specifically for it? Most likely the answer is no.

## When to Create a Section

Let's say we had an extension that adds a slider to a single product page. This extension only has a few options:

-   Auto-insert into single product page (checkbox)
-   Slider Title (text field)

That's only two options, specifically related to  **Products**. We could quite easily just append them onto the core WooCommerce Products Settings (**WooCommerce > Settings > Products**), but that wouldn't be very user friendly. Users wouldn't know where to look initially so they'd have to scan all of the Products options and it would be difficult / impossible to link the options directly. Fortunately, as of WooCommerce 2.2.2, there is a new filter in place that allows you add a new  **section**, beneath one of the core settings' tabs.

## How to Create a Section

We'll go over doing this through individual functions, but you should probably create a Class that stores all of your settings methods.

The first thing you need to is add the section, which can be done like this by hooking into the  `woocommerce_get_sections_products`  filter:

```php
/**

* Create the section beneath the products tab
... (113 lines truncated)
</file>

<file path="docs/extensions/settings-and-config/extend-wc-settings-page.md">
---
post_title: How to add a settings page
sidebar_label: Settings pages
sidebar_position: 2
---

# How to add a settings page

Use `WC_Settings_Page` when your extension needs a full tab under **WooCommerce > Settings**. A settings page class registers the tab, renders one or more sections, defines fields with WooCommerce's settings array format, and lets WooCommerce handle saving through the existing settings form.

If your extension only needs a few settings that clearly belong under an existing WooCommerce settings tab, add a section to that tab instead of creating a new top-level tab. See [How to add a section to a settings tab](./adding-a-section-to-a-settings-tab.md). If your settings belong to a payment gateway, shipping method, or integration, also check whether `WC_Payment_Gateway`, `WC_Shipping_Method`, `WC_Integration`, or `WC_Settings_API` is the better fit.

## How settings pages are loaded

WooCommerce loads settings page objects from `WC_Admin_Settings::get_settings_pages()`. Core pages are loaded first, then extensions can add their own page objects through the `woocommerce_get_settings_pages` filter.

A `WC_Settings_Page` subclass must set its `$id` and `$label` before calling `parent::__construct()`. The parent constructor uses the page ID to register these hooks:

- `woocommerce_settings_tabs_array` adds the settings tab.
- `woocommerce_sections_{$page_id}` outputs section navigation.
- `woocommerce_settings_{$page_id}` outputs the fields.
- `woocommerce_settings_save_{$page_id}` saves the fields.

## Create a settings page class

Load your class only after `WC_Settings_Page` is available. WooCommerce includes the base class before it applies `woocommerce_get_settings_pages`, so a common pattern is to require your settings page class from that filter callback.

The example below defines a full **My plugin** tab with two sections. Place the class in a file such as `includes/class-my-plugin-settings-page.php`, and load that file from the registration callback shown after the class.

```php
... (339 lines truncated)
</file>

<file path="docs/extensions/settings-and-config/how-to-add-your-own-store-management-links.md">
---
post_title: How to add store management links
sidebar_label: Store management links
sidebar_position: 6

---

# How to add store management links

## Introduction

In the new and improved WooCommerce home screen, there are two points of extensibility for plugin developers that have recently had some attention. The first is the setup task list, allowing you to remind the user of tasks they need to complete and keeping track of their progress for them.

The second is the store management links section. Once the user has completed the setup tasks this will display for them. This section consolidates a list of handy navigation links that merchants can use to quickly find features in WooCommerce.

Discoverability can be hard for users so this can be a great place to bring attention to the features of your plugin and allow users to easily find their way to the key functionality your plugin provides.

Adding your own store management links is a simple process.

## Add your own store management link

Before we start, let's outline a couple of restrictions on this feature.

Right now these links are designed to keep the user within WooCommerce, so it does not support external links.

All the links you add will fall under a special category in the list called "Extensions". There is not currently any support for custom categories.

With those things in mind, let's start.

## Step 1 - Enqueue JavaScript
... (51 lines truncated)
</file>

<file path="docs/extensions/settings-and-config/implementing-settings.md">
---
post_title: Creating custom settings for WooCommerce integrations
sidebar_label: Integration settings
sidebar_position: 5

---

# Creating custom settings for WooCommerce integrations

If you're customizing WooCommerce or adding your own functionality to it you'll probably need a settings page of some sort. One of the easiest ways to create a settings page is by taking advantage of the [`WC_Integration` class](https://woocommerce.github.io/code-reference/classes/WC-Integration.html 'WC_Integration Class'). Using the Integration class will automatically create a new settings page under **WooCommerce > Settings > Integrations** and it will automatically save, and sanitize your data for you. We've created this tutorial so you can see how to create a new integration.

## Setting up the Integration

You'll need at least two files to create an integration so you'll need to create a directory.

### Creating the Main Plugin File

Create your main plugin file to [hook](https://developer.wordpress.org/reference/functions/add_action/ 'WordPress add_action()') into the `plugins_loaded` hook and check if the `WC_Integration` [class exists](https://www.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends 'PHP Class Exists'). If it doesn't then the user most likely doesn't have WooCommerce activated. After you do that you need to register the integration. Load the integration file (we'll get to this file in a minute). Use the `woocommerce_integrations` filter to add a new integration to the [array](http://php.net/manual/en/language.types.array.php 'PHP Array').

### Creating the Integration Class

Now that we have the framework setup let's actually implement this Integration class. There already is a `WC_Integration` class so we want to make a [child class](https://www.php.net/manual/en/language.oop5.inheritance.php). This way it inherits all of the existing methods and data. You'll need to set an id, a description, and a title for your integration. These will show up on the integration page. You'll also need to load the settings by calling: `$this->init_form_fields();` & `$this->init_settings();` You'll also need to save your options by calling the `woocommerce_update_options_integration_{your method id}` hook. Lastly you have to input some settings to save! We've included two dummy fields below but we'll go more into fields in the next section.

> Added to a file named `class-wc-integration-demo-integration.php`

```php
<?php
/**
 * Integration Demo Integration.
 *
... (272 lines truncated)
</file>

<file path="docs/extensions/settings-and-config/README.md">
---
post_title: 'Settings APIs and admin pages'
sidebar_label: Overview
sidebar_position: 0
---

# Settings APIs and admin pages

Managing your settings, admin pages, and more is possible through the Settings APIs. The docs in this section cover what the Settings APIs and admin pages system offers in general. This guide goes further to map all of the various approaches you have available, some of the scenarios they cover, and the trade-offs of each approach.

There are also code examples for your reference before you commit to an implementation path. However, reading through the approach you're interested in will give you greater scope to understand and apply the principles of each.

## Approaches at a glance

The Settings API and admin pages section has six approaches, outlined in the table. The four core concepts (Settings API, settings pages, settings tab sections, and admin pages) cover most settings and admin placement decisions, while the remaining approaches cover specialized integrations and navigation shortcuts.

| Approach | Use when | Requires |
| :---- | :---- | :---- |
| [Settings API](/docs/extensions/settings-and-config/settings-api/) | Defining settings for a configurable component, such as a payment gateway or shipping method | PHP |
| [Settings pages](/docs/extensions/settings-and-config/extend-wc-settings-page/) | Your extension needs a full tab under **WooCommerce > Settings** with one or more sections | PHP |
| [Settings tab sections](/docs/extensions/settings-and-config/adding-a-section-to-a-settings-tab/) | Your settings belong under an existing WooCommerce tab rather than a new page | PHP |
| [Admin pages](/docs/extensions/settings-and-config/working-with-woocommerce-admin-pages/) | Your extension needs a standalone page outside WooCommerce's settings structure | PHP or JavaScript |
| [Integration settings](/docs/extensions/settings-and-config/implementing-settings/) | Your extension connects to a third-party service and needs a page under the Integrations tab | PHP |
| [Store management links](/docs/extensions/settings-and-config/how-to-add-your-own-store-management-links/) | Surfacing quick-access links on the WooCommerce home screen | JavaScript |

## Settings API

`WC_Settings_API` provides field definition, rendering, loading, and saving for configurable WooCommerce components. Plugin developers usually inherit it through `WC_Payment_Gateway`, `WC_Shipping_Method`, or `WC_Integration` rather than extending it directly.

Use the [Payment Gateway API](/docs/features/payments/payment-gateway-api/), [Shipping Method API](/docs/features/shipping/shipping-method-api/), or [integration settings](/docs/extensions/settings-and-config/implementing-settings/) guide for a complete implementation.
... (214 lines truncated)
</file>

<file path="docs/extensions/settings-and-config/registering-settings-ui-components.md">
---
post_title: Registering settings UI components
sidebar_label: Register settings UI components
sidebar_position: 8
---

# Registering settings UI components

> **The settings UI is experimental** and subject to change. See the [settings UI status](./settings-ui.md#status) for details.

Use custom components when a WooCommerce settings field needs plugin-specific React UI that cannot be represented by a built-in DataForm field type.

For most fields, prefer DataForm's built-in controls. Custom components are best for specialized selectors, previews, or validation flows.

## PHP field metadata

Declare a stable component name on the field:

```php
array(
	'id'        => 'my_plugin_payment_methods',
	'title'     => __( 'Payment methods', 'my-plugin' ),
	'type'      => 'multiselect',
	'component' => 'my-plugin/payment-method-picker',
	'options'   => array(
		'card' => __( 'Card', 'my-plugin' ),
		'bnpl' => __( 'Buy now, pay later', 'my-plugin' ),
	),
)
```
... (190 lines truncated)
</file>

<file path="docs/extensions/settings-and-config/settings-api.md">
---
post_title: Settings API
sidebar_label: Settings API
sidebar_position: 1
---

# Settings API

The WooCommerce Settings API is used by extensions to display, save, and load settings. The best way to make use of the API in your extension is to create a class that extends the `WC_Settings_API` class:

```php
class My_Extension_Settings extends WC_Settings_API {
	//
}
```

## Defining form fields

You can define your fields using a method called `init_form_fields` in your class constructor:

```php
$this->init_form_fields();
```

You must have your settings defined before you can load them. Setting definitions go in the `form_fields` array:

```php
/**
 * Initialise gateway settings form fields.
 */
... (91 lines truncated)
</file>

<file path="docs/extensions/settings-and-config/settings-ui.md">
---
post_title: Settings UI
sidebar_label: Settings UI
sidebar_position: 7
---

# Settings UI

The settings UI is an experimental, opt-in path for rendering WooCommerce settings pages with React while keeping the existing `WC_Settings_Page` registration and save flow.

It is designed for extension authors who want to migrate incrementally. PHP still owns page registration, settings schema, permissions, script dependencies, and persistence. React owns field rendering and client-side interaction.

## Status

> **The settings UI is experimental.** Until it is marked as stable, the PHP API under `Automattic\WooCommerce\Admin\Settings`, the schema format, and the `@woocommerce/settings-ui` package can change in backwards-incompatible ways in any release. Expect to update integrations between WooCommerce versions.

-   The settings UI is behind the `settings-ui` feature flag.
-   With the flag disabled, settings pages keep the legacy PHP renderer.
-   With the flag enabled, a settings page still has to opt in explicitly.
-   Saves use the existing WooCommerce settings form POST flow by default.
-   The public PHP API is available under `Automattic\WooCommerce\Admin\Settings`.

## Build a settings UI integration

A complete integration has the same pieces whether it is a full settings tab or a section inside an existing tab:

1. Choose the location: a new `WC_Settings_Page` tab, or a registered section under an existing tab.
2. Define fields in PHP using the WooCommerce settings array. This remains the source of truth for labels, descriptions, defaults, option ids, and fallback rendering.
3. Add Settings UI metadata to fields that need custom React rendering, such as a stable `component` name.
4. Return any script handles that register those custom components before the settings UI mounts.
... (332 lines truncated)
</file>

<file path="docs/extensions/settings-and-config/working-with-woocommerce-admin-pages.md">
---
post_title: Integrating admin pages into WooCommerce extensions
sidebar_label: Admin pages
sidebar_position: 4

---

# Integrating admin pages into WooCommerce extensions

## Introduction

There are a number of ways to manage admin-area pages for your WooCommerce extension. You can use existing PHP pages or create new React-powered pages. Regardless of the approach you choose, you'll need to register your page with the [`PageController`](https://woocommerce.github.io/code-reference/classes/Automattic-WooCommerce-Admin-PageController.html) in order to display the WooCommerce Admin header and activity panel on your page.

## Connecting a PHP-powered page to WooCommerce Admin

To register an existing PHP-powered admin page with the [`PageController`](https://woocommerce.github.io/code-reference/classes/Automattic-WooCommerce-Admin-PageController.html), use the [`wc_admin_connect_page()`](https://woocommerce.github.io/code-reference/namespaces/default.html#function_wc_admin_connect_page) function. For example:

```php
wc_admin_connect_page(
    array(
        'id'        => 'woocommerce-settings',
        'screen_id' => 'woocommerce_page_wc-settings-general',
        'title'     => array( 'Settings', 'General' ),
        'path'      => add_query_arg( 'page', 'wc-settings', 'admin.php' ),
    )
);
```

The [`wc_admin_connect_page()`](https://woocommerce.github.io/code-reference/namespaces/default.html#function_wc_admin_connect_page) function accepts an array of arguments, two of which are optional:

... (87 lines truncated)
</file>

<file path="docs/extensions/ux-guidelines-extensions/_category_.json">
{
    "position": 5,
    "label": "UX guidelines",
    "link": {
      "type": "doc",
      "id": "README"
    }
}
</file>

<file path="docs/extensions/ux-guidelines-extensions/accessibility.md">
---
post_title: Accessibility
sidebar_label: Accessibility
---

# Accessibility

Your extensions must meet the [WordPress Accessibility Coding Standards](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/accessibility/) 

For more information on accessibility, check out the [WordPress accessibility quick start guide](https://make.wordpress.org/accessibility/handbook/best-practices/quick-start-guide/).
</file>

<file path="docs/extensions/ux-guidelines-extensions/best-practices.md">
---
post_title: User experience best practices
sidebar_position: 1
---

# Best Practices

- **Plugin name should simply state the feature of the plugin and not use an existing core feature or extension in its' title**. The plugin name should appear at all times in the UI as a functional and original name. e.g "Appointments" instead of "VendorXYZ Bookings Plugin for WooCommerce."

- **Avoid creating new UI**. Before considering a new UI, review the WordPress interface to see if a component can be repurposed. Follow existing UI navigation patterns so merchants have context on where they are when navigating to a new experience.

- **Be considerate of mobile for the merchant (and shopper-facing if applicable) experience**. Stores operate 24/7. Merchants shouldn't be limited to checking their store on a desktop. Extensions need to be built responsively so they work on all device sizes.

- **It's all about the merchant**. Don't distract with unrelated content. Keep the product experience front and center to help the user achieve the tasks they purchased your product for.

- **Present a review request at the right time**. Presenting users with a request for review is a great way to get feedback on your extension. Think about best placement and timing to show these prompts.
    - Avoid showing the user a review request upon first launching the extension. Once the user has had a chance to set up, connect, and use the plugin they'll have a better idea of how to rate it.
    - Try to present the review request at a time that's least disruptive, such as after successful completion of a task or event.

- **Don't alter the core interface**. Don't express your brand by changing the shape of containers in the Woo admin.

- **Focus on the experience**. After the customer installs your product, the experience should be the primary focus. Keep things simple and guide the user to successful setup. Do not convolute the experience or distract the user with branding, self promotion, large banners, or anything obtrusive.

- **Keep copy short and simple**. Limit instructions within the interface to 120-140 characters. Anything longer should be placed in the product documentation.

- **Maintain a consistent tone when communicating with a user**. Maintain the same communication style and terminology across an extension, and avoid abbreviations and acronyms.

    - In extensions:
        - Use sentences for descriptions, feedback, and headlines. Avoid all-caps text.
        - Use standard punctuation and avoid excessive exclamation marks.
... (3 lines truncated)
</file>

<file path="docs/extensions/ux-guidelines-extensions/colors.md">
---
post_title: Colors
sidebar_label: Colors
---

# Colors

When creating extensions for the WordPress wp-admin, use the core colors, respect the user's WordPress admin color scheme selection, and ensure your designs pass AA level guidelines.

When using components with text, such as buttons, cards, or navigation, the background-to-text contrast ratio should be at least 4.5:1 to be [WCAG AA compliant](https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html). Be sure to [test your color contrast ratios](https://webaim.org/resources/contrastchecker/) to abide by WCAG standards.

- [Accessibility handbook on uses of color and contrast](https://make.wordpress.org/accessibility/handbook/current-projects/use-of-color/)
- [Color contrast ratio checker](http://webaim.org/resources/contrastchecker/)
- [More resources regarding accessibility and color testing](http://webaim.org/resources/contrastchecker/)

For WooCommerce-specific color use, review our [Style Guide](https://woocommerce.com/brand-and-logo-guidelines/).
</file>

<file path="docs/extensions/ux-guidelines-extensions/navigation.md">
---
post_title: Navigation
sidebar_label: Navigation
---

# Navigation

Place your product navigation elements within the existing WooCommerce menu structure.

## Extension with its own menu item

The two options to extend the WooCommerce menu structure are within the category menu or within the relevant settings areas.

![Category Subnavigation Image](/img/doc_images/Category-Subnavigation.png)

## Category sub-navigation

If your plugin is extending an area of WooCommerce, it should live directly within that category’s section.

For example, TikTok lives in Marketing and Product Add-Ons lives in Products.

![Category Setting Image](/img/doc_images/Category-Settings.png)

## Settings

If your plugin adds a settings screen to set up the plugin, settings should be under an appropriate tab on the WooCommerce > Settings screen.

For example, shipping and payments extensions will appear in their relevant Settings area. Only if necessary, create a top-level settings tab if your extension has settings that don’t fit under existing tabs and creating a sub-tab isn’t appropriate.

### Don’t: Add top-level navigation
... (35 lines truncated)
</file>

<file path="docs/extensions/ux-guidelines-extensions/notices.md">
---
post_title: Notices
sidebar_label: Notices
---

# Notices

Use notices primarily to provide user feedback in response to an action. Avoid using notices to communicate offers or announcements. Don't apply brand colors, fonts, or illustrations to your notices.

If a post-activation notice is required, keep it within the WordPress plugin area-do not display it on the dashboard, or any other parts of the platform.

Use the standard WordPress notice format and WooCommerce admin notices API.

## Language

Providing timely feedback like success and error messages is essential for ensuring that the user understands whether changes have been made.

Use short but meaningful messages that communicate what is happening. Ensure that the message provides instructions on what the user needs to do to continue. Proper punctuation should be used if the message contains multiple sentences. Avoid abbreviations.

## Design

The placement of feedback is vital so the user notices it. For example, when validation messages are needed to prompt the user to enter data, get the user's attention by displaying a message close to the inputs where data needs to be revised.

![visualization of four different notice designs next to one another](https://developer.woocommerce.com/wp-content/uploads/2023/12/notices1.png)

**Success** message: When the user performs an action that is executed successfully.

**Error Message**: When the user performs an action that could not be completed. (This can include validation messages.) When requiring the user to input data, make sure you verify whether each field meets the requirements, such as format, ranges, and if the field is required. Provide validation messages that are adjacent to each field so that the user can act on each in context. Avoid technical jargon.

**Warning Message**: When the user performs an action that may have completed successfully, but the user should review it and proceed with caution.
... (7 lines truncated)
</file>

<file path="docs/extensions/ux-guidelines-extensions/onboarding.md">
---
post_title: Onboarding
sidebar_label: Onboarding
---

# Onboarding

The first experience your users have with your extension is crucial. A user activating your extension for the first time provides an opportunity to onboard new and reorient returning users the right way. Is it clear to the user how to get started? Keep in mind that the more difficult the setup, the more likely a user will abandon the product altogether so keep it simple and direct.

**Use primary buttons as calls to action and keep secondary information deprioritized for clarity**. Guide merchants towards successful setup with a clear next step and/or step-by-step process with progress indicator if the extension isn't configured or if setup is not complete.

**If necessary, provide a dismissible notification in the plugin area**. Add a notification to communicate next steps if setup or connection is required to successfully enable the plugin.

- Use the standard WordPress notice format and WooCommerce admin notices API.
- Notices should be dismissible. Users should always have a clear way to close the notice.
- Keep the post-activation notice with the WordPress plugin area in context of the plugin listing-do not display it on the dashboard, or any other parts of the platform.
- Don't display more than one notice.
- Try to keep the notice copy between 125 to 200 characters.

If no action is required for setup it's best to rely on other onboarding aids such as the Task List (link to component) and Inbox (link to component) to help users discover features and use your plugin.

**Get to the point and keep it instructional**. This is not a time to promote your brand or pitch the product. The user has bought your product and is ready to use it. Keep the information instructional and precise and avoid the use of branded colors, fonts, and illustrations in empty states and other onboarding aids. Help users with context on next steps.

**Show helpful empty states**. Rely on the existing plugin UI, if any, to guide users towards successful setup and use of the plugin. Avoid onboarding emails, push notifications, and welcome tours.

**Plugins should not redirect on activation from WordPress plugins area**. This can break bulk activation of plugins. Following the [dotorg plugin guideline 11](https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/#11-plugins-should-not-hijack-the-admin-dashboard), the extension shouldn't hijack the dashboard or hide functionality of core or other extensions.

**Avoid dead end links and pages**. There should always be a way forward or back.

**Error Handling and Messaging**. If users encounter an error during setup, provide a clear and useful notification with clear and easily understood information on what went wrong and how to fix it.
... (1 lines truncated)
</file>

<file path="docs/extensions/ux-guidelines-extensions/README.md">
---
sidebar_label: Extension guidelines
category_slug: user-experience-extensions
post_title: Extension guidelines
---

# Extension Guidelines

This section covers general guidelines, and best practices to follow in order to ensure your product experience aligns with WooCommerce for ease of use, seamless integration, and strong adoption.

We strongly recommend you review the current [WooCommerce setup experience](https://woocommerce.com/documentation/plugins/woocommerce/getting-started/) to get familiar with the user experience and taxonomy.

We also recommend you review the [WordPress core guidelines](https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/) to ensure your product isn't breaking any rules, and review [this helpful resource](https://woocommerce.com/document/grammar-punctuation-style-guide/) on content style.

## General

Use existing WordPress/WooCommerce UI, built in components (text fields, checkboxes, etc) and existing menu structures.

Plugins which draw on WordPress' core design aesthetic will benefit from future updates to this design as WordPress continues to evolve. If you need to make an exception for your product, be prepared to provide a valid use case.

-   [WordPress Components library](https://wordpress.github.io/gutenberg/?path=/story/docs-introduction--page)
-   [Figma for WordPress](https://make.wordpress.org/design/2018/11/19/figma-for-wordpress/) | ([WordPress Design Library Figma](https://www.figma.com/file/e4tLacmlPuZV47l7901FEs/WordPress-Design-Library))
-   [WooCommerce Component Library](https://woocommerce.github.io/woocommerce/)

## Component Library - Storybook

> Storybook is an open source tool for developing UI components in isolation for React, React Native and more. It makes building stunning UIs organized and efficient.

The WooCommerce repository also includes [Storybook](https://storybook.js.org/) integration that allows testing and developing in a WooCommerce-agnostic context. This is very helpful for developing reusable components and trying generic JavaScript modules without any backend dependency.

... (4 lines truncated)
</file>

<file path="docs/extensions/ux-guidelines-extensions/settings.md">
---
post_title: Settings
sidebar_label: Settings
---

# Settings

**Make extension settings easy to understand.** Only include settings options that are crucial to the overall functionality of the product.

**Use smart defaults wherever possible**, rather than asking the merchant to configure.

**Group your settings intuitively.** Prioritize frequently-used settings at the top of each section, and place destructive or infrequently-used settings at the bottom.

**Group relevant settings together**, either by frequency of use (eg. Quick Settings), or by description (eg. Account Settings). Use section titles and sub-section titles to create clear hierarchy.

**Avoid long, tedious lists of many different types of settings.** This overwhelms the user with so many options that the product feels unusable to them. Consider using separate pages or sections for different types of settings, or progressive disclosure that surfaces the most used settings and hides everything else.

**Use impersonal titles and text**, eg. "Reports" instead of "My reports." Exception: If referring to the user is necessary for understanding the setting, use the second person ("you") rather than the first person ("I").

**Include helper text** for settings or sections that are not easily understandable.

**Use clear and consistent language.** Avoid technical jargon.
</file>

<file path="docs/extensions/ux-guidelines-extensions/task-list-and-inbox.md">
---
post_title: Task list and inbox
sidebar_label: Task list and inbox
---

# Task List and Inbox

Plugins should choose between implementing a Task or Inbox note based on the following guidelines. Avoid implementing both Task and Inbox note for the same message, which adds clutter and reduces the impact of the message.

Use the Task List and Inbox sparingly. Messages should be clear, concise, and maintain a consistent tone. Follow the [Grammar, Punctuation, and Capitalization guide](https://woocommerce.com/document/grammar-punctuation-style-guide/).

## Task List

![an example of a task in the task list](https://developer.woocommerce.com/wp-content/uploads/2023/12/task-list1.png)

Anything that **requires** action should go in the task list.

- *What appears in the Things to Do Task List:*

    - Tasks that will enable, connect, or configure an extension.
    - Tasks that are critical to the business, such as capturing payment or responding to disputes.

- *What doesn't appear in the Things to do Task List:*

    - Any critical update that would impact or prevent the functioning of the store should appear as a top level notice using the standard WordPress component.
    - Informational notices such as feature announcements or tips for using the plugin should appear in the Inbox as they are not critical and do not require action.
    - Notifications from user activity should result in regular feedback notices (success, info, error, warning).

Examples:

... (22 lines truncated)
</file>

<file path="docs/extensions/ux-guidelines-extensions/testing.md">
---
post_title: Testing
sidebar_label: Testing
---

# Testing

Users must be able to perform all actions of the functionality provided. This can be achieved by running user tests.

To run an effective user test, list as many scenarios your extension supports. An example of a scenario: "I am a store owner who wants to create a customizable product that includes letting customers add custom text and select from 5 different color options for the custom text." Give this scenario to testers, and watch them attempt/perform the task with your extension.

Different ways to do quick user testing:

- Recruit potential customers to test your product.
- Use online services that allow you to expose your extension to new users such as UserTesting.com.
- Ask enthusiasts in the [WooCommerce Community Slack](https://woocommerce.com/community-slack/) for feedback.
</file>

<file path="docs/extensions/_category_.json">
{
    "label": "Extensions",
    "customProps" : {
      "id" : "extensions"
    }
}
</file>

<file path="docs/features/analytics/_category_.json">
{
    "position": 6,
    "label": "Analytics",
    "collapsible": true,
    "collapsed": true,
    "link": {
        "type": "generated-index",
        "title": "Analytics",
        "slug": "/features/analytics"
    }
}
</file>

<file path="docs/features/analytics/adding-columns-to-analytics-reports-and-csv-downloads.md">
---
post_title: How to add columns to analytics reports and CSV downloads
sidebar_label: Add columns to analytics reports
sidebar_position: 2
---

# How to add columns to analytics reports and CSV downloads

Adding columns to analytics reports are a really interesting way to add functionality to WooCommerce. New data can be consumed in the table view of the user interface and in your user's favourite spreadsheet or third party application by generating a CSV.

These instructions assume that you have a test plugin for WooCommerce installed and activated. You can follow the ["Getting started" instructions](extending-woocommerce-admin-reports.md) to get a test plugin set up. That post also includes instructions to further modify the query that is executed to get the data in an advanced fashion - it isn't required to just add a simple column.

In WooCommerce, analytics CSVs are generated in two different ways: in the web browser using data already downloaded, or on the server using a new query. It uses the size of the data set to determine the method - if there is more than one page worth of results it generates the data on the server and emails a link to the user, but if the results fit on one page the data is generated and downloaded straight away in the browser.

We'll look at the on-server method for adding a column first, because this is also where the data sent to the browser is generated.

This example extends the Downloads analytics report. To get some data in your system for this report, create a downloadable product with a download expiry value, create an order purchasing the product, then download the product several times. In testing I created 26 downloads, which is enough that the report is spread over two pages when showing 25 items per page, and on a single page when showing 50 items per page. This let me test CSVs generated both on the server and in browser.

In the PHP for your plugin, add three filter handlers:

```php
// This adds the SELECT fragment to the report SQL
function add_access_expires_select( $report_columns, $context, $table_name ) {
	if ( $context !== 'downloads' ) {
		return $report_columns;
	}
	$report_columns['access_expires'] =
		'product_permissions.access_expires AS access_expires';
	return $report_columns;
}
... (63 lines truncated)
</file>

<file path="docs/features/analytics/extending-woocommerce-admin-reports.md">
---
post_title: How to extend WooCommerce analytics reports
description: A guide to extending WC-Admin Reports with a basic UI dropdown, added query parameters, and modification of SQL queries and resulting report data.
sidebar_label: Extend analytics reports
sidebar_position: 1
---

# How to extend WooCommerce analytics reports

## Introduction

This document serves as a guide to extending WC-Admin Reports with a basic UI dropdown, added query parameters, and modification of SQL queries and resulting report data. This example will create a currency selector for viewing the Orders Report based on a specific currency.

## Getting started

We'll be using `@woocommerce/create-woo-extension` to scaffold a modern WordPress JavaScript environment for plugins. This tool creates a fully functional development environment for integrating with WooCommerce.

In this example, we'll be using the `sql-modification` variant to create a basic report extension that we can build upon.

In your `wp-content/plugins` directory, run the following command to create your extension:

```sh
npx @wordpress/create-block -t @woocommerce/create-woo-extension --variant=sql-modification my-extension-name
```

Navigate to the newly created folder and start development:

```sh
cd my-extension-name
npm run start
... (286 lines truncated)
</file>

<file path="docs/features/email/_category_.json">
{
    "position": 5,
    "label": "Email",
    "collapsible": true,
    "collapsed": true,
    "link": {
        "type": "generated-index",
        "title": "Email",
        "slug": "/features/email"
    }
}
</file>

<file path="docs/features/email/email-editor-integration.md">
---
post_title: Email editor integration
sidebar_label: Email editor integration
---

# WooCommerce email editor integration guide

This guide shows how extensions can add custom email notifications that integrate with the WooCommerce Email Editor.  
**Note:** The WooCommerce Email Editor is currently in alpha. To enable it, go to **WooCommerce > Settings > Advanced > Features** and enable **Block Email Editor (alpha)**.

## Quick start

1. **Extend `WC_Email`** – Create a custom email class for your notification by extending the core WooCommerce email class.
2. **Register with `woocommerce_email_classes`** – Add your new email class to WooCommerce so it appears in the admin email settings.
3. **Register the email with the block editor** – Register your email ID with the `woocommerce_transactional_emails_for_block_editor` filter to enable block editor support.
4. **Create a block template** – Design a block-based template to ensure your email works seamlessly with the WooCommerce Email Editor.
5. **Set up triggers** – Define when and under what conditions your custom email should be sent (for example, after a specific user action or event).

## 1. Create email class

Extend `WC_Email` and implement the required methods:

```php
class YourPlugin_Custom_Email extends WC_Email {

    public function __construct() {
        $this->id             = 'your_plugin_custom_email';
        $this->title          = __( 'Custom Email', 'your-plugin' );
        $this->customer_email = true;
        $this->email_group    = 'your-plugin';
... (567 lines truncated)
</file>

<file path="docs/features/email/email-editor-logging.md">
---
post_title: Email editor logging
sidebar_label: Email editor logging
sidebar_position: 3
---

# Email Editor Logging

Email editor logging uses a severity threshold to reduce noise during normal operation. By default, only warnings and above are logged. To change the logging level, use the `woocommerce_email_editor_logging_threshold` filter:

```php
add_filter( 'woocommerce_email_editor_logging_threshold', function() {
    return WC_Log_Levels::DEBUG;
} );
```

This will enable logging for all email editor operations, such as email editor initialization, personalization tag registration, etc.

For available log levels and their priority, see the [Logging in WooCommerce](/docs/best-practices/data-management/logging/#level) documentation.
</file>

<file path="docs/features/email/email-html-best-practices.md">
---
post_title: HTML best practices
description: Best practices for HTML emails to ensure proper rendering across all major email clients.
sidebar_label: HTML best practices
sidebar_position: 1
---

# Email HTML - Best Practices

## Overview

Email design and development require a different approach than traditional web development. This guide outlines best practices for ensuring your HTML emails render correctly across all major email clients.

### Key principles

- **Width**: Keep your email width between 600-640px - This ensures your email displays properly across all devices without horizontal scrolling on smaller screens.
- **File size**: Keep total email size under 100KB - Large emails may be clipped by Gmail and other providers, and take longer to load on mobile devices.
- **Tables**: Use tables for layout (despite being deprecated for the web) - Email clients have inconsistent CSS support but reliable table rendering.
- **Testing**: Test across multiple email clients and devices - Email clients render HTML differently, and testing helps identify and fix rendering issues.

## HTML

### Use older, simpler HTML standards

- Use HTML 4.01 or XHTML 1.0 - Many email clients use outdated rendering engines and don't support modern HTML5 features.
- Avoid HTML5 elements in the main structure - Elements like `<section>`, `<article>`, and `<aside>` aren't supported in all email clients.
- Always use lowercase for tags and attributes - This ensures maximum compatibility and prevents rendering issues in strict clients.
- Always use quotes for attribute values - Unquoted attributes can cause parsing errors in some email clients.
- Close all tags, even self-closing ones with a trailing slash (`<br />`) - This prevents rendering issues in clients that expect XHTML-style syntax.

... (282 lines truncated)
</file>

<file path="docs/features/email/email-preview.md">
---
post_title: Email preview integration
description: How to integrate with WooCommerce's email preview feature to showcase custom email templates.
sidebar_label: Email preview integration
sidebar_position: 2
---

# Email Preview Integration

## Overview

WooCommerce's Email Preview feature allows you to preview email templates using dummy data (i.e., it doesn't use the actual data from the database). This means that extensions registering new email types need to integrate with the email preview system to properly showcase their emails. 

## Integration Hooks

The following hooks allow extensions to take full control of email preview:

### Style and Content Settings

These hooks allow extensions to add new style and content settings that the email preview listens for changes, and updates the preview when changes are made.

#### `woocommerce_email_preview_email_style_setting_ids`

Add new email style settings that the email preview listens for changes.

```php
add_filter( 'woocommerce_email_preview_email_style_setting_ids', function( $setting_ids ) {
    $setting_ids[] = 'my_extension_email_style';
    return $setting_ids;
} );
... (124 lines truncated)
</file>

<file path="docs/features/mcp/_category_.json">
{
    "position": 8,
    "label": "Model Context Protocol (MCP)",
    "collapsed": false
}
</file>

<file path="docs/features/mcp/README.md">
---
post_title: Model Context Protocol (MCP) Integration
sidebar_label: MCP Integration
category_slug: mcp
---

# Model Context Protocol (MCP) Integration

## Introduction

WooCommerce includes native support for the Model Context Protocol (MCP), enabling AI assistants and tools to interact directly with WooCommerce stores through a standardized protocol. This integration exposes WooCommerce functionality as discoverable tools that AI clients can use to perform store operations with proper authentication and permissions.

:::info

**Developer Preview Notice**
The MCP implementation in WooCommerce is currently in developer preview. Implementation details, APIs, and integration patterns may change in future releases as the feature matures.

:::

## Background

The Model Context Protocol (MCP) is an open standard that enables AI applications to securely connect to external data sources and tools. WooCommerce's MCP integration builds on two core technologies:

- **[WordPress Abilities API](https://github.com/WordPress/abilities-api)** - A standardized system for registering capabilities in WordPress
- **[WordPress MCP Adapter](https://github.com/WordPress/mcp-adapter)** - The core MCP protocol implementation

This architecture allows WooCommerce to expose operations as MCP tools through the flexible WordPress Abilities system while maintaining existing security and permission models.

## What's Available

... (415 lines truncated)
</file>

<file path="docs/features/orders/high-performance-order-storage/_category_.json">
{
    "position": 90,
    "label": "High Performance Order Storage",
    "description": "High Performance Order Storage (HPOS) is a new way to store orders in WooCommerce. It is designed to improve performance and scalability for stores with large numbers of orders.",
    "collapsible": true,
    "collapsed": true,
    "link": {
        "type": "doc",
        "id": "README"
    }
}
</file>

<file path="docs/features/orders/high-performance-order-storage/cli-tools.md">
---
post_title: HPOS CLI Tools
sidebar_label: CLI tools
sidebar_position: 5
---

# HPOS CLI Tools

## Overview

We have a number of [WP-CLI commands](https://developer.woocommerce.com/docs/category/wc-cli/) that can be used to manage HPOS-related functionality, all of which live under the `wp wc hpos` namespace (though you may come across blog posts and older documentation referencing the now-deprecated `wp wc cot` namespace).

The following table provides an overview of what each command does, while more details and examples can be found below.

Keep in mind that the commands themselves have documentation and examples that can be accessed via WP-CLI's help by passing the `--help` flag.

|Command|Use this command to...|
|----|-----|
|`wc hpos status`|Get an overview of all HPOS matters on your site.|
|`wc hpos enable`|Enable HPOS (and possibly compatibility mode).|
|`wc hpos disable`|Disable HPOS (and possibly compatibility mode).|
|`wc hpos count_unmigrated`|Get a count of all orders pending sync.|
|`wc hpos sync`|Performantly sync orders from the currently active order storage to the other.|
|`wc hpos verify_data`|Verify data between datastores.|
|`wc hpos diff`|Get an user friendly version of the differences for an order between both order storages.|
|`wc hpos backfill`|Copy over whole orders or specific bits of order data from any order storage to the other.|
|`wc hpos cleanup`|Remove order data from legacy tables.|

## Usage and examples

... (332 lines truncated)
</file>

<file path="docs/features/orders/high-performance-order-storage/enable-hpos.md">
---
post_title: How to enable High Performance Order Storage
sidebar_label: Enable HPOS
sidebar_position: 1
---

# How to enable High Performance Order Storage

From WooCommerce 8.2, released on October 2023, HPOS is enabled by default for new installations. Existing stores can switch to the "High-Performance Order Storage" from "WordPress Posts Storage" by following the below steps.

To activate High-Performance Order Storage, existing stores will first need to get both the posts and orders table in sync, which can be done by turning on the setting "**Enable compatibility mode (synchronizes orders to the posts table)**".

1. Navigate to **WooCommerce > Settings > Advanced > Features**
2. Turn on the **"Enable compatibility mode (synchronizes orders to the posts table)"** setting.

    ![Enable HPOS Screen](https://developer.woocommerce.com/wp-content/uploads/2023/12/New-Project-4.jpg)

3. Once this setting is activated, background actions will be scheduled.

    - The action `wc_schedule_pending_batch_process` checks whether there are orders that need to be backfilled.
    - If there are, it schedules another action `wc_run_batch_process` that actually backfills the orders to post storage.
    - You can either wait for these actions to run on their own, which should be quite soon, or you can go to **WooCommerce > Status > Scheduled Actions**, find the actions and click on the run button.
    - The action will backfill 25 orders at a time, if there are more orders to be synced, then more actions will be scheduled as soon as the previous actions are completed.

    ![wc_schedule_pending_batch_process Screen](https://developer.woocommerce.com/wp-content/uploads/2023/12/2.jpg)
    ![wc_run_batch_process Screen](https://developer.woocommerce.com/wp-content/uploads/2023/12/New-Project-5.jpg)

4. After both tables are successfully synchronized, you'll be able to select the option to switch to High-Performance Order Storage (HPOS).
  
    - It is advisable to maintain compatibility mode for some time to ensure a seamless transition. In case of any issues, reverting to the post table can be done instantly.
... (1 lines truncated)
</file>

<file path="docs/features/orders/high-performance-order-storage/guide-large-store.md">
---
post_title: A large store's guide to enable HPOS on WooCommerce
sidebar_label: Enable HPOS for large stores
sidebar_position: 2
---

# A large store's guide to enable HPOS on WooCommerce

Do you run a high-volume WooCommerce store? Are you about to embark on the task to enable High Performance Order Storage (HPOS) on said store? As we move more and more high-volume store to HPOS, we decided to document the guidelines for those of you who may be faced with this task.

## Before you begin

1. [Intro to High-Performance Order Storage](/docs/features/orders/high-performance-order-storage/)
2. [High-Performance Order Storage Upgrade Recipe Book](/docs/features/orders/high-performance-order-storage/recipe-book/)
3. [High-Performance Order Storage: Backward Compatibility and Synchronization](https://developer.woocommerce.com/2022/09/29/high-performance-order-storage-backward-compatibility-and-synchronization/)
4. [Intro to High-Performance Order Storage for non-devs](https://woocommerce.com/document/high-performance-order-storage/)

## Phase 1: Test out HPOS on a local development system

If you have a local development setup for your site, you can try out HPOS on your development setup. Make sure that you have all plugins and any custom code enabled on this test site and that you're running their latest versions. The test environment should mimic your production site as much as possible.

At the very least, we suggest you focus on the following tests:

1. Test checkout with every payment method.
2. Test refunds for those checkouts.
3. If you are using WooCommerce Subscriptions, check that subscriptions can be purchased and renewals come through.
4. Any critical flows you've defined for your site.

You can repeat the tests with both synchronization enabled and disabled.

... (112 lines truncated)
</file>

<file path="docs/features/orders/high-performance-order-storage/README.md">
---
sidebar_label: High Performance Order Storage
category_slug: hpos
post_title: High Performance Order Storage (HPOS)
---

# High Performance Order Storage (HPOS)

WooCommerce has traditionally stored store orders and related order information (like refunds) as custom WordPress post types or post meta records. This comes with performance issues.

[High-Performance Order Storage (HPOS)](https://developer.woocommerce.com/2022/09/14/high-performance-order-storage-progress-report/) also previously known as "Custom Order Tables" is a solution that provides an easy-to-understand and solid database structure - specifically designed for eCommerce needs. It uses the WooCommerce CRUD design to store order data in custom tables - optimized for WooCommerce queries with minimal impact on the store's performance.

In January 2022, we published the [initial plan for the Custom Order Tables feature](https://developer.woocommerce.com/2022/01/17/the-plan-for-the-woocommerce-custom-order-table/) and since then, we've been working hard to bring the High-Performance Order Storage (HPOS) to WooCommerce Core. In May 2022, we invited you to [test the order migration process](https://developer.woocommerce.com/2022/05/16/call-for-early-testing-custom-order-table-migrations/) and provide feedback on how our initial work performs on real stores of varied configurations.

From WooCommerce 8.2, released on October 2023, [High-Performance Order Storage (HPOS)](https://developer.woocommerce.com/2022/09/14/high-performance-order-storage-progress-report/)  is officially released under the stable flag and will be enabled by default for new installations.

## What's New with High-Performance Order Storage?

Bringing High-Performance Order Storage (HPOS) to WooCommerce improves these three essential properties for eCommerce stores.

### Scalability

The rise in the number of customers and customer orders increases the load on your store's database - making it difficult to handle customer order requests and deliver a seamless user experience.

With High-Performance Order Storage, you get dedicated tables for data like orders and order addresses and thus dedicated indexes which results in fewer read/write operations and fewer busy tables. This feature enables eCommerce stores of all shapes and sizes to scale their business to their maximum potential - without expert intervention.

### Reliability

High-Performance Order Storage makes implementing and restoring targeted data backup easier. You'll no longer need to worry about losing orders, inventory numbers, or client information with reliable backup in these custom order tables. It'll also facilitate implementing read/write locks and prevent race conditions.

... (139 lines truncated)
</file>

<file path="docs/features/orders/high-performance-order-storage/recipe-book.md">
---
post_title: HPOS extension recipe book
sidebar_label: Extension recipe book
sidebar_position: 3
---

# HPOS extension recipe book

## What is High-Performance Order Storage (HPOS)?

Up until recently, WooCommerce stored order-related data in the post and postmeta tables in the database as a custom WordPress post type, which allowed everyone working in the ecosystem to take advantage of extensive APIs provided by the WordPress core in managing orders as custom post types.

However, in early 2022, [we announced the plans to migrate to dedicated tables for orders](https://developer.woocommerce.com/2022/01/17/the-plan-for-the-woocommerce-custom-order-table/). Orders in their own tables will allow the shops to scale more easily, make the data storage simpler and increase reliability. For further details, please check out our [deep dive on the database structure on our dev blog](https://developer.woocommerce.com/2022/09/15/high-performance-order-storage-database-schema/).

Generally, WooCommerce has tried to be fully backward compatible with the older versions, but, as a result of this project, extension developers will be required to make some changes to their plugins to take advantage of the HPOS. This is because the underlying data structure has changed fundamentally.

More specifically, instead of using WordPress-provided APIs to access order data, developers will need to use WooCommerce-specific APIs. We [introduced these APIs in WooCommerce version 3.0](https://developer.woocommerce.com/2017/04/04/say-hello-to-woocommerce-3-0-bionic-butterfly/) to make the transition to HPOS easier.

In this guide, we will focus on the changes required to make an extension, or any snippet of custom code, compatible with HPOS.

For details on how to take enable or disable HPOS, as well as details on how orders are synced between datastores please refer to the [HPOS documentation](https://woocommerce.com/document/high-performance-order-storage/).

## Backward compatibility

To make the transition easier for shops and developers alike, we have tried to be as backward compatible as possible. One of the major compatibility issues with this project is that since the underlying data structure was `wp_posts` and `wp_postmeta` tables, circumventing the WC-specific CRUD classes and accessing the data directly using WordPress APIs worked fine.

Now that this has changed, directly reading from these WordPress tables may mean reading an outdated order, and directly writing to these tables may mean updating an order that will not be read. Since this is a pretty significant issue, we have added a few mitigations for the transitory period.

### Switching data source

... (157 lines truncated)
</file>

<file path="docs/features/orders/high-performance-order-storage/wc-order-query-improvements.md">
---
post_title: HPOS order querying APIs
sidebar_label: Order querying APIs
sidebar_position: 4
---

# HPOS order querying APIs

With the introduction of HPOS, we've enhanced the querying functionality in WC. Now, in addition to the well-known [existing APIs](/docs/features/orders/wc-get-orders), we're adding a few features that would make it easier to create complex queries on orders or their properties, including the ability to query custom order metadata.

All the new query types are implemented as additional query arguments that can be passed to `wc_get_orders()` and are heavily inspired by similar functionality in WordPress' own `WP_Query`. As regular query arguments, they can be combined with other arguments to produce complex queries that, until now, would have required writing custom code and SQL.

## The new query types

### Metadata queries (`meta_query`)

With the introduction of HPOS, order fields that were previously stored as post metadata have been moved to their own tables, but the remaining metadata (custom, or from other extensions) can now be queried through the `meta_query `argument.

At its core, `meta_query` is an array that can contain one or more arrays with keys:
`key` (the meta key name),
`value` (the meta value)
`compare` (optional) an operator to use for comparison purposes such as LIKE, RLIKE, NOT BETWEEN, BETWEEN, etc.
`type` to cast the meta value to a specific SQL type in the query

The different arrays can also be combined using `relation` (which admits 'AND' or 'OR' values) to produce more complex queries. The syntax for this new argument is exactly the same as for WP_Query's `meta_query`. As such, you can refer to the [`meta_query` docs](https://developer.wordpress.org/reference/classes/wp_query/#custom-field-post-meta-parameters) for more details.

```php
// Example: obtain all orders which have metadata with the "color" key (any value) and have metadata
// with key "size" containing "small" (so it'd match "extra-small" as well as "small", for example).
$orders = wc_get_orders(
... (155 lines truncated)
</file>

<file path="docs/features/orders/_category_.json">
{
    "position": 2,
    "label": "Orders",
    "collapsible": true,
    "collapsed": true,
    "link": {
        "type": "generated-index",
        "title": "Orders",
        "slug": "/features/orders"
    }
}
</file>

<file path="docs/features/orders/wc-get-orders.md">
---
sidebar_label: Order Querying
sidebar_position: 1
---

# `wc_get_orders()` and order queries

`wc_get_orders()` and `WC_Order_Query` provide a standard way of retrieving orders from the database, similar to WordPress' [`get_posts()` and `WP_Query`](https://codex.wordpress.org/Class_Reference/WP_Query) but specifically for orders.

Plugin and theme developers are discouraged from writing custom WordPress queries or direct SQL as changes in the WordPress or WooCommerce database can result in breakage. These APIs provide the best-practices and future-proof way to fetch orders in WooCommerce.

## Basic usage

### Examples

Here are a few examples:

```php
// Get orders from people named John paid in 2016.
$orders = wc_get_orders(
    array(
        'billing_first_name' => 'John',
        'date_paid'          => '2016-01-01...2016-12-31',
    )
);
```

```php
// Get 10 most recent order IDs.
$query = new WC_Order_Query(
... (491 lines truncated)
</file>

<file path="docs/features/payments/ux-guidelines/_category_.json">
{
    "position": 90,
    "label": "UX guidelines",
    "description": "UX guidelines for payments in WooCommerce.",
    "collapsible": true,
    "collapsed": true,
    "link": {
        "type": "doc",
        "id": "README"
    }
}
</file>

<file path="docs/features/payments/ux-guidelines/payment-button-layout.md">
---
post_title: Payment button layout
sidebar_label: Payment button layout
sidebar_position: 4
---

# Payment Button Layout

Define the position and alignment of buttons in relationship to their container, with equal hierarchy and consistent spacing between buttons.

## Product pages

Position payment buttons correctly in relation to "Add to Cart" in horizontal or vertical layout, place payment buttons to the right of or below the "Add to Cart" button.

![Product page layout.png](/img/doc_images/Product-page-layout.png)

## Cart

Position payment buttons correctly in relation to "Proceed to checkout" buttons in vertical layout. Place payment buttons above the "Proceed to checkout" button. Do not place payment buttons below the button or in between.

![Cart layout.png](/img/doc_images/Cart-layout.png)

## Express checkout

Position payment buttons correctly in horizontal layout, consistent in size and spacing. If a second row is required, left-align the buttons.

![Express checkout layout.png](/img/doc_images/Express-checkout-layout.png)

## Mobile view

... (10 lines truncated)
</file>

<file path="docs/features/payments/ux-guidelines/payment-button-size.md">
---
post_title: Payment button size
sidebar_label: Payment button size
sidebar_position: 2
---

# Payment Button Size and Anatomy

Payment buttons must be consistent in visual appearance to other buttons in the shopper experience.

Height for payment buttons ranges from 40px (Small) to 55px (Large). The default button height is 48px. The following presets can be used for button height.

- Small: Height 40px
- Default: Height 48px
- Large: Height 55px

## Anatomy

Payment buttons consist of up to three elements: a button component, payment logo, and optional label.

![Anatomy of a payment button](/img/doc_images/Anatomy-updated.png)

Don't place any text outside the surface area of the button.

![Cart layout 2](/img/doc_images/Cart-layout-2.png)

## Layout and spacing

The spacing between and around the Label and Payment Logo adapts based on the size of the button.

... (57 lines truncated)
</file>

<file path="docs/features/payments/ux-guidelines/payment-button-style.md">
---
post_title: Payment button style
sidebar_label: Payment button style
sidebar_position: 3
---

# Payment Button Style

Use the appropriate button style depending on the site theme.

![Button styles.png](/img/doc_images/Button-styles.png)

## Dark

Use on white or light-color backgrounds. Don't use on black or dark backgrounds.

![Dark.png](/img/doc_images/Dark.png)

## Light

Use on dark-color backgrounds. Don't use on white or light backgrounds.

![Light.png](/img/doc_images/Light.png)

## Light with outline

Use on white or light-color backgrounds that don't provide sufficient contrast. Don't use on dark or saturated backgrounds.

![Light with outline.png](/img/doc_images/Light-with-outline.png)

... (6 lines truncated)
</file>

<file path="docs/features/payments/ux-guidelines/payments-onboarding.md">
---
post_title: Payments onboarding and setup
sidebar_label: Payments onboarding and setup
sidebar_position: 1
---

# Payments Onboarding and Setup

## Payments onboarding

Plugin authors should actively guide merchants through setup of the plugin once installed and activated.

### Third party onboarding

For plugins that use OAuth or a third party experience to obtain permission from the merchant, the merchant clicks on a link to set up your plugin, which redirects to the plugin onboarding.

The merchant is redirected to the payments plugin to complete configuration and completes any required authentication as part of this step.

For example:

- Prompt the merchant to login to or create an account with the payment provider.
- Ask the merchant to complete configuration for billing plans, payouts, or notifications.

### Manual setup

If manual entry of API keys is required, design the setup process to be as simple as possible, ideally with a guided setup wizard.

## Configuration & Settings

Follow the Woo User Experience guidelines for [Settings](/docs/extensions/ux-guidelines-extensions/settings) and [Navigation](/docs/extensions/ux-guidelines-extensions/navigation).
... (15 lines truncated)
</file>

<file path="docs/features/payments/ux-guidelines/README.md">
---
sidebar_label: Payments
category_slug: user-experience-payments
post_title: Payments guidelines
---

# Payments Guidelines

When building payments extensions, you should ensure you follow the [WooCommerce Extension Guidelines](https://developer.woocommerce.com/docs/extensions/ux-guidelines-extensions/).

Payments plugins come in many types: payment processors and gateways, wallets, Buy Now Pay Later, crypto, and more.

The choice between payment plugins depends on the specific needs and preferences of the merchant and their customers. Some merchants may choose to use multiple types of payment plugins to offer their customers a wider range of payment options.

A merchant can discover a payments plugin in the following ways:

- Through direct installation from WordPress plugins.
- Through Woo's public list of payment services on the Marketplace.
- Through the admin onboarding tasks and payments settings. To be added to the list of payment gateways in the Woo admin, the payments plugin must meet the criteria listed in these guidelines.
</file>

<file path="docs/features/payments/_category_.json">
{
    "position": 3,
    "label": "Payments",
    "collapsible": true,
    "collapsed": true,
    "link": {
        "type": "generated-index",
        "title": "Payments",
        "slug": "/features/payments"
    }
}
</file>

<file path="docs/features/payments/payment-gateway-api.md">
---
post_title: WooCommerce Payment Gateway API
sidebar_label: Payment Gateway API
sidebar_position: 1
---

# WooCommerce Payment Gateway API

Payment gateways in WooCommerce are class based and can be added through traditional plugins. This guide provides an intro to gateway development.

## Types of payment gateway

Payment gateways come in several varieties:

1.  **Form based** - This is where the user must click a button on a form that then redirects them to the payment processor on the gateway's own website. _Example_: PayPal standard, Authorize.net DPM
2.  **iFrame based** - This is when the gateway payment system is loaded inside an iframe on your store. _Example_: SagePay Form, PayPal Advanced
3.  **Direct** - This is when the payment fields are shown directly on the checkout page and the payment is made when 'place order' is pressed. _Example_: PayPal Pro, Authorize.net AIM
4.  **Offline** - No online payment is made. _Example_: Cheque, Bank Transfer

Form and iFrame based gateways post data offsite, meaning there are less security issues for you to think about. Direct gateways, however, require server security to be implemented ([SSL certificates](https://woocommerce.com/document/ssl-and-https/), etc.) and may also require a level of [PCI compliance](https://woocommerce.com/document/pci-dss-compliance-and-woocommerce/).

## Creating a basic payment gateway

**Note:** The instructions below are for the default Checkout page. If you're looking to add a custom payment method for the new Checkout block, check out [the payment method integration documentation](/docs/block-development/extensible-blocks/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration).

Payment gateways should be created as additional plugins that hook into WooCommerce. Inside the plugin, you need to create a class after plugins are loaded. Example:

```php
add_action( 'plugins_loaded', 'init_your_gateway_class' );
```
... (257 lines truncated)
</file>

<file path="docs/features/payments/payment-gateway-plugin-base.md">
---
post_title: WooCommerce payment gateway plugin base
sidebar_label: Payment gateway plugin base
sidebar_position: 2
---

# WooCommerce payment gateway plugin base

This code can be used as a base to create your own simple custom payment gateway for WooCommerce. If not used in a custom plugin, you need to add this code to your child theme's functions.php file or via a plugin that allows custom functions to be added, such as the [Code snippets](https://wordpress.org/plugins/code-snippets/) plugin. Please don't add custom code directly to your parent theme's functions.php file as this will be wiped entirely when you update the theme.


```php
<?php
/*
Plugin Name: WooCommerce <enter name> Gateway
Plugin URI: https://woothemes.com/woocommerce
Description: Extends WooCommerce with an <enter name> gateway.
Version: 1.0
Author: WooThemes
Author URI: https://woothemes.com/
	Copyright: © 2009-2011 WooThemes.
	License: GNU General Public License v3.0
	License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/
add_action('plugins_loaded', 'woocommerce_gateway_name_init', 0);
function woocommerce_gateway_name_init() {
	if ( !class_exists( 'WC_Payment_Gateway' ) ) return;
	/**
 	 * Localisation
	 */
... (22 lines truncated)
</file>

<file path="docs/features/payments/payment-token-api.md">
---
post_title: WooCommerce Payment Token API
sidebar_label: Payment Token API
sidebar_position: 3
---

# WooCommerce Payment Token API

WooCommerce 2.6 introduced an API for storing and managing payment tokens for gateways. Users can also manage these tokens from their account settings and choose from saved payment tokens on checkout.

This guide offers a few useful tutorials for using the new API as well as all the various methods available to you.

## Tutorials

### Adding Payment Token API Support To Your Gateway

We'll use the Simplify Commerce gateway in some of these examples.

#### Step 0: Extending The Correct Gateway Base

WooCommerce ships with two base classes for gateways. These classes were introduced along with the Token API in 2.6. They  are `WC_Payment_Gateway_CC` (for credit card based tokens) and `WC_Payment_Gateway_eCheck` (for eCheck based tokens). They contain some useful code for generating payment forms on checkout and should hopefully cover most cases.

You can also implement your own gateway base by extending the abstract `WC_Payment_Gateway` class, if neither of those classes work for you.

Since Simplify deals with credit cards, we extend the credit card gateway.

`class WC_Gateway_Simplify_Commerce extends WC_Payment_Gateway_CC`

#### Step 1: 'Supports' Array

... (574 lines truncated)
</file>

<file path="docs/features/products/_category_.json">
{
    "position": 1,
    "label": "Products",
    "collapsible": true,
    "collapsed": true,
    "link": {
        "type": "generated-index",
        "title": "Products",
        "slug": "/features/products"
    }
}
</file>

<file path="docs/features/products/adding-a-custom-field-to-variable-products.md">
---
post_title: How to add a custom field to simple and variable products
sidebar_label: Custom product fields
sidebar_position: 3
---

# How to add a custom field to simple and variable products

In this tutorial you will learn how to create a custom field for a product and show it in your store. Together we will set up the skeleton plugin, and learn about WP naming conventions and WooCommerce hooks. In the end, you will have a functioning plugin for adding a custom field.

The [full plugin code](https://github.com/EdithAllison/woo-product-custom-fields) was written based on WordPress 6.2 and WooCommerce 7.6.0

## Prerequisites

To do this tutorial you will need to have a WordPress install with the WooCommerce plugin activated, and you will need at least one [simple product set up](https://woocommerce.com/document/managing-products/), or you can [import the WooCommerce sample product range](https://woocommerce.com/document/importing-woocommerce-sample-data/).

## Setting up the plugin

To get started, let's do the steps to [create a skeleton plugin](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/create-woo-extension).

First, navigate to your wp-content/plugins folder, then run:

```sh
npx @wordpress/create-block -t @woocommerce/create-woo-extension woo-product-fields
```

Then we navigate to our new folder and run the install and build:

```sh
cd woo-product-fields
... (231 lines truncated)
</file>

<file path="docs/features/products/wc-get-products.md">
---
post_title: wc_get_products and product queries
sidebar_label: Product queries
sidebar_position: 1
---

# `wc_get_products` and product queries

`wc_get_products` and `WC_Product_Query` provide a standard way of retrieving products that is safe to use and will not break due to database changes in future WooCommerce versions. Building custom WP_Queries or database queries is likely to break your code in future versions of WooCommerce as data moves towards custom tables for better performance. This is the best-practices way for plugin and theme developers to retrieve multiple products. `wc_get_products` and `WC_Product_Query` are similar to WordPress [`get_posts` and `WP_Query`](https://developer.wordpress.org/reference/classes/wp_query/). Just like those, you pass in an array of arguments defining the criteria for the search.

## Basic usage

### Examples

Here are a few examples:

```php
// Get downloadable products created in the year 2016.
$products = wc_get_products( array(
    'downloadable' => true,
    'date_created' => '2016-01-01...2016-12-31',
) );
```

```php
// Get 10 most recent product IDs in date descending order.
$query = new WC_Product_Query( array(
    'limit' => 10,
    'orderby' => 'date',
    'order' => 'DESC',
... (432 lines truncated)
</file>

<file path="docs/features/shipping/_category_.json">
{
    "position": 4,
    "label": "Shipping",
    "collapsible": true,
    "collapsed": true,
    "link": {
        "type": "generated-index",
        "title": "Shipping",
        "slug": "/features/shipping"
    }
}
</file>

<file path="docs/features/shipping/shipping-method-api.md">
---
post_title: Shipping method API
sidebar_label: Shipping method API
sidebar_position: 1
---

# Shipping method API

WooCommerce has a Shipping Method API which plugins can use to add their own rates. This article will take you through the steps to creating a new shipping method based on the core Flat Rate method that interacts with the Shipping API.

## Create a plugin

First off, create a regular WordPress/WooCommerce plugin - see our [Building Your First Extension guide](/docs/extensions/getting-started-extensions/building-your-first-extension) to get started. You'll define your shipping method class in this plugin file and maintain it outside of WooCommerce.

## Checking for WooCommerce and creating a function to house your class

Before we attempt to load our class, we need to make sure that WooCommerce is active and the primary classes and functions necessary for us to work are available. Once we know those are available, we can add an action to initialize our class, and a filter to add our method to the primary shipping method list.

```php
/**
 * If WooCommerce is active, then these classes and function will exist.
 */
if ( class_exists( 'woocommerce' ) && class_exists( 'WC_Shipping_Method' ) && function_exists( 'WC' ) ) {
	// We add an action to init our shipping method class, and a filter to add our shipping method to the method list.
	add_action( 'woocommerce_shipping_init', 'your_shipping_method_init' );
	add_filter( 'woocommerce_shipping_methods', 'your_shipping_method_add' );
}

/**
 * Your function to add your shipping method to the shipping method list.
... (759 lines truncated)
</file>

<file path="docs/features/_category_.json">
{
    "position": 2,
    "label": "Features"
}
</file>

<file path="docs/features/address-autocomplete.md">
---
sidebar_label: Address autocomplete
sidebar_position: 7
---

# Address Autocomplete Provider Implementation

## Overview

The WooCommerce Address Autocomplete system allows third-party services to provide address suggestions as customers type in their billing and shipping addresses during checkout. This guide explains how to create and register custom address providers to integrate with any address validation service.

Please note, this implementation will register the provider for both the shortcode and block-based checkouts.

## Architecture

The address autocomplete system consists of three main components:

1. **Server-side Provider (PHP)** - Handles provider registration and configuration
2. **Client-side Provider (JavaScript)** - Implements the search and selection logic
3. **UI Components** - Displays suggestions and handles user interactions (this is implemented by WooCommerce, plugins do not have to provide this)

## Registering the server-side provider

### Step 1: Create a WC_Address_Provider subclass

Create a PHP class that extends `WC_Address_Provider`:

```php
<?php
/**
... (281 lines truncated)
</file>

<file path="docs/getting-started/_category_.json">
{
    "position": 1,
    "label": "Getting started",
    "collapsed": false
}
</file>

<file path="docs/getting-started/ai.md">
---
post_title: AI
sidebar_label: AI
sidebar_position: 3
---

# AI

This guide provides an overview of AI tools and how to use them to enhance your WooCommerce development workflows.

## MCP

WooCommerce includes native support for the Model Context Protocol (MCP), enabling AI assistants and tools to interact directly with WooCommerce stores through a standardized protocol. Visit our full [MCP documentation](/docs/features/mcp/) for more information.

## AI Documentation Tools

### LLMS.txt Files

To feed the WooCommerce Developer Documentation into your LLM or AI-assisted IDE, you have two options:

1. [`llms.txt`](https://developer.woocommerce.com/docs/llms.txt) - A table of contents that includes the title, URL, and description of each document in the developer docs.
2. [`llms-full.txt`](https://developer.woocommerce.com/docs/llms-full.txt) - A full Markdown-formatted export of the entire documentation in one file.

If you are using an IDE like Cursor or Windsurf, we recommend adding these links as custom documentation so that you can reference them as needed.

**Note** that these do not include the contents of the [WooCommerce Code Reference](https://woocommerce.github.io/code-reference/).

### Serve as Markdown

If you want to view the documentation as Markdown files, you can use append `.md` to the end of any documentation URL. For example, to view this page as Markdown, you can visit:   
... (35 lines truncated)
</file>

<file path="docs/getting-started/debugging.md">
---
post_title: Resources for debugging
sidebar_label: Debugging
sidebar_position: 7
---

# Resources for debugging

## WordPress

A good place to start is usually the debugging tools built into WordPress itself:

The documentation for [Debugging in WordPress c](https://wordpress.org/documentation/article/debugging-in-wordpress/)overs a number of environment variables you can set to enable WordPress’s core debugging tools.

### Query Monitor

A popular plugin for WordPress developers is [Query Monitor](https://wordpress.org/plugins/query-monitor/), the developer tools for WordPress. Query Monitor enables debugging of database queries, PHP errors, AJAX/Rest requests, hooks and actions, block editor blocks, enqueued scripts and stylesheets, HTTP API calls, and more.

### Email Debugging

When working in a local WooCommerce environment, we recommend enabling tools like Mailpit or Mailhog to redirect all transactional emails to a log rather then being sent.

Alternatively, you can use a plugin like Stop Emails to disable any accidental email triggering.

## WooCommerce

### Logging

WooCommerce has a logging system that can be very helpful for finding and tracking errors on your site:

... (16 lines truncated)
</file>

<file path="docs/getting-started/developer-tools.md">
---
post_title: WooCommerce developer tools
sidebar_label: Developer tools
sidebar_position: 5
---

# Developer tools

This guide provides an overview of essential tools and libraries for WooCommerce development. It's intended for developers looking to enhance their WooCommerce projects efficiently.

## Productivity Tools

Use these resources to power up your WooCommerce development workflows.

### Development

#### [wp-cli](https://wp-cli.org/)

This is the command-line interface for [WordPress](https://wordpress.org/). You can update plugins, configure multisite installations and much more, without using a web browser.

#### [wc-cli](/docs/wc-cli/cli-overview)

When WooCommerce is running on a WordPress installation, the WP-CLI is extended with additional functionality for managing your store data.

#### [wp-env](https://www.npmjs.com/package/@wordpress/env)

This command-line tool lets you easily set up a local WordPress Docker environment for building and testing plugins and themes. It's simple to install and requires no configuration.

#### [woocommerce/eslint-plugin](https://www.npmjs.com/package/@woocommerce/eslint-plugin)

... (78 lines truncated)
</file>

<file path="docs/getting-started/development-environment.md">
---
post_title: Setting up your development environment
sidebar_label: Local Development
sidebar_position: 2
---

# Setting up your development environment

## Recommended software

There are some specific software requirements you will need to consider when developing WooCommerce extensions. The necessary software includes:

* [Git](https://git-scm.com/) for version control of your source code  
* [Node.js](https://nodejs.org/) to run node-based scripts and build processes. PNPM installs and uses the Node version pinned in the repository automatically, so a version manager such as [nvm](https://github.com/nvm-sh/nvm/blob/master/README.md) is optional.  
* [Pnpm](https://pnpm.io/) is an npm alternative required if you are building WooCommerce from the repository  
* [Composer](https://getcomposer.org/) is an optional dependency management tool for PHP-based development  
* [WP-CLI](http://wp-cli.org/) is the command line interface for WordPress

Most WordPress hosting environments *do not include Node and Composer* by default, so when distributing extensions and themes, it’s important to include all built assets.

Note: A POSIX compliant operating system (e.g., Linux, macOS) is assumed. If you're working on a Windows machine, the recommended approach is to use [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) (available since Windows 10).

## Setting up a reusable WordPress development environment

In addition to the software shared above, you'll also want to have some way of setting up a local development server stack. There are a number of different tools available for this, each with a certain set of functionality and limitations. We recommend choosing from the options below that fit your preferred workflow best.

### WordPress Studio - Recommended Approach

For easy local development environments, we recommend [WordPress Studio](https://developer.wordpress.com/studio/), the local development environment supported by the [WordPress.com](https://developer.wordpress.com) team. Studio includes the ability to manage multiple local website environments, as well as integrations with your code editor and terminal. Studio also features a WordPress-specific AI Assistant, easy imports from WordPress backups, Blueprint support, free public preview sites, and two-way sync with sites hosted on WordPress.com or Pressable.

... (90 lines truncated)
</file>

<file path="docs/getting-started/project-structure.md">
---
post_title: Project structure
sidebar_label: Project structure
sidebar_position: 1
---

# Project Structure

## Prerequisites

WooCommerce adheres to WordPress code standards and guidelines, so it's best to familiarize yourself with [WordPress Development](https://learn.wordpress.org/tutorial/introduction-to-wordpress/) as well as [PHP](https://www.php.net/). Currently WooCommerce requires PHP 7.4 or newer.

Knowledge and understanding of [WooCommerce hooks and filters](https://woocommerce.com/document/introduction-to-hooks-actions-and-filters/?utm_source=wooextdevguide) will allow you to add and change code without editing core files. You can learn more about WordPress hooks and filters in the [WordPress Plugin Development Handbook](https://developer.wordpress.org/plugins/hooks/).

## Recommended reading

WooCommerce extensions are a specialized type of WordPress plugin. If you are new to WordPress plugin development, take a look at some of the articles in the [WordPress Plugin Developer Handbook](https://developer.wordpress.org/plugins/).

## Anatomy of a WordPress environment

While development environments can vary, the basic file structure for a WordPress environment should be consistent.

When developing a WooCommerce extension, you'll usually be doing most of your work within the `public_html/` directory of your local server.

There are three directories in a WordPress installation. The `wp-admin` and `wp-includes` directories include core functionality and should not be modified. The third directory, `wp-content` is where custom configurations and user-generated media is stored.

 Take some time to familiarize yourself with a few key paths inside `wp-content`:

* `wp-content/debug.log` is the file where WordPress writes the important output such as errors and other messages that can be useful for debugging.  
* `wp-content/plugins`/ is the directory on the server where WordPress plugin folders live.  
... (27 lines truncated)
</file>

<file path="docs/getting-started/README.md">
---
slug: /
sidebar_position: 0
sidebar_label: 'Getting Started'
---

# Getting started

WooCommerce is a customizable, open-source eCommerce platform built on WordPress. It empowers businesses worldwide to sell anything from physical products and digital downloads to subscriptions, content, and even appointments.

* Get familiar with [WordPress Plugin Development](https://developer.wordpress.org/plugins/).
* Take a moment to familiarize yourself with our [Developer Resources](https://developer.wordpress.org/plugins/plugin-basics/).
* Join the [Woo Community Slack](https://woo.com/community-slack/)

---

## Build WooCommerce extensions

Explore comprehensive guides and resources to build and enhance WooCommerce extensions. Dive into development best practices and innovative techniques for creating powerful extensions.

* [How to build your first extension](/docs/extensions/getting-started-extensions/building-your-first-extension)
* [Designing a simple extension](/docs/extensions/getting-started-extensions/how-to-design-a-simple-extension)
* [Extension development best practices](/docs/extensions/best-practices-extensions/extension-development-best-practices)

Learn more about [extension development](/docs/extensions/getting-started-extensions/)

---

## Build WooCommerce themes

... (34 lines truncated)
</file>

<file path="docs/getting-started/scaffolding.md">
---
post_title: Scaffolding and sample store data
sidebar_label: Scaffolding and sample data
sidebar_position: 4
---

# Scaffolding and sample store data

WooCommerce offers a number of starter kits and scaffolds depending on what you are building.

## Starter Themes

If you’re designing a WooCommerce store, you have two options for theme development: Classic Themes and Block Themes.

-   Classic themes use PHP templates to override designs to key pages on your store, including your product pages, product archives, shopping cart, and checkout page. While sites running a classic theme can use the WordPress block editor, many of the templates are not editable within the editor itself.
-   Block themes use the WordPress site editor to generate every aspect of the WordPress site, including the header and footer, product pages, archives, and the cart and checkout pages. Designs built in the site editor can be exported into flat HTML files, but the files themselves are typically edited in the WordPress editor.

### Storefront Theme (Classic)

Storefront is Woo’s flagship classic theme, available in the [WordPress Theme Directory](https://wordpress.org/themes/). You can either rename and modify the theme itself, or override specific aspects of it using a child theme.

For more information on building a classic WooCommerce theme, read our classic theme development handbook. For a comprehensive guide on creating a child block theme and understanding the differences between a classic and block theme, please refer to [WooCommerce block theme development](/docs/theming/block-theme-development/theming-woo-blocks) and [WordPress block child theme development](https://learn.wordpress.org/lesson-plan/create-a-basic-child-theme-for-block-themes/).

### Block Starter Themes

If you are completely new to block theme development, please check [Develop Your First Low-Code Block Theme](https://learn.wordpress.org/course/develop-your-first-low-code-block-theme/) to learn about block theme development, and explore the [Create Block Theme plugin](https://wordpress.org/plugins/create-block-theme/) tool when you're ready to create a new theme.

For more information, check out our [Block Theme Development handbook](/docs/theming/block-theme-development/theming-woo-blocks).

## Extension Scaffolds
... (39 lines truncated)
</file>

<file path="docs/getting-started/tools-for-low-code-development.md">
---
sidebar_position: 6
post_title: Tools for low-code development
sidebar_label: Low-code tools
---

# Tools for low-code development

## Introduction

This guide provides an introduction to low-code solutions, such as Gutenberg and WooCommerce Store Editing, as well as other page builders and pre-built components for creating WooCommerce stores without custom coding. By understanding and leveraging these tools, low code builders can assemble stores with minimal coding and focus on the design and user experience aspects of their e-commerce websites.

## Audience

This guide is intended for low code builders or anyone with a basic understanding of WordPress and WooCommerce who wants to create online stores without the need for extensive custom coding.

## Prerequisites

To follow this guide, you should have:

1. A basic understanding of WordPress and WooCommerce.
2. A WordPress website with WooCommerce installed and activated.

## Step 1 - Using Gutenberg and WooCommerce Store Editing

Gutenberg is the default block editor in WordPress that allows you to create and edit pages by adding and customizing blocks. WooCommerce has extended Gutenberg's functionality, enabling you to create and customize WooCommerce-specific elements, such as product pages and shop pages.

To use Gutenberg and WooCommerce Store Editing:

1. Ensure your WordPress installation is up-to-date to have the latest version of Gutenberg.
... (31 lines truncated)
</file>

<file path="docs/getting-started/version-control-deployment.md">
---
post_title: Version control and deployment
sidebar_label: Version control and deployment
sidebar_position: 8
---

# Version control and deployment

Because WordPress and WooCommerce are both developer frameworks *and* content management systems, it’s important to plan ahead for how you will version control your code and deploy changes to a live environment. A common rule is that “code goes up, content goes down,” meaning that you’ll push your custom code up from a local or staging environment, but never the contents of your database or user-generated content that lives in the `wp-content/uploads` directory.

## Considerations

There is no one-size-fits-all approach to deploying WordPress. Your hosting environment may have a dedicated approach that you need to follow, especially at more enterprise-level hosts like [WordPress VIP](https://docs.wpvip.com/development-workflow/). 

Based on the [project structure](/docs/getting-started/project-structure) of a WordPress installation and your unique needs, you may be version controlling and deploying different parts of your `wp-content` directory. Some common approaches include:

1. Version control starts from the root directory of WordPress, but includes a `.gitignore` file that ignores most of WordPress core and plugins, if your hosting company manages WordPress updates for you. An example `.gitignore` file is available [here from GitHub](https://github.com/github/gitignore/blob/main/WordPress.gitignore) and you can update it to ensure that your custom code is version controlled. This approach is more popular with builders who are managing each site in its own repository.   
2. Version control just the directory that you are working in, typically in `wp-content/plugins/your-extension` or `wp-content/themes/your-theme`. This approach is more common for extension and theme developers who are broadly distributing their code across multiple sites.

**Note:** Do not commit your `wp-config.php` file to a public repository. It may include sensitive information and most likely it will have differences from your local and production environments. 

## Building and Deployment

Most WordPress hosting environments *do not have support* for Node or Composer. You’ll need to confirm with the environment that you’re deploying to, but keep this in mind when setting up your workflow. Some popular approaches include:

1. Committing built files to your repository. Plugins and themes that come from the WordPress.org directory, for example, include all built assets for easy updates.  
2. Adding a build step via a tool like GitHub Actions or a separate CI/CD pipeline.
</file>

<file path="docs/theming/block-theme-development/_category_.json">
{
    "position": 1,
    "label": "Block theme development",
    "link": {
      "type": "doc",
      "id": "theming-woo-blocks"
    }
}
</file>

<file path="docs/theming/block-theme-development/cart-and-checkout.md">
---
post_title: Cart and Checkout blocks theming 
sidebar_label: Cart and Checkout blocks theming 

---

# Cart and checkout blocks theming 

> [!IMPORTANT]
> We strongly discourage writing CSS code based on existing block class names and prioritize using global styles when possible. We especially discourage writing CSS selectors that rely on a specific block being a descendant of another one, as users can move blocks around freely, so they are prone to breaking. Similar to WordPress itself, we consider the HTML structure within components, blocks, and block templates to be "private", and subject to further change in the future, so using CSS to target the internals of a block or a block template is _not recommended or supported_.

If your theme overrides `page-cart.html` or `page-checkout.html`, keep the Cart and Checkout blocks in the assigned page content and render that content from the template with `core/post-content`. See [Cart and Checkout page templates](/docs/theming/block-theme-development/theming-woo-blocks#cart-and-checkout-page-templates) for the recommended template structure.

## Buttons

WC Blocks introduces the button component, it differs from a generic `button` in that it has some default styles to make it correctly fit in the Blocks design.

![Button screenshot](https://user-images.githubusercontent.com/3616980/86381945-e6fd6c00-bc8d-11ea-8811-7e546bea69b9.png)

Themes can still style them to match theme colors or styles as follows:

```css
.wc-block-components-button {
	background-color: #d5502f;
	color: #fff;
	/* More rules can be added to modify the border, shadow, etc. */
}
/* It might be needed to modify the hover, focus, active and disabled states too */
```

... (55 lines truncated)
</file>

<file path="docs/theming/block-theme-development/css-styling.md">
---
post_title: CSS styling for themes
sidebar_label: CSS styling for themes
---

# CSS styling for themes

## Block and component class names

> [!IMPORTANT]
> We strongly discourage writing CSS code based on existing block class names and prioritize using global styles when possible. We especially discourage writing CSS selectors that rely on a specific block being a descendant of another one, as users can move blocks around freely, so they are prone to breaking. Similar to WordPress itself, we consider the HTML structure within components, blocks, and block templates to be "private", and subject to further change in the future, so using CSS to target the internals of a block or a block template is _not recommended or supported_.

WooCommerce Blocks follows BEM for class names, as [stated in our coding guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/docs/contributors/coding-guidelines.md). All classes start with one of these two prefixes:

-   `.wc-block-`: class names specific to a single block.
-   `.wc-block-components-`: class names specific to a component. The component might be reused by different blocks.

The combination of block class names and component class names allows themes to style each component either globally or only in specific blocks. As an example, you could style all prices to be italics with:

```css
/* This will apply to all block prices */
.wc-block-components-formatted-money-amount {
	font-style: italic;
}
```

But if you only wanted to make it italic in the Checkout block, that could be done adding the block selector:

```css
/* This will apply to prices in the checkout block */
... (82 lines truncated)
</file>

<file path="docs/theming/block-theme-development/theming-woo-blocks.md">
---
post_title: Theming for Woo blocks
sidebar_label: Theming for Woo blocks

---

# Theming for Woo blocks

---

**Note:** We're assuming you have some previous knowledge about block theme development and some WordPress concepts. If you are completely new to block theme development, please check [Develop Your First Low-Code Block Theme](https://learn.wordpress.org/course/develop-your-first-low-code-block-theme/)
to learn about block theme development, and explore
the [Create Block Theme plugin](https://wordpress.org/plugins/create-block-theme/) tool when you're ready to create a new theme.

---

## General concepts

### Block templates

WooCommerce comes with several [block templates](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/templates/templates/blockified) by default. Those are:

- Single Product (`single-product.html`)
- Product Catalog (`archive-product.html`)
    - Products by Category (`taxonomy-product_cat.html`)
    - Products by Tag (`taxonomy-product_tag.html`)
    - Products by Attribute (`taxonomy-product_attribute.html`)
- Product Search Results (`product-search-results.html`)
- Page: Coming soon (`page-coming-soon.html`)
- Page: Cart (`page-cart.html`)
... (91 lines truncated)
</file>

<file path="docs/theming/theme-development/_category_.json">
{
    "position": 2,
    "label": "Classic theme development",
    "link": {
      "type": "doc",
      "id": "classic-theme-developer-handbook"
    }
}
</file>

<file path="docs/theming/theme-development/classic-theme-developer-handbook.md">
---
post_title: Classic theme development handbook
sidebar_label: Classic theme development
---

# Classic theme development handbook

---

**Note:** this document is geared toward the development of classic themes. Check this other document for [block theme development](../block-theme-development/theming-woo-blocks.md).

---

WooCommerce looks great with all WordPress themes as of version 3.3, even if they are not WooCommerce-specific themes and do not formally declare support. Templates render inside the content, and this keeps everything looking natural on your site.

Non-WooCommerce themes, by default, also include:

- Zoom feature enabled - ability to zoom in/out on a product image
- Lightbox feature enabled - product gallery images pop up to examine closer
- Comments enabled, not Reviews - visitors/buyers can leave comments as opposed to product ratings or reviews

If you want more control over the layout of WooCommerce elements or full reviews support your theme will need to integrate with WooCommerce. There are a few different ways you can do this, and they are outlined below.

## Theme Integration

There are three possible ways to integrate WooCommerce with a theme. If you are using WooCommerce 3.2 or below (**strongly discouraged**) you will need to use one of these methods to ensure WooCommerce shop and product pages are rendered correctly in your theme. If you are using a version of WooCommerce 3.3 or above you only need to do a theme integration if the automatic one doesn't meet your needs.

### Using `woocommerce_content()`

This solution allows you to create a new template page within your theme that is used for **all WooCommerce taxonomy and post type displays**. While an easy catch-all solution, it does have a drawback in that this template is used for **all WooCommerce taxonomies** (product categories, etc.) and **post types** (product archives, single product pages). Developers are encouraged to use the hooks instead (see below).
... (197 lines truncated)
</file>

<file path="docs/theming/theme-development/conditional-tags.md">
---
post_title: Conditional tags in WooCommerce
sidebar_label: Conditional tags

---

# Conditional tags in WooCommerce

## What are "conditional tags"?

The conditional tags of WooCommerce and WordPress can be used in your template files to change what content is displayed based on what *conditions* the page matches. For example, you may want to display a snippet of text above the shop page. With the `is_shop()` conditional tag, you can.

Because WooCommerce uses custom post types, you can also use many of WordPress' conditional tags. See [codex.wordpress.org/Conditional_Tags](https://codex.wordpress.org/Conditional_Tags) for a list of the tags included with WordPress.

**Note**: You can only use conditional query tags after the `posts_selection` [action hook](https://codex.wordpress.org/Plugin_API/Action_Reference#Actions_Run_During_a_Typical_Request) in WordPress (the `wp` action hook is the first one through which you can use these conditionals). For themes, this means the conditional tag will never work properly if you are using it in the body of functions.php. If a conditional tag is used before it's supposed to, it won't trigger any error or warning: it will simply return `false`, even if the condition it checks for would be met later in the request.

## Available conditional tags

All conditional tags test whether a condition is met, and then return either `TRUE` or `FALSE`. **Conditions under which tags output `TRUE` are listed below the conditional tags**.

The list below holds the main conditional tags. To see all conditional tags, visit the [WooCommerce API Docs](https://woocommerce.com/wc-apidocs/).

### WooCommerce page

- `is_woocommerce()`  
  Returns true if on a page which uses WooCommerce templates (cart and checkout are standard pages with shortcodes and thus are not included).

### Main shop page

- `is_shop()`  
... (71 lines truncated)
</file>

<file path="docs/theming/theme-development/fixing-outdated-woocommerce-templates.md">
---
post_title: How to fix outdated WooCommerce templates
sidebar_label: Fix outdated templates

---

# How to fix outdated WooCommerce templates

## Template Updates and Changes

We sometimes update the default templates when a new version of WooCommerce is released. This applies to major releases (WooCommerce 2.6, 3.0, and 4.0) but also to minor releases (WooCommerce 3.8.0).

Starting in WooCommerce version 3.3, most themes look great with WooCommerce. 

[Our developer-focused blog](https://developer.woocommerce.com/blog/) will list any template file changes with each release. You may need to update templates yourself or contact the theme author for an update if:

- you are using a theme with older templates or an older version of WooCommerce, or
- you modified templates or are using a child theme.

Most theme authors fix themes in a timely manner, so you only need to update your theme to get the updated templates.

Alternatively, you can select and use a different theme that already uses current WooCommerce templates.

## How to Update Outdated Templates

You need to determine what templates to update, make a backup of the old templates, and then restore any customizations.

1. Go to WooCommerce > Status > System Status. Scroll to the end of the page where there is a list of templates overridden by your theme/child theme and a warning message that they need to be updated.
2. Save a backup of the outdated template.
3. Copy the default template from `wp-content/plugins/woocommerce/templates/[path-to-the-template]` and paste it in your theme folder found at `wp-content/themes/[path-to-theme]`.
... (19 lines truncated)
</file>

<file path="docs/theming/theme-development/image-sizes.md">
---
post_title: Image sizing for theme developers
sidebar_label: Image sizing

---

# Image sizing for theme developers

**Note:** this document was created for use when developing classic themes (as opposed to block themes). Check this other document for [block theme development](../block-theme-development/theming-woo-blocks.md).

To display images in your catalog, WooCommerce registers a few image sizes which define the actual image dimensions to be used. These sizes include:

- `woocommerce_thumbnail` - used in the product 'grids' in places such as the shop page.
- `woocommerce_single` - used on single product pages.
- `woocommerce_gallery_thumbnail` - used below the main image on the single product page to switch the gallery.

`woocommerce_single` shows the full product image, as uploaded, so is always uncropped by default. It defaults to 600px width. `woocommerce_gallery_thumbnail` is always square cropped and defaults to 100x100 pixels. This is used for navigating images in the gallery. `woocommerce_thumbnail` defaults to 300px width, square cropped so the product grids look neat. The aspect ratio for cropping can be customized by the store owner. It is important to note that despite the actual image widths that are set, themes can ultimately change the size images are displayed using CSS, and image widths may be limited by the product grid/column widths.

## Themes can define image sizes

Starting with WooCommerce 3.3.0, themes can declare what sizes should be used when declaring WooCommerce support. If a theme defines the image sizes (widths), the store owner will not be able to change them, but the size defined should be optimal for the theme.

```php
add_theme_support( 'woocommerce', array(
    'thumbnail_image_width' => 200,
    'gallery_thumbnail_image_width' => 100,
    'single_image_width' => 500,
) );
```

... (66 lines truncated)
</file>

<file path="docs/theming/theme-development/set-up-a-child-theme.md">
---
post_title: How to set up and use a child theme
sidebar_label: Set up and use a child theme

---

# How to set up and use a child theme

**Note:** This document is intended for creating and using classic child themes. For a comprehensive guide on creating a child block theme and understanding the differences between a classic and block theme, please refer to [WooCommerce block theme development](../block-theme-development/theming-woo-blocks.md) and [WordPress block child theme development](https://learn.wordpress.org/lesson-plan/create-a-basic-child-theme-for-block-themes/).


Sometimes, you might need to customize your theme or WooCommerce beyond what is possible via the options. These guidelines will teach you the basics of how to go about customizing your site by using a child theme.

## What is a child theme?

Before we start it's important that you understand what a child theme is. In short, a child theme is a layer that you put on top of the parent theme to make alterations without having to develop a new theme from scratch. There are two major reasons to use child themes:

- Theme developers can use child themes as a way to offer variations on a theme, similar to what we do with the [Storefront child themes](https://woocommerce.com/products/storefront/)
- Developers can use child themes to host customizations of the parent theme or any plugin on the site since the child theme will get priority over the plugins and parent theme

Read [this guide from the WordPress Codex](https://developer.wordpress.org/themes/advanced-topics/child-themes/).

## Make a backup

Before customizing a website, you should always ensure that you have a backup of your site in case anything goes wrong. More info at: [Backing up WordPress content](https://woocommerce.com/document/backup-wordpress-content/).

## Getting started

To get started, we need to prepare a child theme.

... (97 lines truncated)
</file>

<file path="docs/theming/theme-development/template-structure.md">
---
post_title: Template structure & Overriding templates via a theme
---

# Template structure & Overriding templates via a theme

---

**NOTE** This document makes reference to classic themes which use PHP templates. If you are working on a block theme with HTML templates, [please check the Theming docs for block themes](../block-theme-development/theming-woo-blocks.md).
Overview

---

## Overview

WooCommerce template files contain the markup and template structure for the frontend and HTML emails of your store.

## Template list

The various template files on your WooCommerce site can be found via an FTP client or your hosts file manager, in `/wp-content/plugins/woocommerce/templates/`. Alternatively, you can find the [template files on our repository on GitHub](https://github.com/woocommerce/woocommerce/blob/trunk/docs/theme-development/template-structure.md).

Note: if you are looking for the template files of older versions, you can find them in these paths:

-   Versions 6.0.0 and later: `https://github.com/woocommerce/woocommerce/tree/[VERSION_NUMBER]/plugins/woocommerce/templates`
    -   For example, to find the template files for WooCommerce 9.4.0, you would navigate to [https://github.com/woocommerce/woocommerce/tree/9.4.0/plugins/woocommerce/templates](https://github.com/woocommerce/woocommerce/tree/9.4.0/plugins/woocommerce/templates).
-   Versions prior to 6.0.0: `https://github.com/woocommerce/woocommerce/tree/[VERSION_NUMBER]/templates`
    -   For example, to find the template files for WooCommerce 5.9.0, you would navigate to [https://github.com/woocommerce/woocommerce/tree/5.9.0/templates](https://github.com/woocommerce/woocommerce/tree/5.9.0/templates).

## Changing Templates via Hooks

... (56 lines truncated)
</file>

<file path="docs/theming/theme-development/theme-design-ux-guidelines.md">
---
post_title: Theme design and user experience guidelines
sidebar_label: Theme design and user experience guidelines

---

# Theme design and user experience guidelines

This guide covers general guidelines and best practices to follow in order to ensure your theme experience aligns with ecommerce industry standards and WooCommerce for providing a great online shopping experience, maximizing sales, ensuring ease of use, seamless integration, and strong UX adoption.

We recommend you review the [UI best practices for WordPress](https://developer.wordpress.org/themes/advanced-topics/ui-best-practices/) to ensure your theme is aligned with the WordPress theme requirements.

Make sure your theme fits one or more industries currently available in the [WooCommerce themes store](https://woocommerce.com/product-category/themes). It's important that the theme offers enough originality and distinctiveness in its design, while keeping it familiar, in order to be distinguished from other themes on the WooCommerce theme store. Your theme should avoid copying existing themes on the WooCommerce theme store or other WordPress theme marketplaces.

## Design


High-quality design is an important aspect of an online store, and that is driven by the theme design and content. The design of the theme should be simple, consistent, uncluttered, memorable, intuitive, efficient, and functional. When designing a new theme for WooCommerce special attention should be given to:

### Layout

The theme should be up to industry standards in terms of hierarchy, flow, content balance, and white space.

Theme authors must ensure that store pages (shop, product page, categories, cart, checkout, profile page, etc) fit seamlessly with the theme since they are the central point of a WooCommerce theme.

The Theme is expected to be fully functional and optimized to be accessed on common device types such as laptops, tablets, and smartphones.

### Typography

The theme should provide elegant and legible font pairings that promote a comfortable reading experience.
... (62 lines truncated)
</file>

<file path="docs/theming/theme-development/thumbnail-image-regeneration.md">
---
post_title: Thumbnail image regeneration

---

# Thumbnail image regeneration

WooCommerce 3.3 introduced thumbnail regeneration functionality. In the past when image size settings were changed you would need to install an external plugin and then have it regenerate all WordPress image thumbnails before the changes would be visible.

The new image regeneration functionality, combined with the introduction of WooCommerce image settings in the customizer, now ensure that as you make changes to your store image settings you can preview the changes in real-time within the customizer.

## How it works

When you make changes to image sizes/aspect ratios in the customiser, or if your theme changes image sizes, WC will detect these changes and queue a background regeneration job. The 2 events which can trigger this are:

- Publishing settings in the customizer
- Switching themes

Whilst in the customizer, size changes can be previewed due to our on-the-fly image regen. These changes will not be persisted to the live site until you hit publish.

### Background jobs and BasicAuth

If your site is behind BasicAuth, both async requests and background processes will fail to complete. This is because WP Background Processing relies on the WordPress HTTP API, which requires you to attach your BasicAuth credentials to requests.

You can pass these credentials via a snippet, see:[BasicAuth documentation](https://github.com/A5hleyRich/wp-background-processing#basicauth).

### Viewing background regeneration logs

To view the logs for background image regeneration go to `WooCommerce > Status > Logs` and select the `wc-background-regeneration` log from the dropdown.

... (32 lines truncated)
</file>

<file path="docs/theming/theme-development/using-custom-attributes-in-menus.md">
---
post_title: Managing custom attributes in WooCommerce menus and taxonomy archives
sidebar_label: Custom attributes in menus
---

# Managing custom attributes in WooCommerce menus and taxonomy archives

Attributes that can be used for the layered nav are a custom taxonomy, which means you can display them in menus, or display products by attributes. This requires some work on your part, and archives must be enabled.

## Register the taxonomy for menus

When registering taxonomies for your custom attributes, WooCommerce calls the following hook:

```php
$show_in_nav_menus = apply_filters('woocommerce_attribute_show_in_nav_menus', false, $name);
```

So, for example, if your attribute slug was `size` you would do the following to register it for menus:

```php
add_filter('woocommerce_attribute_show_in_nav_menus', 'wc_reg_for_menus', 1, 2);

function wc_reg_for_menus( $register, $name = '' ) {
if ( $name == 'pa_size' ) $register = true;
return $register;
}
```

Custom attribute slugs are prefixed with `pa_`, so an attribute called `size` would be `pa_size`

... (11 lines truncated)
</file>

<file path="docs/theming/_category_.json">
{
    "position": 3,
    "label": "Theming"
}
</file>

<file path="docs/theming/theme-design.md">
---
sidebar_label: UX guidelines
sidebar_position: 3
category_slug: user-experience-themes
post_title: Theme design guidelines
---

# Theme design guidelines

This page covers general guidelines and best practices to follow so your theme experience aligns with ecommerce industry standards and WooCommerce. A strong theme design should support a great online shopping experience, maximize sales, remain easy to use, integrate cleanly, and encourage strong UX adoption.

We recommend you review the [UI best practices for WordPress](https://developer.wordpress.org/themes/advanced-topics/ui-best-practices/) to ensure your theme is aligned with the WordPress theme requirements.

Make sure your theme fits one or more industries currently available in the [WooCommerce themes store](https://woocommerce.com/product-category/themes). The theme should offer enough originality and distinctiveness in its design, while keeping it familiar, to be distinguished from other themes on the WooCommerce theme store. Your theme should avoid copying existing themes on the WooCommerce theme store or other WordPress theme marketplaces.

## Design

High-quality design is an important aspect of an online store, and that is driven by the theme design and content. The design of the theme should be simple, consistent, uncluttered, memorable, intuitive, efficient, and functional. When designing a new theme for WooCommerce, pay special attention to the following areas.

### Layout

The theme should be up to industry standards in terms of hierarchy, flow, content balance, and white space.

Theme authors must ensure that store pages, such as shop, product page, categories, cart, checkout, and profile pages, fit seamlessly with the theme since they are the central point of a WooCommerce theme.

The theme is expected to be fully functional and optimized for common device types such as laptops, tablets, and smartphones.

### Typography

The theme should provide elegant and legible font pairings that promote a comfortable reading experience.
... (64 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/_category_.json">
{
    "label": "Commands",
    "position": 4,
    "collapsible": true,
    "collapsed": true,
    "link": {
        "type": "doc",
        "id": "README"
    }
}
</file>

<file path="docs/wc-cli/wc-cli-commands/README.md">
---
post_title: WooCommerce CLI commands
sidebar_label: Commands
sidebar_position: 4
---

# WooCommerce CLI Commands

## Overview

This document serves as a comprehensive reference for the WooCommerce Command Line Interface (WC-CLI) commands. It includes syntax, options, and brief descriptions for each command. These commands are applicable for WooCommerce version 3.0.0 and later.

## General Command Structure

The general syntax for WC-CLI commands is:

```bash
wp wc [command] [options]
```

For detailed help on any specific command, use:

```bash
wp wc [command] --help
```

## Commands

| Command | Description |
| --- | --- |
... (31 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-blueprint.md">
---
title: wc blueprint
sidebar_label: wc blueprint
---

Imports and exports WooCommerce Blueprints.

## wc blueprint import `<schema-path>`

Import a WooCommerce Blueprint schema file.

- `--show-messages` - Show debug messages. Supported log levels: all, error, info, debug.

## wc blueprint export `<save-to-filename>`

Export a WooCommerce Blueprint schema file.

- `--steps` - name of steps to export.
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-com.md">
---
title: wc com
sidebar_label: wc com
---

Interacts with extensions from the WooCommerce.com marketplace via CLI.

## wc com connect

Connect the store to WooCommerce.com with an application password.

- `--password` - WooCommerce.com application password. If omitted, the command prompts for it.
- `--force` - Disconnect the site first and force a new connection if the site is already connected.

## wc com disconnect

Disconnect the store from WooCommerce.com.

- `--yes` - Do not prompt for confirmation.

## wc com extension list

List extensions owned by the connected site.

- `--format` - Render output in a particular format.

    Default: table

    Options: table, csv, json, yaml

... (15 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-customer-download.md">
---
title: wc customer_download
sidebar_label: wc customer_download
---

Manage WooCommerce customer download resources.

## wc customer_download list `<customer_id>`

List all customer downloads.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-customer.md">
---
title: wc customer
sidebar_label: wc customer
---

Manage WooCommerce customer resources.

## wc customer list

List all customers.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--page` - Current page of the collection.
- `--per_page` - Maximum number of items to be returned in result set. Defaults to 100 items.
- `--search` - Limit results to those matching a string.
- `--exclude` - Ensure result set excludes specific IDs.
- `--include` - Limit result set to specific IDs.
- `--offset` - Offset the result set by a specific number of items.
- `--order` - Order sort attribute ascending or descending.
- `--orderby` - Sort collection by object attribute.
- `--email` - Limit result set to resources with a specific email.
- `--role` - Limit result set to resources with a specific role.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope

... (49 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-hpos.md">
---
title: wc hpos
sidebar_label: wc hpos
---

Commands for managing High-Performance Order Storage (HPOS). For detailed examples, see [HPOS CLI tools](/docs/features/orders/high-performance-order-storage/cli-tools/).

The older `wc cot` namespace is deprecated. Use `wc hpos` instead of the remaining deprecated aliases: `wc cot count_unmigrated`, `wc cot sync`, `wc cot verify_cot_data`, `wc cot enable`, and `wc cot disable`. The `wc cot migrate` command is fully deprecated and no longer works.

## wc hpos status

Displays a summary of HPOS settings and sync status for the site.

## wc hpos enable

Set custom order tables as the authoritative order datastore after running compatibility and sync checks.

- `--for-new-shop` - Enable HPOS only if this is a new shop, regardless of whether tables are in sync.
- `--with-sync` - Also enable compatibility mode, which keeps the HPOS and posts datastores in sync.
- `--ignore-plugin-compatibility` - Enable HPOS even if active plugins are incompatible with HPOS.

## wc hpos disable

Set the posts datastore as authoritative after confirming HPOS and posts tables are in sync.

- `--with-sync` - Also disable compatibility mode, which stops keeping the HPOS and posts datastores in sync.

## wc hpos compatibility-info

Show WooCommerce-aware plugins known to be compatible, incompatible, or uncertain for HPOS.
... (69 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-order-note.md">
---
title: wc order_note
sidebar_label: wc order_note
---

Manage WooCommerce order note resources.

## wc order_note list `<order_id>`

List all order notes.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--type` - Limit result to customers or internal notes.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope

## wc order_note create `<order_id>`

Create a new order note.

- `--note` - Order note content. (*Required*)
- `--customer_note` - If true, the note will be shown to customers and they will be notified. If false, the note will be for admin reference only.
- `--porcelain` - Output just the id when the operation is successful.

## wc order_note get `<order_id>` `<id>`
... (19 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-palt.md">
---
title: wc palt
sidebar_label: wc palt
---

Commands for managing the product attributes lookup table. The table stores denormalized product attribute term data used to speed up catalog filtering.

## wc palt enable

Enable usage of the product attributes lookup table.

- `--force` - Skip confirmation when enabling table usage while regeneration is in progress, was aborted, or the lookup table is empty.

## wc palt disable

Disables usage of the product attributes lookup table.

## wc palt info

Displays information about the product attributes lookup table.

## wc palt regenerate_for_product `<product_id>`

Regenerate product attributes lookup table data for one product.

- `--disable-db-optimization` - Do not use optimized database access even if products are stored as custom post types.

## wc palt abort_regeneration

Abort background regeneration of the product attributes lookup table.
... (28 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-payment-gateway.md">
---
title: wc payment_gateway
sidebar_label: wc payment_gateway
---

Manage WooCommerce payment gateway resources.

## wc payment_gateway list

List all payment gateways.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope

## wc payment_gateway get `<id>`

Get a single payment gateway.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table
... (14 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-product-attribute-term.md">
---
title: wc product_attribute_term
sidebar_label: wc product_attribute_term
---

Manage WooCommerce product attribute term resources.

## wc product_attribute_term list `<attribute_id>`

List all product attribute terms.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--page` - Current page of the collection.
- `--per_page` - Maximum number of items to be returned in result set. Defaults to 100 items.
- `--search` - Limit results to those matching a string.
- `--exclude` - Ensure result set excludes specific ids.
- `--include` - Limit result set to specific ids.
- `--order` - Order sort attribute ascending or descending.
- `--orderby` - Sort collection by resource attribute.
- `--hide_empty` - Whether to hide resources not assigned to any products.
- `--parent` - Limit result set to resources assigned to a specific parent.
- `--product` - Limit result set to resources assigned to a specific product.
- `--slug` - Limit result set to resources with a specific slug.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope
... (41 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-product-attribute.md">
---
title: wc product_attribute
sidebar_label: wc product_attribute
---

Manage WooCommerce product attribute resources.

## wc product_attribute list

List all product attributes.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope

## wc product_attribute create

Create a new product attribute.

- `--name` - Name for the resource. (*Required*)
- `--slug` - An alphanumeric identifier for the resource unique to its type.
- `--type` - Type of attribute.
- `--order_by` - Default sort order.
- `--has_archives` - Enable/Disable attribute archives.
- `--porcelain` - Output just the id when the operation is successful.
... (32 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-product-cat.md">
---
title: wc product_cat
sidebar_label: wc product_cat
---

Manage WooCommerce product category resources.

## wc product_cat list

List all product categories.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--page` - Current page of the collection.
- `--per_page` - Maximum number of items to be returned in result set. Defaults to 100 items.
- `--search` - Limit results to those matching a string.
- `--exclude` - Ensure result set excludes specific ids.
- `--include` - Limit result set to specific ids.
- `--order` - Order sort attribute ascending or descending.
- `--orderby` - Sort collection by resource attribute.
- `--hide_empty` - Whether to hide resources not assigned to any products.
- `--parent` - Limit result set to resources assigned to a specific parent.
- `--product` - Limit result set to resources assigned to a specific product.
- `--slug` - Limit result set to resources with a specific slug.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope
... (47 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-product-review.md">
---
title: wc product_review
sidebar_label: wc product_review
---

Manage WooCommerce product review resources.

## wc product_review list `<product_id>`

List all product reviews.

- `--id` - Unique identifier for the review.
- `--context` - Scope under which the request is made; determines fields present in response.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope

## wc product_review create `<product_id>`

Create a new product review.

- `--id` - Unique identifier for the review.
- `--review` - Review content. (*Required*)
- `--date_created` - The date the review was created, in the site's timezone.
- `--date_created_gmt` - The date the review was created, as GMT.
- `--rating` - Review rating (0 to 5).
... (36 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-product-shipping-class.md">
---
title: wc product_shipping_class
sidebar_label: wc product_shipping_class
---

Manage WooCommerce product shipping class resources.

## wc product_shipping_class list

List all product shipping classes.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--page` - Current page of the collection.
- `--per_page` - Maximum number of items to be returned in result set. Defaults to 100 items.
- `--search` - Limit results to those matching a string.
- `--exclude` - Ensure result set excludes specific ids.
- `--include` - Limit result set to specific ids.
- `--offset` - Offset the result set by a specific number of items.
- `--order` - Order sort attribute ascending or descending.
- `--orderby` - Sort collection by resource attribute.
- `--hide_empty` - Whether to hide resources not assigned to any products.
- `--product` - Limit result set to resources assigned to a specific product.
- `--slug` - Limit result set to resources with a specific slug.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope
... (39 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-product-tag.md">
---
title: wc product_tag
sidebar_label: wc product_tag
---

Manage WooCommerce product tag resources.

## wc product_tag list

List all product tags.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--page` - Current page of the collection.
- `--per_page` - Maximum number of items to be returned in result set. Defaults to 100 items.
- `--search` - Limit results to those matching a string.
- `--exclude` - Ensure result set excludes specific ids.
- `--include` - Limit result set to specific ids.
- `--offset` - Offset the result set by a specific number of items.
- `--order` - Order sort attribute ascending or descending.
- `--orderby` - Sort collection by resource attribute.
- `--hide_empty` - Whether to hide resources not assigned to any products.
- `--product` - Limit result set to resources assigned to a specific product.
- `--slug` - Limit result set to resources with a specific slug.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope
... (39 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-product-variation.md">
---
title: wc product_variation
sidebar_label: wc product_variation
---

Manage WooCommerce product variation resources.

## wc product_variation list `<product_id>`

List all product variations.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--page` - Current page of the collection.
- `--per_page` - Maximum number of items to be returned in result set. Defaults to 100 items.
- `--search` - Limit results to those matching a string.
- `--after` - Limit response to resources published after a given ISO8601 compliant date.
- `--before` - Limit response to resources published before a given ISO8601 compliant date.
- `--exclude` - Ensure result set excludes specific IDs.
- `--include` - Limit result set to specific ids.
- `--offset` - Offset the result set by a specific number of items.
- `--order` - Order sort attribute ascending or descending.
- `--orderby` - Sort collection by object attribute.
- `--parent` - Limit result set to those of particular parent IDs.
- `--parent_exclude` - Limit result set to all items except those of a particular parent ID.
- `--slug` - Limit result set to products with a specific slug.
- `--status` - Limit result set to products assigned a specific status.
- `--type` - Limit result set to products assigned a specific type.
- `--sku` - Limit result set to products with a specific SKU.
- `--featured` - Limit result set to featured products.
- `--category` - Limit result set to products assigned a specific category ID.
... (103 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-product.md">
---
title: wc product
sidebar_label: wc product
---

Manage WooCommerce product resources.

## wc product list

List all products.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--page` - Current page of the collection.
- `--per_page` - Maximum number of items to be returned in result set. Defaults to 100 items.
- `--search` - Limit results to those matching a string.
- `--after` - Limit response to resources published after a given ISO8601 compliant date.
- `--before` - Limit response to resources published before a given ISO8601 compliant date.
- `--exclude` - Ensure result set excludes specific IDs.
- `--include` - Limit result set to specific ids.
- `--offset` - Offset the result set by a specific number of items.
- `--order` - Order sort attribute ascending or descending.
- `--orderby` - Sort collection by object attribute.
- `--parent` - Limit result set to those of particular parent IDs.
- `--parent_exclude` - Limit result set to all items except those of a particular parent ID.
- `--slug` - Limit result set to products with a specific slug.
- `--status` - Limit result set to products assigned a specific status.
- `--type` - Limit result set to products assigned a specific type.
- `--sku` - Limit result set to products with a specific SKU.
- `--featured` - Limit result set to featured products.
- `--category` - Limit result set to products assigned a specific category ID.
... (137 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-setting.md">
---
title: wc setting
sidebar_label: wc setting
---

Manage WooCommerce setting resources.

## wc setting get `<id>`

Get a single setting.

- `--group` - Settings group ID.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, yaml, headers, body, envelope

## wc setting update `<id>`

Update an existing setting.

- `--group` - Settings group ID.
- `--value` - Setting value.
- `--porcelain` - Output just the id when the operation is successful.
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-shipping-method.md">
---
title: wc shipping_method
sidebar_label: wc shipping_method
---

Manage WooCommerce shipping method resources.

## wc shipping_method list

List all shipping methods.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope

## wc shipping_method get `<id>`

Get a single shipping method.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table
... (3 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-shipping-zone-location.md">
---
title: wc shipping_zone_location
sidebar_label: wc shipping_zone_location
---

Manage WooCommerce shipping zone location resources.

## wc shipping_zone_location list `<id>`

List all shipping zone locations.

- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-shipping-zone-method.md">
---
title: wc shipping_zone_method
sidebar_label: wc shipping_zone_method
---

Manage WooCommerce shipping zone method resources.

## wc shipping_zone_method list `<zone_id>`

List all shipping zone methods.

- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope

## wc shipping_zone_method create `<zone_id>`

Create a new shipping zone method.

- `--order` - Shipping method sort order.
- `--enabled` - Shipping method enabled status.
- `--settings` - Shipping method settings.
- `--method_id` - Shipping method ID. (*Required*)
- `--porcelain` - Output just the id when the operation is successful.

## wc shipping_zone_method get `<zone_id>` `<instance_id>`
... (27 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-shipping-zone.md">
---
title: wc shipping_zone
sidebar_label: wc shipping_zone
---

Manage WooCommerce shipping zone resources.

## wc shipping_zone list

List all shipping zones.

- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope

## wc shipping_zone create

Create a new shipping zone.

- `--name` - Shipping zone name. (*Required*)
- `--order` - Shipping zone order.
- `--porcelain` - Output just the id when the operation is successful.

## wc shipping_zone get `<id>`

Get a single shipping zone.
... (24 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-shop-coupon.md">
---
title: wc shop_coupon
sidebar_label: wc shop_coupon
---

Manage WooCommerce shop coupon resources.

## wc shop_coupon list

List all shop coupons.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--page` - Current page of the collection.
- `--per_page` - Maximum number of items to be returned in result set. Defaults to 100 items.
- `--search` - Limit results to those matching a string.
- `--after` - Limit response to resources published after a given ISO8601 compliant date.
- `--before` - Limit response to resources published before a given ISO8601 compliant date.
- `--exclude` - Ensure result set excludes specific IDs.
- `--include` - Limit result set to specific ids.
- `--offset` - Offset the result set by a specific number of items.
- `--order` - Order sort attribute ascending or descending.
- `--orderby` - Sort collection by object attribute.
- `--code` - Limit result set to resources with a specific code.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope
... (73 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-shop-order-refund.md">
---
title: wc shop_order_refund
sidebar_label: wc shop_order_refund
---

Manage WooCommerce shop order refund resources.

## wc shop_order_refund list `<order_id>`

List all shop order refunds.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--page` - Current page of the collection.
- `--per_page` - Maximum number of items to be returned in result set. Defaults to 100 items.
- `--search` - Limit results to those matching a string.
- `--after` - Limit response to resources published after a given ISO8601 compliant date.
- `--before` - Limit response to resources published before a given ISO8601 compliant date.
- `--exclude` - Ensure result set excludes specific IDs.
- `--include` - Limit result set to specific ids.
- `--offset` - Offset the result set by a specific number of items.
- `--order` - Order sort attribute ascending or descending.
- `--orderby` - Sort collection by object attribute.
- `--parent` - Limit result set to those of particular parent IDs.
- `--parent_exclude` - Limit result set to all items except those of a particular parent ID.
- `--dp` - Number of decimal points to use in each resource.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table
... (35 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-shop-order.md">
---
title: wc shop_order
sidebar_label: wc shop_order
---

Manage WooCommerce shop order resources.

## wc shop_order list

List all shop orders.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--page` - Current page of the collection.
- `--per_page` - Maximum number of items to be returned in result set. Defaults to 100 items.
- `--search` - Limit results to those matching a string.
- `--after` - Limit response to resources published after a given ISO8601 compliant date.
- `--before` - Limit response to resources published before a given ISO8601 compliant date.
- `--exclude` - Ensure result set excludes specific IDs.
- `--include` - Limit result set to specific ids.
- `--offset` - Offset the result set by a specific number of items.
- `--order` - Order sort attribute ascending or descending.
- `--orderby` - Sort collection by object attribute.
- `--parent` - Limit result set to those of particular parent IDs.
- `--parent_exclude` - Limit result set to all items except those of a particular parent ID.
- `--status` - Limit result set to orders assigned a specific status.
- `--customer` - Limit result set to orders assigned a specific customer.
- `--product` - Limit result set to orders assigned a specific product.
- `--dp` - Number of decimal points to use in each resource.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
... (70 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-tax-class.md">
---
title: wc tax_class
sidebar_label: wc tax_class
---

Manage WooCommerce tax class resources.

## wc tax_class list

List all tax classes.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope

## wc tax_class create

Create a new tax class.

- `--name` - Tax class name. (*Required*)
- `--porcelain` - Output just the id when the operation is successful.

## wc tax_class delete `<slug>`

Delete an existing tax class.
... (4 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-tax.md">
---
title: wc tax
sidebar_label: wc tax
---

Manage WooCommerce tax resources.

## wc tax list

List all taxes.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--page` - Current page of the collection.
- `--per_page` - Maximum number of items to be returned in result set. Defaults to 100 items.
- `--search` - Limit results to those matching a string.
- `--exclude` - Ensure result set excludes specific IDs.
- `--include` - Limit result set to specific IDs.
- `--offset` - Offset the result set by a specific number of items.
- `--order` - Order sort attribute ascending or descending.
- `--orderby` - Sort collection by object attribute.
- `--class` - Sort by tax class.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope

## wc tax create
... (53 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-tool.md">
---
title: wc tool
sidebar_label: wc tool
---

Runs WooCommerce system status tools from the CLI.

## wc tool list

List all system status tools.

- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope

## wc tool run `<id>`

Run a system status tool.
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-update.md">
---
title: wc update
sidebar_label: wc update
---

Runs all pending WooCommerce database updates.
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-webhook-delivery.md">
---
title: wc webhook_delivery
sidebar_label: wc webhook_delivery
---

Manage WooCommerce webhook delivery resources.

## wc webhook_delivery list `<webhook_id>`

List all webhook deliveries.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope

## wc webhook_delivery get `<webhook_id>` `<id>`

Get a single webhook delivery.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table
... (3 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-commands/wc-webhook.md">
---
title: wc webhook
sidebar_label: wc webhook
---

Manage WooCommerce webhook resources.

## wc webhook list

List all webhooks.

- `--context` - Scope under which the request is made; determines fields present in response.
- `--page` - Current page of the collection.
- `--per_page` - Maximum number of items to be returned in result set. Defaults to 100 items.
- `--search` - Limit results to those matching a string.
- `--after` - Limit response to resources published after a given ISO8601 compliant date.
- `--before` - Limit response to resources published before a given ISO8601 compliant date.
- `--exclude` - Ensure result set excludes specific IDs.
- `--include` - Limit result set to specific ids.
- `--offset` - Offset the result set by a specific number of items.
- `--order` - Order sort attribute ascending or descending.
- `--orderby` - Sort collection by object attribute.
- `--status` - Limit result set to webhooks assigned a specific status.
- `--fields` - Limit response to specific fields. Defaults to all fields.
- `--field` - Get the value of an individual field.
- `--format` - Render response in a particular format.

    Default: table

    Options: table, json, csv, ids, yaml, count, headers, body, envelope
... (42 lines truncated)
</file>

<file path="docs/wc-cli/_category_.json">
{
    "label": "CLI",
    "link": {
      "type": "generated-index",
      "title": "WC-CLI"
    },
    "customProps" : {
      "id" : "cli"
    }
}
</file>

<file path="docs/wc-cli/cli-faq.md">
---
post_title: WooCommerce CLI frequently asked questions
sidebar_label: Frequently asked questions
sidebar_position: 5

---

# WooCommerce CLI Frequently Asked Questions

## General Questions

### What is WooCommerce CLI?

- WooCommerce CLI (WC-CLI) is a command-line interface for managing WooCommerce settings and data. It provides a fast and efficient way to perform many tasks that would otherwise require manual work via the WordPress admin interface.

### How do I install WooCommerce CLI?

- WooCommerce CLI is included as part of WooCommerce from version 3.0.0 onwards. Ensure you have WooCommerce 3.0.0 or later installed, and you automatically have access to WC-CLI.

### Is WooCommerce CLI different from WP-CLI?

- WooCommerce CLI is a part of WP-CLI specifically designed for WooCommerce. While WP-CLI deals with general WordPress management, WC-CLI focuses on WooCommerce-specific tasks.

## Technical Questions

### How can I create a backup of my WooCommerce data?

- WC-CLI doesn't directly handle backups. However, you can use other WP-CLI commands to export WooCommerce data or rely on WordPress backup plugins.

### Can I update WooCommerce settings using the CLI?
... (37 lines truncated)
</file>

<file path="docs/wc-cli/cli-overview.md">
---
sidebar_label: WooCommerce CLI
category_slug: wc-cli
post_title: WooCommerce CLI Overview
sidebar_position: 1
---

# WooCommerce CLI Overview

## Introduction to WooCommerce CLI

WooCommerce CLI (WC-CLI) offers an efficient way to manage WooCommerce (WC) stores via the command line. This tool is a part of WC from version 3.0.0 onwards and leverages the capabilities of the WC REST API. This means that most tasks achievable through the REST API can also be performed via the command line.

For documentation on WC versions 2.5 and 2.6's CLI, visit [Legacy CLI commands](https://github.com/woocommerce/woocommerce/wiki/Legacy-CLI-commands-(v2.6-and-below)).

## About WP-CLI

WP-CLI is a powerful set of command-line tools for managing WordPress installations. You can update plugins, configure multisite installations, and much more, all without using a web browser. For more information, visit the [official WP-CLI website](http://wp-cli.org/).

## Getting Started with WooCommerce CLI

To begin using WC-CLI, ensure that you have WP-CLI installed and that you are running WooCommerce 3.0.0 or later. The CLI commands are accessed through the `wp wc` command. For a full list of available commands, type `wp wc` in your command-line interface.

For specific details on commands and their usage, refer to the [command reference](/docs/wc-cli/wc-cli-commands/). The [how-to guide](/docs/wc-cli/using-wc-cli/) provides a practical approach to common tasks, ideal for those new to WC-CLI or looking for quick solutions.

## Additional Resources

For those interested in exploring further, the following resources might be helpful:

- [WC REST API Documentation](https://developer.woocommerce.com/docs/category/rest-api/)
... (2 lines truncated)
</file>

<file path="docs/wc-cli/using-wc-cli.md">
---
post_title: How to use WooCommerce CLI
sidebar_label: Using WooCommerce CLI
sidebar_position: 2

---

# How to Use WooCommerce CLI

## Introduction

This guide aims to assist beginners in using WooCommerce CLI (WC-CLI) for managing WooCommerce stores via the command line.

## Getting Started

- Ensure WP-CLI is installed and WooCommerce is at least version 3.0.0.
- To check WC-CLI availability:

```bash
wp wc --info
```

### General Command Structure

The general syntax for WC-CLI commands is:

```bash
wp wc [command] [options]
```

... (42 lines truncated)
</file>

<file path="docs/wc-cli/wc-cli-examples.md">
---
post_title: WooCommerce CLI examples
sidebar_label: Examples
sidebar_position: 3

---

# WooCommerce CLI Examples

Full documentation for every command is available using `--help`. Below are some example commands to show what the CLI can do.

All the examples below use user ID 1 (usually an admin account), but you should replace that with your own user account.

You can also find other examples (without output) by looking at [the testing files for our CLI tests](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/tests/cli/features).

Each command will have a `.feature` file. For example, [these some payment gateway commands](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/tests/cli/features/payment_gateway.feature).

## Clearing the product/shop transients cache

Command: 

`$ wp wc tool run clear_transients --user=1`

Response:

`Success: Updated system_status_tool clear_transients.`

## Listing all system tools

Command: 
... (155 lines truncated)
</file>

<file path="docs/woo-marketplace/_category_.json">
{
    "label": "Woo Marketplace",
    "customProps" : {
      "id" : "woo-marketplace"
    },
    "link": {
      "type": "generated-index",
      "title": "Woo Marketplace",
      "description": "Documentation for developers publishing extensions, themes, and integrations on the Woo Marketplace."
    }
}
</file>

<file path="docs/woo-marketplace/billing-api-saas.mdx">
---
sidebar_position: 11
sidebar_label: 'Billing API for SaaS products'
---

# Billing API for SaaS products

## Introduction

Woo Marketplace's Billing API enables you to sell subscriptions for your SaaS app on the Woo Marketplace, via our in-house billing and subscription system. Woo Marketplace's Billing API supports recurring payments, free trials, upgrades, downgrades, and one-time payments.

Follow this guide to get your billing powered by WooCommerce's world-class billing system, and listed on the Woo Marketplace. You can integrate the Billing API with your existing sign-up and purchase flows, or create a different experience specifically for customers coming from WooCommerce.com.

[View API Documentation on Apiary](https://woocommercecomsaasbillingapi.docs.apiary.io/)

## Set up your SaaS App

To complete integrating WooCommerce Billing into your SaaS app, you'll need a sandbox and the API reference. The various API flows are described below.

To get started, please [submit your product](/docs/woo-marketplace/submitting-your-product/) to the WooCommerce Marketplace. Include details about your product and upload a zip file to test whether your product utilizes a WordPress plugin to connect to your app. We will review your product to determine if it is a good fit before granting sandbox access.

### Sandbox for testing

The integration with the SaaS Billing API should be implemented and tested inside the sandbox, before being opened up for production usage. The differences between production and sandbox are the domain (sandbox.woocommerce.com) and the API credentials. Switching from sandbox to production should just be a matter of changing the domain name, API key and secret.

**Sandbox domain:** `https://sandbox.woocommerce.com/`
**Base URL for API on the sandbox:** `https://sandbox.woocommerce.com/wp-json/wccom/billing/1.0/`

### Local Development

... (409 lines truncated)
</file>

<file path="docs/woo-marketplace/content-style-guide.md">
---
sidebar_position: 9
sidebar_label: 'Content Style Guide'
---

# Marketplace Content Style Guide

This guide provides formatting and writing standards for creating product pages and documentation on the WooCommerce Marketplace. Following these guidelines ensures consistency across the Marketplace and creates a professional experience for merchants browsing and purchasing extensions.

For product page structure, required elements, and asset specifications, refer to [Product Page Content and Assets](/docs/woo-marketplace/product-page-content-and-assets/).

## Writing Standards

### Product Naming Convention

Use the format "Product Name for WooCommerce" rather than "WooCommerce Product Name" throughout the product copy.

This format ensures your product name complies with [trademark rules](https://woocommerce.com/trademark-guidelines/) and leads with its unique identifier, improving discoverability and clarity.

### Grammar and Punctuation

Follow the [WooCommerce grammar, punctuation, and capitalization guide](/docs/best-practices/coding-standards/grammar-punctuation-capitalization/) for comprehensive guidance. Key points include:

**Use the Oxford comma** when listing three or more items:

- ✓ "Track orders, manage inventory, and process refunds."
- ✗ "Track orders, manage inventory and process refunds."

**Use active voice** instead of passive voice whenever possible:

... (192 lines truncated)
</file>

<file path="docs/woo-marketplace/excellence-verified-badge.md">
---
sidebar_position: 7
sidebar_label: 'Excellence Verified badge'
---

# Earning the Excellence Verified badge on the Woo Marketplace

The Woo Marketplace is a trusted source for merchants searching for high-quality extensions to add to their stores. That trust is what brings merchants in ready to buy, and it's what makes the Marketplace worth selling on. The Excellence Verified badge builds on it. It marks the products that reach the highest tier, checked for security, compatibility, maintenance, and merchant ratings.

This guide explains what the badge offers, how a product earns it, where vendors can check their current status, and how to close the gap.

## What the badge offers

Products that earn the Excellence Verified badge stand out across the Marketplace. The badge:

- Appears on the product page and on product cards in listings.
- Raises visibility in Discover, including a dedicated area for badged products.
- Includes the product when merchants filter to badged products only.

More benefits are on the way as the program grows, including promotional placements for badged products across more areas.

Products that don't earn the badge aren't penalized in any way. They keep their existing visibility and placement. The badge adds recognition for the products that reach the top tier.

## How to earn a badge

The badge is built on four factors, and a product needs to do well on all of them:

- **Secure**: scanned for vulnerabilities and malicious code.
- **Compatible**: installs and runs cleanly on current WordPress and WooCommerce.
- **Maintained**: kept up to date with recent releases.
... (83 lines truncated)
</file>

<file path="docs/woo-marketplace/getting-started.md">
---
sidebar_position: 1
---

# Getting started

We are excited to have you here! The WooCommerce.com Marketplace connects trusted developers and merchants worldwide to create powerful and flexible online stores.

## Why you should sell in the Woo Marketplace

- **Access to a global network** of WooCommerce merchants
- **Built-in brand recognition and trust** by listing your product in the official WooCommerce Marketplace
- **Revenue sharing** designed to support your business growth
- **Opportunities** to be featured in WooCommerce marketing campaigns
- **Insights and feedback** from a community of active merchants and developers

## Are you a good fit?

We are looking for products that:

- Solve real merchant problems
- Are secure, well-documented, and well-maintained
- Follow [security](https://developer.wordpress.org/apis/security/), [development](/docs/extensions/best-practices-extensions/extension-development-best-practices/), and [user experience](/docs/extensions/ux-guidelines-extensions/best-practices/) best practices
- Offer high-quality merchant support
- Include [a clear and sustainable monetization model](/docs/woo-marketplace/monetization-expectations/), whether through direct sales, subscriptions, or another approach

## The agreement

To join the WooCommerce Marketplace, vendors must offer high-quality, secure products, provide strong customer support, and follow WooCommerce's guidelines around listings, updates, pricing, and communication. The commercial terms are based on a revenue share model, with 70% of sales going to the vendor.

... (44 lines truncated)
</file>

<file path="docs/woo-marketplace/index.mdx">
---
title: Woo Marketplace
slug: /woo-marketplace
sidebar_position: 0
---

import DocCardList from '@theme/DocCardList';

Documentation for developers publishing extensions, themes, and integrations on the Woo Marketplace.

<DocCardList />
</file>

<file path="docs/woo-marketplace/managing-products.md">
---
sidebar_position: 5
sidebar_label: 'Managing products'
---

# Managing products in the Woo Marketplace

Developers selling in the WooCommerce.com Marketplace can edit their product pages, access information like usage data and sales, and manage reviews.

## Editing a product page

Most of the work for managing products can be done via the [vendor dashboard](https://woocommerce.com/wp-admin/).

- From your vendor dashboard, navigate to _Products > All Products_.
- Select the product you want to work on.

From there, you can see information about usage, upload a new version, or edit the product page. [Review our product page guidelines](/docs/woo-marketplace/product-page-content-and-assets/).

![Product management interface in vendor dashboard](./_media/manage-products-overview.png)

### Uploading new versions

To maintain a high-quality and competitive Marketplace, we encourage all vendors to regularly update their products. Consistent updates ensure compatibility with the latest versions of WooCommerce and WordPress, improve security and performance, and deliver ongoing value to customers.

[Review our product update guidelines and best practices](/docs/woo-marketplace/product-update-guidelines/).

### Adding or editing documentation

To review, edit, or add documentation, navigate to _Documentation_ in your vendor dashboard. [Review our guidelines for creating effective documentation](/docs/extensions/best-practices-extensions/support-and-documentation).

... (14 lines truncated)
</file>

<file path="docs/woo-marketplace/managing-your-account.mdx">
---
sidebar_position: 4
sidebar_label: 'Managing your account'
---

# Manage your Woo Marketplace partner account

Partners selling on the Woo Marketplace can edit their store profile and update their support email from the Partner dashboard. For some changes, we ask that you contact the Marketplace team for help.

To access store settings, click the **Store** menu under **_Settings_** in your [partner dashboard](https://woocommerce.com/wp-admin/).

## Business legal name and contact address

When you first join the WooCommerce Marketplace, we'll ask you to complete the **_Business Legal Name_** and **_Business Contact Address_** fields. These allow us to set up an account for you on our accounting platform so you can get paid for your extension sales.

![Screenshot of business name and address settings in the WooCommerce Marketplace Partner Dashboard.](./_media/vendor-store-settings-1.png)

If you make changes to the business name, you'll see a prompt to resign the **Partner Agreement**. Please click on **Partner Agreement** in the left menu, scroll down and tick the box to agree, then save. If the business name changes to a new entity after you have started selling, we will reach out about setting up a new accounting profile.

To change your vendor name, [please contact us](https://woocommerce.com/wp-admin/admin.php?page=wcpv-vendor-support).

## Vendor logo and profile

Your vendor logo and profile are a great way to tell more about yourself and your company to prospective customers! This will appear at the public profile for your brand along with your extensions.

![Screenshot of logo and profile settings in the WooCommerce Marketplace Partner Dashboard.](./_media/vendor-logo-profile.png)

- **Do:** Upload a logo for your company that **does not include** the [WooCommerce brand or trademark](https://woocommerce.com/trademark-guidelines/).
- **Do:** Tell your brand story. Why are you a great WooCommerce partner?
- **Do:** Link to your website homepage (optional). Use the same URL listed in your vendor profile if you opt to include it.
... (53 lines truncated)
</file>

<file path="docs/woo-marketplace/monetization-expectations.md">
---
sidebar_position: 2
sidebar_label: 'Monetization expectations'
---

# Monetization expectations for Marketplace plugins

When listing a plugin on the Woo Marketplace, it's important to understand how we approach monetization. Our goal is to ensure alignment between how your plugin generates value and how that value is captured, creating a transparent experience for merchants and sustainable partnerships for developers.

:::note
We do not currently accept free plugins that have no path to monetization. There should be a path to monetization either within the plugin itself or through connection to other paid products or services that then fall into one of the monetization models listed below.
:::

## Matching monetization models

The monetization model for your Marketplace listing should reflect the way your solution generates revenue:

- **Standalone functionality plugins**: Plugins that extend WooCommerce with features not tied to an external system can be sold through the standard Marketplace license model, with billing handled directly through Woo.
- **Integration plugins**: Plugins that connect WooCommerce to an external service or platform require a monetization approach that matches how the integrated system bills merchants.

## Standalone plugin licensing

For plugins that add functionality to WooCommerce without connecting to an external service, we offer two listing options:

### Paid license

The Marketplace supports a single-site license model. If you sell your plugin elsewhere with multi-site licenses or tiered packages, your Marketplace listing should use a price that closely matches your existing single-site license fee.

### Freemium

... (62 lines truncated)
</file>

<file path="docs/woo-marketplace/product-page-content-and-assets.mdx">
---
sidebar_position: 8
sidebar_label: 'Product page content and assets'
---

# Product page content and assets

This document is designed to walk you through each step of editing your product page, detailing the assets you'll need and offering a few recommendations to maximize its effectiveness. Whether you're introducing a new product or refining an existing listing, the success of your page hinges on a clear, engaging, and user-friendly presentation.

## Editing the product page

1. Log in to your [Vendor Dashboard](https://woocommerce.com/wp-admin/).
2. Navigate to _Products > [All Products](https://woocommerce.com/wp-admin/edit.php?post_type=product)_.
3. Select the product you want to work on.

From there, you can see information about usage, upload a new version, or edit the product page.

![Product edit interface](./_media/product-page-edit.png)

## Product icon

The product icon is the key visual element in all occurrences of your product in the Woo Marketplace. The image should be:

- **The logo of your product, not your brand.** For example, a Gmail extension would display a Gmail logo icon, not the Google logo.
- A **160×160px** image file in JPG or PNG format.
- The image is displayed at 80x80px, so please mind legibility. We recommend logos/symbols rather than text that would be too small to read.
- Please keep the icon content inside the **112×112px** area. This region of the image is unlikely to be hidden from view.
- We use the `border-radius` property to define the radius of the icon's corners, so please don't add rounded corners to your image.

![Product icon guidelines](./_media/product-icon-guidelines.png)
... (192 lines truncated)
</file>

<file path="docs/woo-marketplace/product-update-guidelines.md">
---
sidebar_position: 6
sidebar_label: 'Product update guidelines'
---

# Product update guidelines and best practices

To maintain a high-quality and competitive Marketplace, we encourage all vendors to regularly update their products. Consistent updates ensure compatibility with the latest versions of WooCommerce and WordPress, improve security and performance, and deliver ongoing value to customers.

## Best practices

### TL;DR

- Update your product at minimum **every 6 months**.
- Align with the [WooCommerce core release calendar](https://developer.woocommerce.com/release-calendar/).
- Use tools such as the [Quality Insights Toolkit](https://qit.woo.com/) (QIT) and your **vendor dashboard**.
- Check the [feature request portal](https://woocommerce.com/document/feature-request-portal/) for product ideas.
- Regular updates = better customer trust and renewal rates.

## Why regular updates matter

- **Compatibility**: Ensures your product works seamlessly with the latest WooCommerce and WordPress releases.
- **Security**: Patches vulnerabilities and keeps customer sites secure.
- **Performance**: Enhances speed, reliability, and efficiency.
- **Customer trust**: Builds confidence in your brand and product longevity. Regularly updated products often see higher renewal rates. Each update is a reminder of the value of keeping a subscription.
- **Support load reduction**: Reduces the number of support tickets by proactively addressing issues.

### Recommendations

1. **Monitor the [WooCommerce release calendar](https://developer.woocommerce.com/release-calendar/)**: Anticipate changes that might impact your product.
... (160 lines truncated)
</file>

<file path="docs/woo-marketplace/submitting-your-product.mdx">
---
sidebar_position: 3
sidebar_label: 'Submitting your product'
---

# Submitting your product to the Woo Marketplace

We look forward to reviewing your extension, theme, or integration for listing in the WooCommerce.com Marketplace. Before getting started, make sure you have [applied for a Marketplace vendor account](https://woocommerce.com/partners/) and your application has been approved.

## Pre-submission checklist

<details>
<summary>Business review</summary>

This includes an analysis of the product's business model and revenue share structure with Woo, as well as product rationale, competition, and developer/company history.

- **Mutually beneficial partnership**: Products must share revenue with Woo, exclude spam links, affiliate links, or links to upsell products outside of the Woo Marketplace. See our [monetization expectations](/docs/woo-marketplace/monetization-expectations/).
- **Trademark compliance**: Ensure that product names do not violate Woo's [trademark guidelines](https://woocommerce.com/trademark-guidelines/#sg-trademarks). Select a unique name that builds your brand and sets your product apart from others. [Review our product name guidelines](/docs/woo-marketplace/product-page-content-and-assets/#naming-guidelines).
- **Competitive pricing**: Is the proposed price equal to or less than the price of the product sold in other environments? Select a suggested price that matches the price you sell elsewhere.

</details>

<details>
<summary>Development guideline compliance</summary>

- Products must follow [security best practices](https://developer.wordpress.org/apis/security/).
- Products must support PHP 7.4+ as a minimum (PHP 8.3+ strongly recommended).

:::warning PHP 7.4 End of Life
PHP 7.4 reached [End of Life](https://www.php.net/supported-versions.php) (EOL) in November 2022. Using it may expose sites to security vulnerabilities.
... (156 lines truncated)
</file>

<file path="docs/woo-marketplace/support-guidelines.md">
---
sidebar_position: 10
sidebar_label: 'Support guidelines'
---

# Support guidelines for the Woo Marketplace

Adhering to the support expectations outlined in this guide is a requirement under the Marketplace Vendor Agreement. Failure to meet these expectations may result in temporary or permanent removal of your products from the Marketplace.

By participating in the WooCommerce.com Marketplace, you're not just selling a product — you're offering a complete customer experience. Providing timely, high-quality support is a core part of that experience and a key factor in building long-term trust with your customers.

That said, great support is not only a requirement — it's a growth opportunity. Providing excellent support boosts customer loyalty, increases positive reviews, encourages repeat purchases, and strengthens your reputation in the Marketplace, ultimately contributing to your long-term growth and profitability.

## Support expectations

Marketplace vendors are responsible for customer support in line with WooCommerce's Support Policy, including:

- Timely responses to customer emails.
- Handling customer reviews and ratings promptly.
- Managing feature requests posted on product pages.

The WooCommerce team supports vendors by managing account issues, refunds, coupons, escalations, and live chat queries.

### Response times

Timely responses are critical. If you are unavailable or expect delays, communicate this clearly with the WooCommerce team and arrange to redirect support requests appropriately.

### Support ratings

Customers can rate their support experience seven (7) days after submitting a ticket. Maintaining good support ratings is crucial for continued Marketplace participation.
... (79 lines truncated)
</file>

<file path="packages/js/admin-layout/changelog/.gitkeep">

</file>

<file path="packages/js/admin-layout/changelog/consolidate-eslint-core-modules">
Significance: patch
Type: dev
Comment: Consolidate the shared `import/core-modules` list into `@woocommerce/eslint-config`. Tooling only; no runtime change.
</file>

<file path="packages/js/admin-layout/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/admin-layout/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/admin-layout/src/components/LayoutContext/index.ts">

</file>

<file path="packages/js/admin-layout/src/components/LayoutContext/layout-context.tsx">
import {
	createElement,
	createContext,
	useContext,
	useMemo,
} from '@wordpress/element';
⋮----
export type LayoutContextType = {
	layoutString: string;
	extendLayout: ( item: string ) => LayoutContextType;
	layoutParts: string[];
	isDescendantOf: ( item: string ) => boolean;
};
⋮----
type LayoutContextProviderProps = {
	children: React.ReactNode;
	value: LayoutContextType;
};
⋮----
export const getLayoutContextValue = (
	layoutParts: LayoutContextType[ 'layoutParts' ] = []
): LayoutContextType => (
⋮----
export const LayoutContextProvider = ( {
	children,
	value,
}: LayoutContextProviderProps ) => (
	<LayoutContext.Provider value={ value }>
		{ children }
	</LayoutContext.Provider>
... (6 lines truncated)
</file>

<file path="packages/js/admin-layout/src/components/index.ts">

</file>

<file path="packages/js/admin-layout/src/hooks/index.ts">

</file>

<file path="packages/js/admin-layout/src/hooks/use-admin-sidebar-width.ts">
import { useEffect, useState } from '@wordpress/element';
⋮----
export function useAdminSidebarWidth()
</file>

<file path="packages/js/admin-layout/src/plugins/woo-footer-item/index.tsx">
import { Slot, Fill } from '@wordpress/components';
import { createElement } from '@wordpress/element';
import {
	createOrderedChildren,
	sortFillsByOrder,
} from '@woocommerce/components';
⋮----
export const WooFooterItem = ( {
	children,
	order = 1,
}: {
	children?: React.ReactNode;
	order?: number;
} ) =>
</file>

<file path="packages/js/admin-layout/src/plugins/woo-header-item/index.tsx">
import { Slot, Fill } from '@wordpress/components';
import { createElement } from '@wordpress/element';
import {
	createOrderedChildren,
	sortFillsByOrder,
} from '@woocommerce/components';
⋮----
const getSlotFillName = ( name?: string ) =>
⋮----
type WooHeaderItemProps = {
	order?: number;
	name?: string;
} & Omit< React.ComponentProps< typeof Fill >, 'name' >;
⋮----
export const WooHeaderItem = ( {
	children,
	order = 1,
	name = '',
}: WooHeaderItemProps ) =>
⋮----
<Fill name=
⋮----
<Slot name=
</file>

<file path="packages/js/admin-layout/src/plugins/woo-header-navigation-item/index.tsx">
import { Slot, Fill } from '@wordpress/components';
import { createElement } from '@wordpress/element';
import {
	createOrderedChildren,
	sortFillsByOrder,
} from '@woocommerce/components';
⋮----
type WooHeaderNavigationItemProps = {
	order?: number;
} & Omit< React.ComponentProps< typeof Fill >, 'name' >;
⋮----
export const WooHeaderNavigationItem = ( {
	children,
	order = 1,
}: WooHeaderNavigationItemProps ) =>
</file>

<file path="packages/js/admin-layout/src/plugins/woo-header-page-title/index.tsx">
import { Slot, Fill } from '@wordpress/components';
import { createElement, Fragment } from '@wordpress/element';
⋮----
export const WooHeaderPageTitle = ( {
	children,
}: Omit< React.ComponentProps< typeof Fill >, 'name' > ) =>
</file>

<file path="packages/js/admin-layout/src/plugins/index.ts">

</file>

<file path="packages/js/admin-layout/src/index.ts">

</file>

<file path="packages/js/admin-layout/.npmrc">
package-lock=false
</file>

<file path="packages/js/admin-layout/build.mjs">

</file>

<file path="packages/js/admin-layout/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.0.0](https://www.npmjs.com/package/@woocommerce/admin-layout/v/2.0.0) - 2026-06-11 

-   Major - Update @wordpress/* dependencies to WordPress 6.8 minimum. [#64114]
-   Major - Updated declared dependencies to React 18 and WordPress 6.6. [#53531]
-   Minor - Bump jest package dependency to 29.5.x. [#60324]
-   Minor - Improve build time for admin-layout by using webpack filesystem cache. [#64082]
-   Minor - Remove unused React imports. [#55554]
-   Minor - Upgraded TypeScript in the monorepo to 5.7.2. [#53165]
-   Patch - Fix woo header components types. [#55822]
-   Patch - Bump wireit dependency version to latest. [#57313]
-   Patch - CI: leverage composer packages cache in lint monorepo job. [#52054]
-   Patch - Fix react-18-upgrade TODOs (@ts-expect-error) in WC Admin. [#55478]
-   Patch - Fix the admin layout package installation example. [#65500]
-   Patch - Fix WooFooterItem type. [#54710]
-   Patch - Migrate from React RC types to direct React Props types with jscodeshift codemod. [#56594]
-   Patch - Monorepo: build RAM usage optimization. [#58781]
-   Patch - Monorepo: consolidate @wordpress/babel-preset-default, @wordpress/browserslist-config, glob packages versions. [#56392]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Monorepo: consolidate syncpack config around React 17/18 usage. [#52022]
-   Patch - Monorepo: consolidate TypeScript config files and JS test directories naming. [#52191]
-   Patch - Monorepo: drop the unused `concurrently` package from dependencies. [#58765]
-   Patch - Monorepo: refresh DependencyExtractionWebpackPlugin for compatibility with filesystem cache, admin build cleanup. [#64111]
-   Patch - Monorepo: refresh wireit dependencyOutputs configuration synchronization when installing dependencies. [#55095]
-   Patch - Monorepo: watch startup time optimization. [#59166]
-   Patch - Monorepo: Webpack deps review and consolidation and a bit of deps grooming. [#56746]
-   Patch - Move the CommonJS build to prepack so day-to-day development only builds the ESM output. [#64876]
... (25 lines truncated)
</file>

<file path="packages/js/admin-layout/composer.json">
{
	"name": "woocommerce/admin-layout",
	"description": "WooCommerce Admin layout component library",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/admin-layout/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/admin-layout/package.json">
{
	"name": "@woocommerce/admin-layout",
	"version": "2.0.0",
	"description": "WooCommerce admin layout components and utilities.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"keywords": [
		"wordpress",
		"woocommerce"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/admin-layout/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
	"main": "build/index.js",
	"module": "build-module/index.js",
	"types": "build-types/index.d.ts",
	"react-native": "src/index",
... (82 lines truncated)
</file>

<file path="packages/js/admin-layout/README.md">
# Admin Layout

A collection of WooCommerce Admin layout components and utilities.

## Installation

Install the module

```bash
pnpm install @woocommerce/admin-layout --save
```
</file>

<file path="packages/js/admin-layout/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": [
		{
			"path": "../components"
		}
	]
}
</file>

<file path="packages/js/admin-layout/webpack.config.js">

</file>

<file path="packages/js/block-templates/changelog/remove-product-block-editor-reference">
Significance: patch
Type: dev

Remove stale product block editor references.
</file>

<file path="packages/js/components/changelog/.gitkeep">

</file>

<file path="packages/js/components/changelog/39772-search-wcsettings">
Significance: patch
Type: fix

Prevent the Search variations autocompleter from failing when wcSettings is unavailable.
</file>

<file path="packages/js/components/changelog/66078-dehoist-react">
Significance: patch
Type: dev
Comment: Declare react/react-dom as devDependencies alongside the existing peerDependencies. Tooling only; no runtime change.
</file>

<file path="packages/js/components/changelog/66477-sprinkle-filter-picker-colon">
Significance: patch
Type: tweak

Remove the trailing colon from FilterPicker labels to match WordPress 7.0 form-field labeling.
</file>

<file path="packages/js/components/changelog/67634-35900-ip-search-bug">
Significance: patch
Type: fix

Fix removal of Advanced Filter selections that use string identifiers, such as download IP addresses.
</file>

<file path="packages/js/components/changelog/consolidate-eslint-core-modules">
Significance: patch
Type: dev
Comment: Consolidate the shared `import/core-modules` list into `@woocommerce/eslint-config`. Tooling only; no runtime change.
</file>

<file path="packages/js/components/changelog/dev-eslint-no-floating-promises">
Significance: patch
Type: dev

Add void to intentionally-unawaited promises for the new no-floating-promises lint rule
</file>

<file path="packages/js/components/changelog/dev-migrate-advanced-filters-to-ts">
Significance: patch
Type: dev

Migrate AdvancedFilters component to TS
</file>

<file path="packages/js/components/changelog/fix-37168-37169-form-state-updates">
Significance: minor
Type: fix

Fix Form setValue reporting every field as changed and dropping earlier writes made in the same synchronous stack.
</file>

<file path="packages/js/components/changelog/fix-53727-rtl-dropdown-arrow">
Significance: patch
Type: fix

Keep the dropdown button arrow in place when open in RTL languages
</file>

<file path="packages/js/components/changelog/fix-55817-rtl-pagination-arrows">
Significance: patch
Type: fix

Flip the pagination previous/next arrow icons in RTL locales so they point in the direction they navigate.
</file>

<file path="packages/js/components/changelog/fix-form-setvalue-lodash-key-resolution">
Significance: patch
Type: fix
Comment: Follow-up to #68050 and #68224, both unreleased. Form setValue again resolves a name as one literal key or a path the way lodash set() does, which is what the last release did, so no shipped behavior changes.
</file>

<file path="packages/js/components/changelog/fix-form-setvalue-zero-segment-name">
Significance: patch
Type: fix

Fix Form setValue dropping a write whose name yields no path segments, such as an empty string.
</file>

<file path="packages/js/components/changelog/fix-select-control-inline-tag-alignment">
Significance: patch
Type: fix

Align inline tags in single-select controls.
</file>

<file path="packages/js/components/changelog/fix-wooplug-1016-ellipsis-menu-labels">
Significance: patch
Type: fix

Keep EllipsisMenu labels on one line and show focus styles only for keyboard navigation.
</file>

<file path="packages/js/components/changelog/fix-wooplug-1941-tax-rate-filter-options">
Significance: patch
Type: fix

Show all applicable tax rates in the Analytics advanced filter by requesting the full page of results instead of only the first 10.
</file>

<file path="packages/js/components/changelog/woo6-109-storybook-10">
Significance: patch
Type: dev
Comment: Upgrade Storybook development tooling to version 10.
</file>

<file path="packages/js/components/changelog/wooa7s-1541-downloads-customer-filter">
Significance: minor
Type: add

Search: add a `registeredCustomers` type that matches registered customers on name, username or email, and a `customerNames` type that replaces `customers`. `customers` is now a deprecated alias of `customerNames` and behaves identically.
</file>

<file path="packages/js/components/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/components/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/components/changelog/wooplug-929-settings-alias-docs">
Significance: patch
Type: dev
Comment: Point the Jest mocking note for @woocommerce/settings to the dependency extraction plugin README.
</file>

<file path="packages/js/components/src/abbreviated-card/stories/abbreviated-card.story.js">
export const Basic = () => (
	<AbbreviatedCard icon={ page } href="#">
		<h3>Title</h3>
		<p>Abbreviated card content</p>
	</AbbreviatedCard>
);
</file>

<file path="packages/js/components/src/abbreviated-card/index.js">
const AbbreviatedCard = ( {
	children,
	className,
	href,
	icon,
	onClick,
	type,
} ) =>
</file>

<file path="packages/js/components/src/abbreviated-card/README.md">
# AbbreviatedCard

Use `AbbreviatedCard` to display an abbreviated card element.

## Usage

```jsx
import { Icon, box } from '@wordpress/icons';

<AbbreviatedCard
	href="#"
	icon={ <Icon icon={ page } /> }
	onClick={ () => alert( 'Abbreviated card clicked' ) }
>
	Content
</AbbreviatedCard>;
```

### Props

| Name        | Type      | Default | Description                                                                      |
| ----------- | --------- | ------- | -------------------------------------------------------------------------------- |
| `children`  | ReactNode | `null`  | (required) The children inside the abbreviated card, rendered in the `component` |
| `className` | String    | `null`  | Additional CSS classes                                                           |
| `href`      | String    | `null`  | (required) The resource to link to                                               |
| `icon`      | Element   | `null`  | (required) The element used to represent the icon for this card                  |
| `onClick`   | Function  | `null`  | On click handler called when the component is clicked                            |
| `type`      | String    | `null`  | Type of link                                                                     |
</file>

<file path="packages/js/components/src/advanced-filters/stories/advanced-filters.story.tsx">
import { createElement } from '@wordpress/element';
⋮----
import AdvancedFilters from '../';
import type { AdvancedFilterConfig } from '../types';
⋮----
export const Basic = () => (
	<AdvancedFilters
		siteLocale={ siteLocale }
		path={ path }
		query={ query }
		config={ advancedFilters }
		currency={ currency }
	/>
);
</file>

<file path="packages/js/components/src/advanced-filters/attribute-filter.tsx">
import { SelectControl as Select, Spinner } from '@wordpress/components';
import clsx from 'clsx';
import {
	createElement,
	Fragment,
	useEffect,
	useState,
} from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';
import { __ } from '@wordpress/i18n';
⋮----
import Search from '../search';
import SelectControl from '../select-control';
import {
	backwardsCompatibleCreateInterpolateElement as createInterpolateElement,
	textContent,
} from './utils';
import type {
	ActiveFilter,
	FilterComponentProps,
	FilterConfig,
	FilterRule,
} from './types';
⋮----
export type AttributeFilterProps = FilterComponentProps;
⋮----
type AttributeOption = {
	key: string;
	label: string;
};
... (24 lines truncated)
</file>

<file path="packages/js/components/src/advanced-filters/date-filter.tsx">
import { createElement, Component, Fragment } from '@wordpress/element';
import { SelectControl } from '@wordpress/components';
import { find, partial } from 'lodash';
import clsx from 'clsx';
import { __, _x } from '@wordpress/i18n';
import { isoDateFormat, toMoment } from '@woocommerce/date';
import moment from 'moment';
import type { Moment } from 'moment';
import type { ReactNode } from 'react';
⋮----
import DatePicker from '../calendar/date-picker';
import {
	backwardsCompatibleCreateInterpolateElement as createInterpolateElement,
	textContent,
} from './utils';
import type { FilterComponentProps, FilterConfig, FilterRule } from './types';
⋮----
export type DateFilterProps = FilterComponentProps;
⋮----
type DateUpdate = {
	date: Moment | null;
	text: string;
	error: string | null;
};
⋮----
type RangeInput = 'after' | 'before';
⋮----
type DateFilterState = {
	before: Moment | null;
	beforeText: string;
... (35 lines truncated)
</file>

<file path="packages/js/components/src/advanced-filters/index.tsx">
import { __ } from '@wordpress/i18n';
import {
	Button,
	Card,
	CardBody,
	CardFooter,
	CardHeader,
	Dropdown,
	SelectControl,
} from '@wordpress/components';
import { createElement, Component, createRef } from '@wordpress/element';
import { partial, isEqual } from 'lodash';
import AddOutlineIcon from 'gridicons/dist/add-outline';
import {
	getActiveFiltersFromQuery,
	getDefaultOptionValue,
	getNewPath,
	getQueryFromActiveFilters,
	getHistory,
} from '@woocommerce/navigation';
⋮----
import Link from '../link';
import AdvancedFilterItem from './item';
import { Text } from '../experimental';
import { backwardsCompatibleCreateInterpolateElement as createInterpolateElement } from './utils';
import type {
	ActiveFilter,
	AdvancedFilterAction,
	AdvancedFilterConfig,
	Currency,
... (58 lines truncated)
</file>

<file path="packages/js/components/src/advanced-filters/item.tsx">
import { createElement } from '@wordpress/element';
import { Button } from '@wordpress/components';
import CrossSmallIcon from 'gridicons/dist/cross-small';
import clsx from 'clsx';
⋮----
import SelectFilter from './select-filter';
import SearchFilter from './search-filter';
import NumberFilter from './number-filter';
import DateFilter from './date-filter';
import AttributeFilter from './attribute-filter';
import type {
	ActiveFilter,
	AdvancedFilterConfig,
	Currency,
	FilterConfig,
	OnFilterChange,
	Query,
} from './types';
⋮----
export type AdvancedFilterItemProps = {
	config: AdvancedFilterConfig;
	currency: Currency;
	filter: ActiveFilter;
	isEnglish: boolean;
	onFilterChange: OnFilterChange;
	query: Query;
	removeFilter: () => void;
};
⋮----
const isKnownComponent = (
... (3 lines truncated)
</file>

<file path="packages/js/components/src/advanced-filters/number-filter.tsx">
import { createElement, Component, Fragment } from '@wordpress/element';
import { SelectControl, TextControl } from '@wordpress/components';
import { get, find, isArray } from 'lodash';
import clsx from 'clsx';
import { sprintf, __, _x } from '@wordpress/i18n';
import { CurrencyFactory } from '@woocommerce/currency';
import type { CurrencyConfig } from '@woocommerce/currency';
import type { ComponentType, ReactNode } from 'react';
⋮----
import TextControlWithAffixesBase from '../text-control-with-affixes';
import {
	backwardsCompatibleCreateInterpolateElement as createInterpolateElement,
	textContent,
} from './utils';
import type {
	ActiveFilter,
	Currency,
	FilterComponentProps,
	FilterConfig,
	FilterRule,
} from './types';
⋮----
export type NumberFilterProps = FilterComponentProps & {
	currency: Currency;
};
⋮----
type TextControlWithAffixesProps = {
	className?: string;
	type?: string;
	value: string | number;
... (42 lines truncated)
</file>

<file path="packages/js/components/src/advanced-filters/README.md">
# Advanced Filters

Displays a configurable set of filters which can modify query parameters. Display, behavior, and types of filters can be designated by a configuration object.

## Usage

Below is a config example complete with translation strings. Advanced filters makes use of [createInterpolateElement](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-element/#createinterpolateelement) to organize sentence structure, resulting in a filter visually represented as a sentence fragment in any language.

```js
const config = {
	title: __(
		// A sentence describing filters for Orders
		// See screen shot for context: https://cloudup.com/cSsUY9VeCVJ
		'Orders Match <select/> Filters',
		'woocommerce'
	),
	filters: {
		status: {
			labels: {
				add: __( 'Order Status', 'woocommerce' ),
				remove: __( 'Remove order status filter', 'woocommerce' ),
				rule: __(
					'Select an order status filter match',
					'woocommerce'
				),
				// A sentence describing an Order Status filter
				// See screen shot for context: https://cloudup.com/cSsUY9VeCVJ
				title: __( 'Order Status <rule/> <filter/>', 'woocommerce' ),
				filter: __( 'Select an order status', 'woocommerce' ),
			},
... (164 lines truncated)
</file>

<file path="packages/js/components/src/advanced-filters/search-filter.tsx">
import { createElement, Component, Fragment } from '@wordpress/element';
import { SelectControl } from '@wordpress/components';
import { find, isEqual } from 'lodash';
import clsx from 'clsx';
⋮----
import Search from '../search';
import type { SearchProps, SearchType } from '../search';
import {
	backwardsCompatibleCreateInterpolateElement as createInterpolateElement,
	textContent,
} from './utils';
import type {
	ActiveFilter,
	ActiveFilterValue,
	FilterComponentProps,
	FilterConfig,
	FilterRule,
	Query,
	SearchLabel,
} from './types';
⋮----
export type SearchFilterProps = FilterComponentProps;
⋮----
export type SearchSelection = {
	key: string | number;
	label: string;
	id?: string | number;
};
⋮----
type SearchFilterState = {
... (19 lines truncated)
</file>

<file path="packages/js/components/src/advanced-filters/select-filter.tsx">
import { createElement, Component, Fragment } from '@wordpress/element';
import { SelectControl, Spinner } from '@wordpress/components';
import { find } from 'lodash';
import clsx from 'clsx';
import { getDefaultOptionValue } from '@woocommerce/navigation';
⋮----
import {
	backwardsCompatibleCreateInterpolateElement as createInterpolateElement,
	textContent,
} from './utils';
import type {
	ActiveFilter,
	FilterComponentProps,
	FilterConfig,
	FilterOption,
	FilterRule,
} from './types';
⋮----
export type SelectFilterProps = FilterComponentProps;
⋮----
type SelectFilterState = {
	options?: FilterOption[];
};
⋮----
constructor( props: SelectFilterProps )
⋮----
updateOptions( options: FilterOption[] )
⋮----
getScreenReaderText( filter: ActiveFilter, config: FilterConfig )
⋮----
... (2 lines truncated)
</file>

<file path="packages/js/components/src/advanced-filters/types.ts">
import type { CurrencyConfig } from '@woocommerce/currency';
⋮----
import type { AutoCompleter } from '../search/autocompleters';
⋮----
export type Query = Record<
	string,
	string | string[] | string[][] | undefined
>;
⋮----
export type FilterRule = {
	value: string;
	label: string;
};
⋮----
export type FilterOption = {
	value: string;
	label: string;
};
⋮----
export type FilterLabels = {
	add: string;
	remove?: string;
	rule?: string;
	title: string;
	filter?: string;
	placeholder?: string;
};
⋮----
export type SearchLabel = {
	id?: string | number;
... (68 lines truncated)
</file>

<file path="packages/js/components/src/advanced-filters/utils.ts">
import { isArray, isNumber, isString } from 'lodash';
import deprecated from '@wordpress/deprecated';
import { createInterpolateElement, isValidElement } from '@wordpress/element';
import type { ReactElement, ReactNode } from 'react';
⋮----
export function textContent( components: ReactNode )
⋮----
const toText = ( component: ReactNode ) =>
⋮----
/**
 * This function processes an input string, checks for deprecated interpolation formatting, and
 * modifies it to conform to the new standard.
 * The deprecated interpolation formatting is `{{element}}...{{/element}}`, and the new standard
 * formatting is `<element>...</element>`.
 *
 * @param {string} interpolatedString The interpolation string to be parsed.
 *
 * @return {string}  Fixed interpolation string.
 */
export function getInterpolatedString( interpolatedString: string )
⋮----
// Closing tag
⋮----
// Self-closing tag
⋮----
// Opening tag
⋮----
export function backwardsCompatibleCreateInterpolateElement(
	interpolatedString: string,
	conversionMap: Record< string, ReactElement >
... (2 lines truncated)
</file>

<file path="packages/js/components/src/analytics/error/stories/analytics-error.story.tsx">
import { createElement } from '@wordpress/element';
import { StoryFn } from '@storybook/react-webpack5';
⋮----
import AnalyticsError from '../';
⋮----
const Template: StoryFn = ( args ) => <AnalyticsError
</file>

<file path="packages/js/components/src/analytics/error/index.js">
function AnalyticsError(
⋮----
const actionCallback = () =>
</file>

<file path="packages/js/components/src/analytics/error/README.md">
# AnalyticsError

Standard error message with reload action used in Analytics pages.

## Usage

```jsx
<AnalyticsError />
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`className` | String    | `null`  | Additional CSS classes
</file>

<file path="packages/js/components/src/analytics/index.js">

</file>

<file path="packages/js/components/src/animation-slider/stories/animation-slider.story.js">
class BasicExample extends Component
⋮----
forward()
⋮----
back()
⋮----
render()
⋮----
export const Basic = ()
</file>

<file path="packages/js/components/src/animation-slider/index.js">
class AnimationSlider extends Component
⋮----
onExited()
⋮----
render()
</file>

<file path="packages/js/components/src/animation-slider/README.md">
AnimationSlider
===

This component creates slideable content controlled by an animate prop to direct the contents to slide left or right.
All other props are passed to `CSSTransition`. More info at http://reactcommunity.org/react-transition-group/css-transition

## Usage

```jsx
<AnimationSlider animationKey="1" animate="right">
	{ ( status ) => (
		<span>One (1)</span>
	) }
</AnimationSlider>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`children` | function | `null` | (required) A function returning rendered content with argument status, reflecting `CSSTransition` status
`animationKey` | any | `null` | (required) A unique identifier for each slideable page
`animate` | string | `null` | null, 'left', 'right', to designate which direction to slide on a change
`onExited` | function | `null` | A function to be executed after a transition is complete, passing the containing ref as the argument
</file>

<file path="packages/js/components/src/badge/stories/badge.story.tsx">
import { Card, CardBody } from '@wordpress/components';
import { createElement } from '@wordpress/element';
import { StoryFn } from '@storybook/react-webpack5';
⋮----
import { Badge, BadgeProps } from '../';
⋮----
const Template: StoryFn< BadgeProps > = ( args ) => (
	<Card>
		<CardBody>
			<Badge { ...args } />
		</CardBody>
	</Card>
);
</file>

<file path="packages/js/components/src/badge/index.tsx">
import { createElement } from '@wordpress/element';
⋮----
export type BadgeProps = {
	count: number;
} & React.HTMLAttributes< HTMLSpanElement >;
⋮----
export const Badge = (
</file>

<file path="packages/js/components/src/calendar/stories/date-picker.story.js">
const DatePickerExample = () =>
⋮----
function onDatePickerUpdate(
⋮----
export const Basic = ()
</file>

<file path="packages/js/components/src/calendar/stories/date-range.story.js">
const DateRangeExample = () =>
⋮----
function onRangeUpdate( update )
⋮----
export const Basic = ()
</file>

<file path="packages/js/components/src/calendar/date-picker.js">
class DatePicker extends Component
⋮----
handleFocus( isOpen, onToggle )
⋮----
handleBlur( isOpen, onToggle, event )
⋮----
onDateChange( onToggle, dateString )
⋮----
onInputChange( event )
⋮----
render()
</file>

<file path="packages/js/components/src/calendar/date-range.js">
const isRTL = ()
⋮----
class DateRange extends Component
⋮----
keepFocusInside( blurSource, e )
⋮----
onDatesChange(
⋮----
onFocusChange( focusedInput )
⋮----
onInputChange( input, event )
⋮----
setTnitialVisibleMonth( isDoubleCalendar, before )
⋮----
render()
</file>

<file path="packages/js/components/src/calendar/input.js">
const DateInput = ( {
	disabled = false,
	value,
	onChange,
	dateFormat,
	label,
	describedBy,
	error,
	onFocus = () => {},
	onBlur = () => {},
	onKeyDown = noop,
	errorPosition = 'bottom center',
} ) =>
</file>

<file path="packages/js/components/src/calendar/phrases.js">
chooseAvailableStartDate: (
chooseAvailableEndDate: (
chooseAvailableDate: (
dateIsUnavailable: (
dateIsSelected: (
</file>

<file path="packages/js/components/src/calendar/README.md">
# DatePicker and DateRange

## DatePicker

### Usage

```jsx
<DatePicker
	date={ date }
	text={ text }
	error={ error }
	onUpdate={ ( { date, text, error } ) => setState( { date, text, error } ) }
	dateFormat="MM/DD/YYYY"
/>
```

#### Props

| Name            | Type     | Default | Description                                                                  |
| --------------- | -------- | ------- | ---------------------------------------------------------------------------- |
| `date`          | Object   | `null`  | A moment date object representing the selected date. `null` for no selection |
| `disabled`      | Boolean  | `null`  | Whether the input is disabled                                                |
| `text`          | String   | `null`  | The date in human-readable format. Displayed in the text input               |
| `error`         | String   | `null`  | A string error message, shown to the user                                    |
| `onUpdate`      | Function | `null`  | (required) A function called upon selection of a date or input change        |
| `dateFormat`    | String   | `null`  | (required) The date format in moment.js-style tokens                         |
| `isInvalidDate` | Function | `null`  | A function to determine if a day on the calendar is not valid                |
| `popoverProps`  | Object   | `{}`    | Props that will be sent to the Dropdown component                            |

## DateRange
... (36 lines truncated)
</file>

<file path="packages/js/components/src/chart/d3chart/d3base/index.js">
export default class D3Base extends Component
⋮----
componentDidMount()
⋮----
shouldComponentUpdate( nextProps )
⋮----
componentDidUpdate()
⋮----
componentWillUnmount()
⋮----
delayedScroll()
⋮----
deleteChart()
⋮----
drawUpdatedChart()
⋮----
getContainer()
⋮----
render()
</file>

<file path="packages/js/components/src/chart/d3chart/d3base/README.md">
# D3 Base Component

Integrate React Lifecycle methods with d3.js charts.

### Base Component Responsibilities

* Create and manage mounting and unmounting parent `div` and `svg`
* Handle resize events, resulting re-renders, and event listeners
* Handle re-renders as a result of new props

## Props

### className
{ string } A class to be applied to the parent `div`

### getParams( node )
{ function } A function returning an object containing required properties for drawing a chart. This object is created before re-render, making it an ideal place for calculating scales and other props or user input based properties.
* `svg` { node } The parent `div`. Useful for calculating available widths

### drawChart( svg, params )
{ function } draw the chart
* `svg` { node } Base element 
* `params` { Object } Properties created by the `getParams` function
</file>

<file path="packages/js/components/src/chart/d3chart/utils/axis-x.js">
const calculateMaxXTicks = ( width, mode ) =>
⋮----
const getFirstDatePerMonth = ( dates ) =>
⋮----
const areDatesInTheSameDay = ( dates ) =>
⋮----
const getFactors = ( inputNum ) =>
⋮----
const calculateXTicksIncrementFactor = ( uniqueDates, maxTicks ) =>
⋮----
const getXTicksFromIncrementFactor = ( uniqueDates, incrementFactor ) =>
⋮----
export const getXTicks = ( uniqueDates, width, mode, interval ) =>
⋮----
export const compareStrings = (
	s1,
	s2,
	splitChar = new RegExp( [ ' |,' ], 'g' )
) =>
⋮----
const removeDuplicateDates = ( d, i, ticks, formatter ) =>
⋮----
export const drawXAxis = ( node, params, scales, formats ) =>
</file>

<file path="packages/js/components/src/chart/d3chart/utils/axis-y.js">
const calculateYGridValues = ( numberOfTicks, limit, roundValues ) =>
⋮----
const getNegativeYGrids = ( yMin, step ) =>
⋮----
const getPositiveYGrids = ( yMax, step ) =>
⋮----
export const getYGrids = ( yMin, yMax, step ) =>
⋮----
export const drawYAxis = ( node, scales, formats, margin, isRTL ) =>
</file>

<file path="packages/js/components/src/chart/d3chart/utils/axis.js">
export const drawAxis = ( node, params, scales, formats, margin, isRTL ) =>
</file>

<file path="packages/js/components/src/chart/d3chart/utils/bar-chart.js">
export const drawBars = ( node, data, params, scales, formats, tooltip ) =>
</file>

<file path="packages/js/components/src/chart/d3chart/utils/breakpoints.js">

</file>

<file path="packages/js/components/src/chart/d3chart/utils/color.js">
export const getColor = ( orderedKeys, colorScheme ) => ( key ) =>
</file>

<file path="packages/js/components/src/chart/d3chart/utils/index.js">
export const getFormatter = ( format, formatter = d3Format )
⋮----
export const getUniqueKeys = ( data ) =>
⋮----
export const getOrderedKeys = ( data ) =>
⋮----
export const getUniqueDates = ( data, dateParser ) =>
⋮----
export const isDataEmpty = ( data, baseValue = 0 ) =>
</file>

<file path="packages/js/components/src/chart/d3chart/utils/line-chart.js">
export const getDateSpaces = (
	data,
	uniqueDates,
	visibleKeys,
	width,
	xScale
) =>
⋮----
export const getLine = ( xScale, yScale )
⋮----
export const getLineData = ( data, orderedKeys )
⋮----
export const drawLines = ( node, data, params, scales, formats, tooltip ) =>
</file>

<file path="packages/js/components/src/chart/d3chart/utils/scales.js">
export const getXScale = ( uniqueDates, width, compact = false )
⋮----
export const getXGroupScale = ( orderedKeys, xScale, compact = false )
⋮----
export const getXLineScale = ( uniqueDates, width )
⋮----
const getYValueLimits = ( data ) =>
⋮----
export const calculateStep = ( minValue, maxValue ) =>
⋮----
export const getYScaleLimits = ( data ) =>
⋮----
export const getYScale = ( height, yMin, yMax )
</file>

<file path="packages/js/components/src/chart/d3chart/utils/tooltip.js">
class ChartTooltip
⋮----
calculateXPosition( elementCoords, chartCoords, elementWidthRatio )
⋮----
calculateYPosition( elementCoords, chartCoords )
⋮----
calculatePosition( element, elementWidthRatio = 1 )
⋮----
hide()
⋮----
getTooltipRowLabel( d, row )
⋮----
show( d, triggerElement, parentNode, elementWidthRatio = 1 )
</file>

<file path="packages/js/components/src/chart/d3chart/chart.js">
const isRTL = ()
⋮----
class D3Chart extends Component
⋮----
getFormatParams()
⋮----
getScaleParams( uniqueDates )
⋮----
getParams( uniqueDates )
⋮----
createTooltip( chart, getColorFunction, visibleKeys )
⋮----
drawChart( node )
⋮----
shouldBeCompact()
⋮----
getMargin()
⋮----
getWidth()
⋮----
getEmptyMessage()
⋮----
render()
</file>

<file path="packages/js/components/src/chart/d3chart/example.md">
```jsx
import { D3Chart, D3Legend } from 'react-d3-chart';

const data =  [
	{
		date: '2018-05-30T00:00:00',
		Hoodie: { value: 21599 },
		Sunglasses: { value: 38537 },
		Cap: { value: 106010 },
	},
	{
		date: '2018-05-31T00:00:00',
		Hoodie: { value: 14205 },
		Sunglasses: { value: 24721 },
		Cap: { value: 70131 },
	},
	{
		date: '2018-06-01T00:00:00',
		Hoodie: { value: 10581 },
		Sunglasses: { value: 19991 },
		Cap: { value: 53552 },
	},
	{
		date: '2018-06-02T00:00:00',
		Hoodie: { value: 9250 },
		Sunglasses: { value: 16072 },
		Cap: { value: 47821 },
	},
];

... (7 lines truncated)
</file>

<file path="packages/js/components/src/chart/d3chart/index.js">

</file>

<file path="packages/js/components/src/chart/d3chart/legend.js">
class D3Legend extends Component
⋮----
componentDidMount()
⋮----
componentWillUnmount()
⋮----
updateListScroll()
⋮----
render()
</file>

<file path="packages/js/components/src/chart/stories/chart.story.js">
export const Default = ( { legendPosition } ) => (
	<Chart data={ data } legendPosition={ legendPosition } />
);
</file>

<file path="packages/js/components/src/chart/constants.js">

</file>

<file path="packages/js/components/src/chart/index.js">
function getD3CurrencyFormat( symbol, position )
⋮----
/**
 * A chart container using d3, to display timeseries data with an interactive legend.
 */
class Chart extends Component
⋮----
getDataKeys()
⋮----
componentDidUpdate()
⋮----
componentDidMount()
⋮----
componentWillUnmount()
⋮----
setD3DefaultFormat()
⋮----
getOrderedKeys( focusedKeys, visibleKeys, selectedIds = [] )
⋮----
handleTypeToggle( chartType )
⋮----
handleLegendToggle( event )
⋮----
handleLegendHover( event )
⋮----
updateDimensions()
⋮----
getVisibleData( data, orderedKeys )
⋮----
setInterval( interval )
... (9 lines truncated)
</file>

<file path="packages/js/components/src/chart/placeholder.js">
class ChartPlaceholder extends Component
⋮----
render()
</file>

<file path="packages/js/components/src/chart/README.md">
Chart
===

A chart container using d3, to display timeseries data with an interactive legend.

## Usage

```jsx
const data = [
	{
		date: '2018-05-30T00:00:00',
		Hoodie: {
			label: 'Hoodie',
			value: 21599,
		},
		Sunglasses: {
			label: 'Sunglasses',
			value: 38537,
		},
		Cap: {
			label: 'Cap',
			value: 106010,
		},
	},
	{
		date: '2018-05-31T00:00:00',
		Hoodie: {
			label: 'Hoodie',
			value: 14205,
		},
... (92 lines truncated)
</file>

<file path="packages/js/components/src/collapsible-content/stories/collapsible-content.story.tsx">
import { createElement } from '@wordpress/element';
⋮----
import { CollapsibleContent } from '../';
⋮----
export const Basic = () =>
⋮----
export const Expanded = () =>
</file>

<file path="packages/js/components/src/collapsible-content/collapsible-content.tsx">
import { useInstanceId } from '@wordpress/compose';
import { createElement, useState } from '@wordpress/element';
import { Icon, chevronDown, chevronUp } from '@wordpress/icons';
⋮----
import { DisplayState } from '../display-state';
⋮----
export type CollapsedProps = {
	initialCollapsed?: boolean;
	toggleText: string;
	persistRender?: boolean;
	children: React.ReactNode;
	hintText?: string;
} & React.HTMLAttributes< HTMLDivElement >;
⋮----
const getState = () =>
</file>

<file path="packages/js/components/src/collapsible-content/index.tsx">

</file>

<file path="packages/js/components/src/compare-filter/stories/compare-filter.story.js">
getLabels()
⋮----
export const Basic = ( {
	path = new URL( document.location ).searchParams.get( 'path' ),
} ) => <CompareFilter path=
</file>

<file path="packages/js/components/src/compare-filter/button.js">
const CompareButton = ( {
	className,
	count,
	children,
	disabled,
	helpText,
	onClick,
} )
</file>

<file path="packages/js/components/src/compare-filter/index.js">
export class CompareFilter extends Component
⋮----
componentDidUpdate(
		{ param: prevParam, query: prevQuery },
		{ selected: prevSelected }
)
⋮----
clearQuery()
⋮----
updateLabels( selected )
⋮----
updateQuery()
⋮----
onButtonClicked( e )
⋮----
render()
</file>

<file path="packages/js/components/src/compare-filter/README.md">
CompareFilter
===

Displays a card + search used to filter results as a comparison between objects.

## Usage

```jsx
const path = ''; // from React Router
const getLabels = () => Promise.resolve( [] );
const labels = {
	helpText: 'Select at least two products to compare',
	placeholder: 'Search for products to compare',
	title: 'Compare Products',
	update: 'Compare',
};

<CompareFilter
	type="products"
	param="product"
	path={ path }
	getLabels={ getLabels }
	labels={ labels }
/>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
... (7 lines truncated)
</file>

<file path="packages/js/components/src/conditional-wrapper/conditional-wrapper.tsx">
export type ConditionalWrapperProps< T = JSX.Element > = {
	children: T;
	condition: boolean;
	wrapper: ( children: T ) => JSX.Element;
};
⋮----
export const ConditionalWrapper = < T, >( {
	condition,
	wrapper,
	children,
}: ConditionalWrapperProps< T > ): JSX.Element | T
</file>

<file path="packages/js/components/src/conditional-wrapper/index.ts">

</file>

<file path="packages/js/components/src/confetti-animation/index.ts">
import confetti from 'canvas-confetti';
import { useEffect, useRef } from '@wordpress/element';
⋮----
type FireOptions = {
	spread: number;
	startVelocity?: number;
	decay?: number;
	scalar?: number;
};
⋮----
function fireConfetti( colors: string[] )
⋮----
function fire( particleRatio: number, opts: FireOptions )
⋮----
export const ConfettiAnimation = ( {
	trigger = true,
	delay = 0,
	colors = COLORS,
} ) =>
</file>

<file path="packages/js/components/src/date/stories/date.story.js">
export const Basic = ()
</file>

<file path="packages/js/components/src/date/index.js">
const Date = ( {
	date,
	machineFormat = 'Y-m-d H:i:s',
	screenReaderFormat = 'F j, Y',
	visibleFormat = 'Y-m-d',
} ) =>
</file>

<file path="packages/js/components/src/date/README.md">
Date
===

Use the `Date` component to display accessible dates or times.

## Usage

```jsx
<Date date="2019-01-01" />
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`date` | One of type: string, object | `null` | (required) Date to use in the component
`machineFormat` | String | `'Y-m-d H:i:s'` | Date format used in the `datetime` prop of the `time` element
`screenReaderFormat` | String | `'F j, Y'` | Date format used for screen readers
`visibleFormat` | String | `'Y-m-d'` | Date format displayed in the page
</file>

<file path="packages/js/components/src/date-range-filter-picker/stories/date-range-filter-picker.story.js">
export const Basic = () => (
	<DateRangeFilterPicker
		key="daterange"
		query={ query }
		onRangeSelect={ () => {} }
		dateQuery={ dateQuery }
		isoDateFormat={ isoDateFormat }
	/>
);
</file>

<file path="packages/js/components/src/date-range-filter-picker/compare-periods.js">
class ComparePeriods extends Component
⋮----
render()
</file>

<file path="packages/js/components/src/date-range-filter-picker/content.js">
class DatePickerContent extends Component
⋮----
onTabSelect( tab )
⋮----
isFutureDate( dateString )
⋮----
render()
</file>

<file path="packages/js/components/src/date-range-filter-picker/index.js">
class DateRangeFilterPicker extends Component
⋮----
formatDate( date, format )
⋮----
getResetState()
⋮----
update( update )
⋮----
onSelect( selectedTab, onClose )
⋮----
getButtonLabel()
⋮----
isValidSelection( selectedTab )
⋮----
resetCustomValues()
⋮----
render()
</file>

<file path="packages/js/components/src/date-range-filter-picker/preset-periods.js">
class PresetPeriods extends Component
⋮----
render()
</file>

<file path="packages/js/components/src/date-range-filter-picker/README.md">
Date Range Picker
===

Select a range of dates or single dates

## Usage

```jsx
import {
	getDateParamsFromQuery,
	getCurrentDates,
	isoDateFormat,
	loadLocaleData,
} from '@woocommerce/date';

/**
 * External dependencies
 */
import { partialRight } from 'lodash';

const query = {};

// Fetch locale from store settings and load for date functions.
const localeSettings = {
	userLocale: 'fr_FR',
	weekdaysShort: [ 'dim', 'lun', 'mar', 'mer', 'jeu', 'ven', 'sam' ],
};
loadLocaleData( localeSettings );

const defaultDateRange = 'period=month&compare=previous_year';
... (40 lines truncated)
</file>

<file path="packages/js/components/src/date-time-picker-control/stories/date-time-picker-control.story.tsx">
import { Button, Popover, SlotFillProvider } from '@wordpress/components';
import { createElement, useCallback, useState } from '@wordpress/element';
⋮----
import { DateTimePickerControl } from '../';
⋮----
const Template = ( args ) => <DateTimePickerControl
⋮----
function ControlledDecorator( Story, props )
⋮----
function nowWithZeroedSeconds()
⋮----
setControlledDate(
⋮----
function PopoverSlotDecorator( Story, props )
</file>

<file path="packages/js/components/src/date-time-picker-control/date-time-picker-control.tsx">
import { Ref } from 'react';
import { format as formatDate } from '@wordpress/date';
import {
	createElement,
	useCallback,
	useState,
	useEffect,
	useMemo,
	useRef,
	forwardRef,
} from '@wordpress/element';
import { Icon, calendar } from '@wordpress/icons';
import moment, { Moment } from 'moment';
import clsx from 'clsx';
import { sprintf, __ } from '@wordpress/i18n';
import { useDebounce, useInstanceId } from '@wordpress/compose';
import {
	BaseControl,
	DatePicker,
	DateTimePicker as WpDateTimePicker,
	Dropdown,
	__experimentalInputControl as InputControl,
} from '@wordpress/components';
⋮----
S( momentDate: Moment )
⋮----
z( momentDate: Moment )
⋮----
t( momentDate: Moment )
⋮----
... (80 lines truncated)
</file>

<file path="packages/js/components/src/date-time-picker-control/index.tsx">

</file>

<file path="packages/js/components/src/date-time-picker-control/README.md">
# DateTimePickerControl

Add a component to allow selecting of a date and time via a calendar selection or by manual input.

## Usage

```jsx
<DateTimePickerControl
	onChange={ ( date ) => console.log( date ) }
	dateFormat="DD-MM-YYYY H:MM"
/>
```

### Props

| Name             | Type     | Default             | Description                                                           |
| ---------------- | -------- | ------------------- | --------------------------------------------------------------------- |
| `currentDate`    | String   | `null`              | A date in ISO format to be used as the initially set date             |
| `dateTimeFormat` | String   | `MM/DD/YYYY h:mm a` | The format used for the datetime                                      |
| `disabled`       | Boolean  | `null`              | Whether the input is disabled                                         |
| `is12Hour`       | Boolean  | `true`              | Whether the date time picker should show a 12 or 24 hour format       |
| `onChange`       | Function | `undefined`         | (required) A function called upon selection of a date or input change |
| `popoverProps`   | Object   | `{}`                | Props that will be sent to the Dropdown component                     |
</file>

<file path="packages/js/components/src/display-state/display-state.tsx">
import { createElement } from '@wordpress/element';
⋮----
export type DisplayStateProps = {
	state?: 'visible' | 'visually-hidden' | 'hidden';
	children: React.ReactNode;
} & React.HTMLAttributes< HTMLDivElement >;
</file>

<file path="packages/js/components/src/display-state/index.ts">

</file>

<file path="packages/js/components/src/dropdown-button/stories/index.story.js">
export const Basic = () => (
	<Dropdown
		renderToggle={ ( { isOpen, onToggle } ) => (
			<DropdownButton
				onClick={ onToggle }
				isOpen={ isOpen }
				labels={ [ 'All products Sold' ] }
			/>
		) }
		renderContent={ () => <p>Dropdown content here</p> }
	/>
);
</file>

<file path="packages/js/components/src/dropdown-button/index.js">
const DropdownButton = ( props ) =>
</file>

<file path="packages/js/components/src/dropdown-button/README.md">
DropdownButton
===

A button useful for a launcher of a dropdown component. The button is 100% width of its container and displays single or multiple lines rendered as `<span/>` elements.

## Usage

```jsx
<Dropdown
	renderToggle={ ( { isOpen, onToggle } ) => (
		<DropdownButton
			onClick={ onToggle }
			isOpen={ isOpen }
			labels={ [ 'All products Sold' ] }
		/>
	) }
	renderContent={ () => (
		<p>Dropdown content here</p>
	) }
/>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`labels` | Array | `null` | (required) An array of elements to be rendered as the content of the button
`isOpen` | Boolean | `null` | Boolean describing if the dropdown in open or not
</file>

<file path="packages/js/components/src/dynamic-form/field-types/field-checkbox.tsx">
import { CheckboxControl } from '@wordpress/components';
import { createElement } from '@wordpress/element';
⋮----
import { ControlProps } from '../types';
⋮----
export const CheckboxField = ( {
	field,
	onChange,
	...props
}: ControlProps ) =>
⋮----
onChange=
</file>

<file path="packages/js/components/src/dynamic-form/field-types/field-password.tsx">
import { createElement } from '@wordpress/element';
⋮----
import { TextField } from './field-text';
import { ControlProps } from '../types';
⋮----
export const PasswordField = ( props: ControlProps ) =>
</file>

<file path="packages/js/components/src/dynamic-form/field-types/field-select.tsx">
import { createElement, useMemo } from '@wordpress/element';
⋮----
import SelectControl from '../../select-control';
import { ControlProps } from '../types';
⋮----
type SelectControlOption = {
	key: string;
	label: string;
	value: { id: string };
};
⋮----
const transformOptions = ( options: Record< string, string > )
⋮----
export const SelectField = (
</file>

<file path="packages/js/components/src/dynamic-form/field-types/field-text.tsx">
import { createElement } from '@wordpress/element';
⋮----
import TextControl from '../../text-control';
import { ControlProps } from '../types';
⋮----
export const TextField = ( {
	field,
	type = 'text',
	...props
}: ControlProps & {
	type?: string;
} ) =>
</file>

<file path="packages/js/components/src/dynamic-form/field-types/index.ts">

</file>

<file path="packages/js/components/src/dynamic-form/stories/index.story.js">
const getField = ( fieldId )
⋮----
const validate = ( values ) =>
⋮----
const DynamicExample = () =>
⋮----
export const Basic = ()
</file>

<file path="packages/js/components/src/dynamic-form/dynamic-form.tsx">
import { createElement, useMemo } from '@wordpress/element';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
import { Form } from '../form';
import {
	TextField,
	PasswordField,
	CheckboxField,
	SelectField,
} from './field-types';
⋮----
import { Field, FormInputProps } from './types';
⋮----
type DynamicFormProps = {
	fields: Field[] | { [ key: string ]: Field };
	validate: ( values: Record< string, string > ) => Record< string, string >;
	isBusy?: boolean;
	onSubmit?: ( values: Record< string, string > ) => void;
	onChange?: (
		value: { name: string; value: unknown },
		values: Record< string, string >,
		result: boolean
	) => void;
	submitLabel?: string;
};
⋮----
const getInitialConfigValues = ( fields: Field[] )
⋮----
onClick=
... (1 lines truncated)
</file>

<file path="packages/js/components/src/dynamic-form/index.js">

</file>

<file path="packages/js/components/src/dynamic-form/README.md">
# DynamicForm

A component to handle form state and provide input helper props.

## Usage

```jsx
const initialValues = { firstName: '' };

<DynamicForm
	fields={ fields }
	onSubmit={ ( values ) => {
		setSubmitted( values );
	} }
	isBusy={ false }
	onChange={ () => {} }
	validate={ () => ( {} ) }
	submitLabel="Submit"
/>;
```

### Props

| Name          | Type     | Default   | Description                                                                                                                                                             |
| ------------- | -------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fields`      | {} or [] | []        | An object to describe the structure and types of all fields, matching the structure returned by the [Settings API](https://developer.woocommerce.com/docs/settings-api/) |
| `isBusy`      | Boolean  | false     | Boolean indicating busy state of submit button                                                                                                                          |
| `onSubmit`    | Function | `noop`    | Function to call when a form is submitted with valid fields                                                                                                             |
| `onChange`    | Function | `noop`    | Function to call when any values on the form are changed                                                                                                                |
| `validate`    | Function | `noop`    | A function that is passed a list of all values and should return an `errors` object with error response                                                                 |
... (13 lines truncated)
</file>

<file path="packages/js/components/src/dynamic-form/types.ts">
import { Option } from '../select-control/types';
⋮----
export type Field = {
	id: string;
	type: 'text' | 'password' | 'checkbox' | 'select';
	title: string;
	label: string;
	description?: string;
	default?: string;
	class?: string;
	css?: string;
	options?: Record< string, string >;
	tip?: string;
	value?: string;
	placeholder?: string;
};
⋮----
export type FormInputProps = React.InputHTMLAttributes< HTMLInputElement > & {
	onChange: ( value: string | boolean | Option[] ) => void;
	onBlur?: () => void;
};
⋮----
export type ControlProps = FormInputProps & {
	field: Field;
};
</file>

<file path="packages/js/components/src/ellipsis-menu/stories/ellipsis-menu.story.js">
const ExampleEllipsisMenu = () =>
⋮----
export const Basic = ()
</file>

<file path="packages/js/components/src/ellipsis-menu/index.tsx">
import type { ComponentProps } from 'react';
import { createElement } from '@wordpress/element';
import clsx from 'clsx';
import { Button, Dropdown, NavigableMenu } from '@wordpress/components';
import { Icon } from '@wordpress/icons';
import Ellipsis from 'gridicons/dist/ellipsis';
import { MouseEvent, KeyboardEvent, ReactNode } from 'react';
⋮----
type CallbackProps = {
	isOpen?: boolean;
	onToggle: () => void;
	onClose?: () => void;
};
⋮----
type EllipsisMenuProps = {
	label: string;
	renderContent?: ( props: CallbackProps ) => ReactNode | JSX.Element;
	className?: string;
	onToggle?: ( e: MouseEvent | KeyboardEvent ) => void;
	placement?: ComponentProps<
		typeof Dropdown
	>[ 'popoverProps' ][ 'placement' ];
	focusOnMount?: ComponentProps< typeof Dropdown >[ 'focusOnMount' ];
};
⋮----
const renderEllipsis = ( {
		onToggle: toggleHandlerOverride,
		isOpen,
}: CallbackProps ) =>
⋮----
... (13 lines truncated)
</file>

<file path="packages/js/components/src/ellipsis-menu/menu-item.tsx">
import { BaseControl, FormToggle } from '@wordpress/components';
import { createElement } from '@wordpress/element';
import { DOWN, ENTER, SPACE, UP } from '@wordpress/keycodes';
import { useRef, MouseEvent, KeyboardEvent } from 'react';
⋮----
type MenuItemProps = {
	checked?: boolean;
	children?: React.ReactNode;
	isCheckbox?: boolean;
	isClickable?: boolean;
	onInvoke: ( () => void ) | undefined;
};
⋮----
const MenuItem = ( {
	checked,
	children,
	isCheckbox = false,
	isClickable = false,
	onInvoke = () => {},
}: MenuItemProps ) =>
⋮----
const onClick = ( event: MouseEvent< HTMLDivElement > ) =>
⋮----
const onKeyDown = ( event: KeyboardEvent< HTMLDivElement > ) =>
</file>

<file path="packages/js/components/src/ellipsis-menu/menu-title.tsx">
import { createElement } from '@wordpress/element';
⋮----
const MenuTitle = ( {
	children,
}: {
	children: React.ReactNode;
} ) =>
</file>

<file path="packages/js/components/src/ellipsis-menu/README.md">
# EllipsisMenu

## EllipsisMenu

This is a dropdown menu hidden behind a vertical ellipsis icon. When clicked, the inner MenuItems are displayed.

### Usage

```jsx
<EllipsisMenu label="Choose which analytics to display"
	renderContent={ ( { onToggle } )=> {
		return (
			<div>
				<MenuTitle>Display stats</MenuTitle>
				<MenuItem onInvoke={ () => setState( { showCustomers: ! showCustomers } ) }>
					<ToggleControl
						label="Show Customers"
						checked={ showCustomers }
						onChange={ () => setState( { showCustomers: ! showCustomers } ) }
					/>
				</MenuItem>
				<MenuItem onInvoke={ () => setState( { showOrders: ! showOrders } ) }>
					<ToggleControl
						label="Show Orders"
						checked={ showOrders }
						onChange={ () => setState( { showOrders: ! showOrders } ) }
					/>
				</MenuItem>
				<MenuItem onInvoke={ onToggle }>
					<Button
... (68 lines truncated)
</file>

<file path="packages/js/components/src/empty-content/stories/empty-content.story.js">
export const Basic = () => (
	<EmptyContent
		title="Nothing here"
		message="Some descriptive text"
		actionLabel="Reload page"
		actionURL="#"
	/>
);
</file>

<file path="packages/js/components/src/empty-content/index.js">
class EmptyContent extends Component
⋮----
renderIllustration()
⋮----
renderActionButtons( type )
⋮----
renderActions()
⋮----
render()
</file>

<file path="packages/js/components/src/empty-content/README.md">
EmptyContent
===

A component to be used when there is no data to show.
It can be used as an opportunity to provide explanation or guidance to help a user progress.

## Usage

```jsx
<EmptyContent
	title="Nothing here"
	message="Some descriptive text"
	actionLabel="Reload page"
	actionURL="#"
/>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`title` | String | `null` | (required) The title to be displayed
`message` | String | `null` | An additional message to be displayed
`illustration` | String | `'/empty-content.svg'` | The url string of an image path. Prefix with `/` to load an image relative to the plugin directory
`illustrationHeight` | Number | `null` | Height to use for the illustration
`illustrationWidth` | Number | `400` | Width to use for the illustration
`actionLabel` | String | `null` | (required) Label to be used for the primary action button
`actionURL` | String | `null` | URL to be used for the primary action button
`actionCallback` | Function | `null` | Callback to be used for the primary action button
`secondaryActionLabel` | String | `null` | Label to be used for the secondary action button
... (4 lines truncated)
</file>

<file path="packages/js/components/src/error-boundary/stories/error-boundary.story.tsx">
import React, { createElement } from '@wordpress/element';
import { Meta, StoryFn } from '@storybook/react-webpack5';
⋮----
import { ErrorBoundary, ErrorBoundaryProps } from '../';
⋮----
const ChildComponent = () =>
⋮----
const Template: StoryFn< ErrorBoundaryProps > = ( args ) => (
	<ErrorBoundary { ...args }>
		<ChildComponent />
	</ErrorBoundary>
);
</file>

<file path="packages/js/components/src/error-boundary/constants.ts">

</file>

<file path="packages/js/components/src/error-boundary/index.tsx">
import { createElement } from '@wordpress/element';
import { Component, ReactNode, ErrorInfo } from 'react';
import { __ } from '@wordpress/i18n';
⋮----
import EmptyContent from '../empty-content';
import { alertIcon } from './constants';
⋮----
export type ErrorBoundaryProps = {
	children: ReactNode;
	errorMessage?: ReactNode;
	showActionButton?: boolean;
	actionLabel?: string;
	actionCallback?: ( error: Error ) => void;
	resetErrorAfterAction?: boolean;
	onError?: ( error: Error, errorInfo: ErrorInfo ) => void;
};
⋮----
type ErrorBoundaryState = {
	hasError: boolean;
	error: Error | null;
	errorInfo: ErrorInfo | null;
};
⋮----
constructor( props: ErrorBoundaryProps )
⋮----
static getDerivedStateFromError(
		error: Error
): Partial< ErrorBoundaryState >
⋮----
componentDidCatch( _error: Error, errorInfo: ErrorInfo )
... (1 lines truncated)
</file>

<file path="packages/js/components/src/experimental-select-control/hooks/use-async-filter.tsx">
import { Spinner } from '@wordpress/components';
import { useDebounce } from '@wordpress/compose';
import { useCallback, useState, createElement } from '@wordpress/element';
⋮----
import { SelectControlProps } from '../select-control';
import { SuffixIcon } from '../suffix-icon';
</file>

<file path="packages/js/components/src/experimental-select-control/stories/select-control.story.tsx">
import {
	Button,
	CheckboxControl,
	Modal,
	SlotFillProvider,
	Spinner,
} from '@wordpress/components';
import { useCallback } from 'react';
⋮----
import { createElement, useState } from '@wordpress/element';
import { tag } from '@wordpress/icons';
⋮----
import { SelectedType, DefaultItemType, getItemLabelType } from '../types';
import { MenuItem } from '../menu-item';
import {
	SelectControl,
	selectControlStateChangeTypes,
	useAsyncFilter,
} from '../';
import { Menu, MenuSlot } from '../menu';
import { SuffixIcon } from '../suffix-icon';
⋮----
Selected:
⋮----
onSelect=
⋮----
const [ selected, setSelected ] = useState< DefaultItemType[] >( [
		sampleItems[ 0 ],
		sampleItems[ 2 ],
	] );
... (36 lines truncated)
</file>

<file path="packages/js/components/src/experimental-select-control/combo-box.tsx">
import { createElement, MouseEvent, useRef, forwardRef } from 'react';
import clsx from 'clsx';
import { Icon, chevronDown } from '@wordpress/icons';
⋮----
type ComboBoxProps = {
	children?: React.ReactNode | null;
	comboBoxProps: JSX.IntrinsicElements[ 'div' ];
	inputProps: JSX.IntrinsicElements[ 'input' ];
	getToggleButtonProps?: () => Omit<
		JSX.IntrinsicElements[ 'button' ],
		'ref'
	>;
	suffix?: JSX.Element | null;
	showToggleButton?: boolean;
};
⋮----
const maybeFocusInput = ( event: MouseEvent< HTMLDivElement > ) =>
⋮----
className=
</file>

<file path="packages/js/components/src/experimental-select-control/index.ts">

</file>

<file path="packages/js/components/src/experimental-select-control/menu-item.tsx">
import { createElement, CSSProperties, ReactElement } from 'react';
import clsx from 'clsx';
import { Tooltip } from '@wordpress/components';
⋮----
import { getItemPropsType } from './types';
⋮----
export type MenuItemProps< ItemType > = {
	index: number;
	isActive: boolean;
	item: ItemType;
	children: ReactElement | string;
	getItemProps: getItemPropsType< ItemType >;
	activeStyle?: CSSProperties;
	tooltipText?: string;
	className?: string;
};
⋮----
export const MenuItem = < ItemType, >( {
	children,
	getItemProps,
	index,
	isActive,
	activeStyle = { backgroundColor: '#bde4ff' },
	item,
	tooltipText,
	className,
}: MenuItemProps< ItemType > ) =>
⋮----
function renderListItem()
⋮----
... (2 lines truncated)
</file>

<file path="packages/js/components/src/experimental-select-control/menu.tsx">
import { Popover } from '@wordpress/components';
import clsx from 'clsx';
import {
	createElement,
	useEffect,
	useRef,
	createPortal,
	Children,
	useLayoutEffect,
} from '@wordpress/element';
⋮----
import { getMenuPropsType } from './types';
⋮----
type PopoverProps = React.ComponentProps< typeof Popover >;
type MenuProps = {
	children?: JSX.Element | JSX.Element[];
	getMenuProps: getMenuPropsType;
	isOpen: boolean;
	className?: string;
	position?: PopoverProps[ 'position' ];
	scrollIntoViewOnOpen?: boolean;
};
⋮----
className={ clsx(
							'woocommerce-experimental-select-control__popover-menu-container',
							className
						) }
onMouseUp=
⋮----
export const MenuSlot = ()
... (1 lines truncated)
</file>

<file path="packages/js/components/src/experimental-select-control/README.md">
SelectControl
===

A component that allows searching and selection of one or more items, providing accessibility for item and menu interaction.

## Usage

`SelectControl` expects an array of item objects with `value` and `label` properties by default, with the option of passing your own ItemType to the component. Using the `getItemLabel` and `getItemValue` props will allow you to pass a function to determine the respective label and value used and customize this object's shape.

```jsx
const [ selected, setSelected ] = useState< SelectedType >( [] );

const items = [
	{ value: 'item-1', label: 'Item 1' },
	{ value: 'item-2', label: 'Item 2' },
];

<SelectControl
    multiple
    items={ items }
    label="My select control"
    selected={ selected }
    onSelect={ ( item ) => item && setSelected( [ ...selected, item ] ) }
    onRemove={ () => setSelected( selected.filter( ( i ) => i !== item ) ) }
/>
```

And with a Custom Type to describe the item shape:

```jsx
... (81 lines truncated)
</file>

<file path="packages/js/components/src/experimental-select-control/select-control.tsx">
import clsx from 'clsx';
import {
	useCombobox,
	UseComboboxState,
	UseComboboxStateChangeOptions,
	useMultipleSelection,
	GetInputPropsOptions,
} from 'downshift';
import { useInstanceId } from '@wordpress/compose';
import {
	useState,
	useEffect,
	createElement,
	Fragment,
	useRef,
} from '@wordpress/element';
import { chevronDown } from '@wordpress/icons';
⋮----
import {
	ChildrenType,
	DefaultItemType,
	getItemLabelType,
	getItemValueType,
} from './types';
import { SelectedItems } from './selected-items';
import { ComboBox } from './combo-box';
import { Menu } from './menu';
import { MenuItem } from './menu-item';
import { SuffixIcon } from './suffix-icon';
import {
... (52 lines truncated)
</file>

<file path="packages/js/components/src/experimental-select-control/selected-items.tsx">
import clsx from 'clsx';
import {
	createElement,
	forwardRef,
	useImperativeHandle,
	useRef,
} from '@wordpress/element';
import { decodeEntities } from '@wordpress/html-entities';
⋮----
import Tag from '../tag';
import {
	getItemLabelType,
	getItemValueType,
	SelectedItemFocusHandle,
} from './types';
⋮----
type SelectedItemsProps< ItemType > = {
	isReadOnly: boolean;
	items: ItemType[];
	getItemLabel: getItemLabelType< ItemType >;
	getItemValue: getItemValueType< ItemType >;
	getSelectedItemProps: ( { selectedItem: any, index: any } ) => {
		[ key: string ]: string;
	};
⋮----
const focusSibling = ( event: React.KeyboardEvent< HTMLDivElement > ) =>
⋮----
onKeyDown=
</file>

<file path="packages/js/components/src/experimental-select-control/suffix-icon.tsx">
import { createElement } from 'react';
import { Icon } from '@wordpress/icons';
import clsx from 'clsx';
⋮----
type SuffixIconProps = {
	icon: JSX.Element;
	className?: string;
};
⋮----
export const SuffixIcon = (
⋮----
className=
</file>

<file path="packages/js/components/src/experimental-select-control/types.ts">
import {
	UseComboboxGetItemPropsOptions,
	UseComboboxGetMenuPropsOptions,
	GetPropsCommonOptions,
} from 'downshift';
⋮----
export type DefaultItemType = {
	label: string;
	value: string | number;
};
⋮----
export type SelectedType< ItemType > = ItemType | null;
⋮----
export type Props = {
	[ key: string ]: any;
};
⋮----
export type getItemPropsType< ItemType > = (
	options: UseComboboxGetItemPropsOptions< ItemType >
) => any;
⋮----
export type getMenuPropsType = (
	options?: UseComboboxGetMenuPropsOptions,
	otherOptions?: GetPropsCommonOptions
) => any;
⋮----
export type ChildrenProps< ItemType > = {
	items: ItemType[];
	isOpen: boolean;
	highlightedIndex: number;
... (24 lines truncated)
</file>

<file path="packages/js/components/src/experimental-select-control/utils.ts">
import { getItemLabelType, DefaultItemType } from './types';
⋮----
function isDefaultItemType< ItemType >(
	item: ItemType | DefaultItemType | null
): item is DefaultItemType
⋮----
export const defaultGetItemLabel = < ItemType >( item: ItemType | null ) =>
⋮----
export const defaultGetItemValue = < ItemType >( item: ItemType | null ) =>
⋮----
export const defaultGetFilteredItems = < ItemType >(
	allItems: ItemType[],
	inputValue: string,
	selectedItems: ItemType[],
	getItemLabel: getItemLabelType< ItemType >
) =>
</file>

<file path="packages/js/components/src/experimental-select-tree-control/stories/select-tree-control.story.tsx">
import { createElement, useState } from 'react';
⋮----
import { Button, Modal, SlotFillProvider } from '@wordpress/components';
⋮----
import { SelectTree } from '../select-tree';
import { Item } from '../../experimental-tree-control/types';
import { SelectTreeMenuSlot } from '../select-tree-menu';
⋮----
const filterItems = ( items: Item[], searchValue ) =>
⋮----
// eslint-disable-next-line no-alert
⋮----
onInputChange=
⋮----
onRemove=
⋮----
Selected:
<Button onClick=
⋮----
// eslint-disable-next-line no-alert
⋮----
// eslint-disable-next-line no-alert
</file>

<file path="packages/js/components/src/experimental-select-tree-control/index.ts">

</file>

<file path="packages/js/components/src/experimental-select-tree-control/select-tree-menu.tsx">
import { Popover, Spinner } from '@wordpress/components';
import clsx from 'clsx';
import {
	createElement,
	useEffect,
	useRef,
	useLayoutEffect,
	useState,
} from '@wordpress/element';
import { escapeRegExp } from 'lodash';
⋮----
import {
	LinkedTree,
	Tree,
	TreeControlProps,
} from '../experimental-tree-control';
⋮----
type PopoverProps = React.ComponentProps< typeof Popover >;
type MenuProps = {
	isEventOutside: ( event: React.SyntheticEvent ) => boolean;
	isOpen: boolean;
	isLoading?: boolean;
	position?: PopoverProps[ 'position' ];
	scrollIntoViewOnOpen?: boolean;
	highlightedIndex?: number;
	items: LinkedTree[];
	treeRef?: React.ForwardedRef< HTMLOListElement >;
	onClose?: () => void;
} & Omit< TreeControlProps, 'items' >;
⋮----
... (4 lines truncated)
</file>

<file path="packages/js/components/src/experimental-select-tree-control/select-tree.tsx">
import { chevronDown, chevronUp, closeSmall } from '@wordpress/icons';
import clsx from 'clsx';
import {
	createElement,
	useEffect,
	useState,
	Fragment,
	useRef,
} from '@wordpress/element';
import { useInstanceId } from '@wordpress/compose';
import { BaseControl, Button, TextControl } from '@wordpress/components';
import { decodeEntities } from '@wordpress/html-entities';
import { __ } from '@wordpress/i18n';
import { speak } from '@wordpress/a11y';
⋮----
import {
	toggleNode,
	createLinkedTree,
	getVisibleNodeIndex as getVisibleNodeIndex,
	getNodeDataByIndex,
} from '../experimental-tree-control/linked-tree-utils';
import {
	Item,
	LinkedTree,
	TreeControlProps,
} from '../experimental-tree-control/types';
import { SelectedItems } from '../experimental-select-control/selected-items';
import { ComboBox } from '../experimental-select-control/combo-box';
import { SuffixIcon } from '../experimental-select-control/suffix-icon';
import { SelectTreeMenu } from './select-tree-menu';
... (40 lines truncated)
</file>

<file path="packages/js/components/src/experimental-tree-control/hooks/use-expander.ts">
import { useEffect, useState } from 'react';
⋮----
import { TreeItemProps } from '../types';
⋮----
export function useExpander( {
	shouldItemBeExpanded,
	item,
}: Pick< TreeItemProps, 'shouldItemBeExpanded' | 'item' > )
⋮----
function onExpand()
⋮----
function onCollapse()
⋮----
function onToggleExpand()
</file>

<file path="packages/js/components/src/experimental-tree-control/hooks/use-highlighter.ts">
import { useMemo } from 'react';
⋮----
import { CheckedStatus, TreeItemProps } from '../types';
⋮----
export function useHighlighter( {
	item,
	multiple,
	checkedStatus,
	shouldItemBeHighlighted,
}: Pick< TreeItemProps, 'item' | 'multiple' | 'shouldItemBeHighlighted' > & {
	checkedStatus: CheckedStatus;
} )
</file>

<file path="packages/js/components/src/experimental-tree-control/hooks/use-keyboard.ts">
import { LinkedTree } from '../types';
⋮----
function getFirstChild(
	currentHeading: HTMLDivElement
): HTMLLabelElement | null
⋮----
function getFirstAncestor(
	currentHeading: HTMLDivElement
): HTMLLabelElement | null
⋮----
function getAllHeadings(
	currentHeading: HTMLDivElement
): NodeListOf< HTMLDivElement > | undefined
⋮----
function getNextFocusableElement(
	currentHeading: HTMLDivElement,
	code: 'ArrowDown' | 'ArrowUp'
): HTMLLabelElement | null
⋮----
function getFirstFocusableElement(
	currentHeading: HTMLDivElement
): HTMLLabelElement | null
⋮----
function getLastFocusableElement(
	currentHeading: HTMLDivElement
): HTMLLabelElement | null
⋮----
export function useKeyboard( {
	item,
	isExpanded,
... (18 lines truncated)
</file>

<file path="packages/js/components/src/experimental-tree-control/hooks/use-selection.ts">
import { useMemo } from 'react';
⋮----
import { CheckedStatus, Item, LinkedTree, TreeItemProps } from '../types';
⋮----
function getDeepChildren( item: LinkedTree )
⋮----
function isIndeterminate(
	selectedItems: Record< string, number >,
	children?: LinkedTree[],
	memo: Record< string, boolean > = indeterminateMemo
): boolean
⋮----
function mapSelectedItems(
	selected: Item | Item[] = []
): Record< string, number >
⋮----
function hasSelectedSibblingChildren(
	children: LinkedTree[],
	values: Item[],
	selectedItems: Record< string, number >
)
⋮----
export function useSelection( {
	item,
	multiple,
	shouldNotRecursivelySelect,
	selected,
	level,
	index,
	onSelect,
... (19 lines truncated)
</file>

<file path="packages/js/components/src/experimental-tree-control/hooks/use-tree-item.ts">
import { useInstanceId } from '@wordpress/compose';
⋮----
import { TreeItemProps } from '../types';
import { useExpander } from './use-expander';
import { useHighlighter } from './use-highlighter';
import { useKeyboard } from './use-keyboard';
import { useSelection } from './use-selection';
⋮----
export function useTreeItem( {
	item,
	level,
	multiple,
	shouldNotRecursivelySelect,
	selected,
	index,
	getLabel,
	shouldItemBeExpanded,
	shouldItemBeHighlighted,
	onSelect,
	onRemove,
	isExpanded,
	onCreateNew,
	shouldShowCreateButton,
	onLastItemLoop,
	onFirstItemLoop,
	onTreeBlur,
	onEscape,
	highlightedIndex,
	isHighlighted,
	onExpand,
... (3 lines truncated)
</file>

<file path="packages/js/components/src/experimental-tree-control/hooks/use-tree.ts">
import { TreeProps } from '../types';
⋮----
export function useTree( {
	items,
	level = 1,
	role = 'listbox',
	multiple,
	selected,
	getItemLabel,
	shouldItemBeExpanded,
	shouldItemBeHighlighted,
	onSelect,
	onRemove,
	shouldNotRecursivelySelect,
	createValue,
	onTreeBlur,
	onCreateNew,
	shouldShowCreateButton,
	onFirstItemLoop,
	onEscape,
	highlightedIndex,
	onExpand,
	...props
}: TreeProps )
</file>

<file path="packages/js/components/src/experimental-tree-control/stories/tree-control.story.tsx">
import interpolate from '@automattic/interpolate-components';
import { BaseControl, TextControl } from '@wordpress/components';
import { createElement, useCallback, useRef, useState } from 'react';
⋮----
import { TreeControl } from '../tree-control';
import { Item, LinkedTree } from '../types';
⋮----
export const SimpleTree = () =>
⋮----
function shouldItemBeExpanded( item: LinkedTree, filter: string )
⋮----
shouldItemBeExpanded( item, filter )
⋮----
const [ text, setText ] = useState( '' );
⋮----
shouldItemBeExpanded=
⋮----
shouldItemBeExpanded={ useCallback(
						( item ) => shouldItemBeExpanded( item, text ),
						[ text ]
					) }
shouldItemBeHighlighted=
</file>

<file path="packages/js/components/src/experimental-tree-control/typings/global.d.ts">
interface Props {
			indeterminate?: boolean;
		}
</file>

<file path="packages/js/components/src/experimental-tree-control/index.ts">

</file>

<file path="packages/js/components/src/experimental-tree-control/linked-tree-utils.ts">
import { AugmentedItem, Item, LinkedTree } from './types';
⋮----
type MemoItems = {
	[ value: AugmentedItem[ 'value' ] ]: LinkedTree;
};
⋮----
const shouldItemBeExpanded = (
	item: LinkedTree,
	createValue: string | undefined
): boolean =>
⋮----
function findChildren(
	items: AugmentedItem[],
	memo: MemoItems = {},
	parent?: AugmentedItem[ 'parent' ],
	createValue?: string | undefined
): LinkedTree[]
⋮----
function populateIndexes(
	linkedTree: LinkedTree[],
	startCount = 0
): LinkedTree[]
⋮----
function populate( tree: LinkedTree[] ): number
⋮----
export function createLinkedTree(
	items: Item[],
	value: string | undefined
): LinkedTree[]
⋮----
... (19 lines truncated)
</file>

<file path="packages/js/components/src/experimental-tree-control/tree-control.tsx">
import { createElement, forwardRef } from 'react';
⋮----
import { createLinkedTree } from './linked-tree-utils';
import { Tree } from './tree';
import { TreeControlProps } from './types';
</file>

<file path="packages/js/components/src/experimental-tree-control/tree-item.tsx">
import { Button, CheckboxControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { chevronDown, chevronUp } from '@wordpress/icons';
import clsx from 'clsx';
import { createElement, forwardRef } from 'react';
import { decodeEntities } from '@wordpress/html-entities';
⋮----
import { useTreeItem } from './hooks/use-tree-item';
import { Tree } from './tree';
import { TreeItemProps } from './types';
⋮----
function handleKeyDown( event: React.KeyboardEvent< HTMLElement > )
⋮----
className=
⋮----
selection.onSelectChild( event.target.checked )
⋮----
? __( 'Collapse', 'woocommerce' )
</file>

<file path="packages/js/components/src/experimental-tree-control/tree.tsx">
import { Button, Icon } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import clsx from 'clsx';
import { createElement, forwardRef, Fragment, useRef } from 'react';
import { plus } from '@wordpress/icons';
import { useMergeRefs } from '@wordpress/compose';
⋮----
import { useTree } from './hooks/use-tree';
import { TreeItem } from './tree-item';
import { TreeProps } from './types';
import { countNumberOfNodes } from './linked-tree-utils';
⋮----
props.onCreateNew();
</file>

<file path="packages/js/components/src/experimental-tree-control/types.ts">
export interface Item {
	parent?: string;
	value: string;
	label: string;
}
⋮----
export type AugmentedItem = Item & {
	isExpanded: boolean;
};
⋮----
export interface LinkedTree {
	parent?: LinkedTree;
	data: AugmentedItem;
	children: LinkedTree[];
	index?: number;
}
⋮----
export type CheckedStatus = 'checked' | 'unchecked' | 'indeterminate';
⋮----
type BaseTreeProps = {
	selected?: Item | Item[];
	onExpand?( index: number, value: boolean ): void;
	highlightedIndex?: number;
	multiple?: boolean;
	shouldNotRecursivelySelect?: boolean;
	createValue?: string;
	onCreateNew?: () => void;
	shouldShowCreateButton?( value?: string ): boolean;
	isExpanded?: boolean;
	onSelect?( value: Item | Item[] ): void;
... (67 lines truncated)
</file>

<file path="packages/js/components/src/filter-picker/stories/filter-picker.story.js">
showFilters: ()
⋮----
export const Basic = ( {
	path = new URL( document.location ).searchParams.get( 'path' ),
} ) =>
</file>

<file path="packages/js/components/src/filter-picker/index.js">
class FilterPicker extends Component
⋮----
componentDidUpdate(
⋮----
updateSelectedTag( tags )
⋮----
getFilter( value )
⋮----
getButtonLabel( selectedFilter )
⋮----
getVisibleFilters( filters, nav )
⋮----
selectSubFilter( value )
⋮----
goBack()
⋮----
getAllFilterParams()
⋮----
const getParam = ( filters ) =>
⋮----
update( value, additionalQueries =
⋮----
onTagChange( filter, onClose, config, tags )
⋮----
renderButton( filter, onClose, config )
⋮----
const selectFilter = ( event ) =>
⋮----
const onClick = ( event ) =>
⋮----
... (6 lines truncated)
</file>

<file path="packages/js/components/src/filter-picker/README.md">
Filter Picker
===

Modify a url query parameter via a dropdown selection of configurable options. This component manipulates the `filter` query parameter.

## Usage

```jsx
import { FilterPicker } from '@woocommerce/components';

const renderFilterPicker = () => {
	const config = {
		label: 'Meal',
		staticParams: [],
		param: 'meal',
		showFilters: function showFilters() {
			return true;
		},
		filters: [
			{ label: 'Breakfast', value: 'breakfast' },
			{
				label: 'Lunch',
				value: 'lunch',
				subFilters: [
					{ label: 'Meat', value: 'meat', path: [ 'lunch' ] },
					{ label: 'Vegan', value: 'vegan', path: [ 'lunch' ] },
					{ 
						label: 'Pescatarian',
						value: 'fish',
						path: [ 'lunch' ],
... (53 lines truncated)
</file>

<file path="packages/js/components/src/filters/stories/filters.story.js">
showFilters: ()
⋮----
getLabels: ()
⋮----
getLabels()
⋮----
export const Examples = () => (
	<div>
		<H>Date picker only</H>
		<Section component={ false }>
			<ReportFilters
				path={ path }
				query={ query }
				storeDate={ storeDate }
			/>
		</Section>
		<H>Date picker & more filters</H>
		<Section component={ false }>
			<ReportFilters
				filters={ filters }
				path={ path }
				query={ query }
				storeDate={ storeDate }
			/>
		</Section>
		<H>Advanced filters</H>
		<Section component={ false }>
			<AdvancedFilters
				siteLocale={ siteLocale }
				path={ path }
... (13 lines truncated)
</file>

<file path="packages/js/components/src/filters/index.js">
class ReportFilters extends Component
⋮----
renderCard( config )
⋮----
onRangeSelect( data )
⋮----
getDateQuery( query )
⋮----
render()
⋮----
onDateSelect: () =>
</file>

<file path="packages/js/components/src/filters/README.md">
ReportFilters
===

Add a collection of report filters to a page. This uses `DatePicker` & `FilterPicker` for the "basic" filters, and `AdvancedFilters`
or a comparison card if "advanced" or "compare" are picked from `FilterPicker`.

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`advancedFilters` | Object | `{}` | Config option passed through to `AdvancedFilters`
`siteLocale` | string| `en_US` | The locale of the site. Passed through to `AdvancedFilters`
`currency` | object | {} | The currency of the site. Passed through to `AdvancedFilters`
`filters` | Array | `[]` | Config option passed through to `FilterPicker` - if not used, `FilterPicker` is not displayed
`path` | String | `null` | (required) The `path` parameter supplied by React-Router
`query` | Object | `{}` | The query string represented in object form
`showDatePicker` | Boolean | `true` | Whether the date picker must be shown
`onDateSelect` | Function | `() => {}` | Function to be called after date selection
`onFilterSelect` | Function | `null` | Function to be called after filter selection
`onAdvancedFilterAction` | Function | `null` | Function to be called after an advanced filter action has been taken
`storeDate` | object | `null` | (required) Date utility function object bound to store settings.
</file>

<file path="packages/js/components/src/flag/stories/flag.story.js">
export const Examples = () => (
	<div>
		<H>Default (inherits parent font size)</H>
		<Section component={ false }>
			<Flag code="VU" />
		</Section>
		<H>Large</H>
		<Section component={ false }>
			<Flag code="VU" size={ 48 } />
		</Section>
		<H>Invalid Country Code</H>
		<Section component={ false }>
			<Flag code="invalid country code" />
		</Section>
	</div>
);
</file>

<file path="packages/js/components/src/flag/index.js">
const Flag = (
</file>

<file path="packages/js/components/src/flag/README.md">
Flag
===

Use the `Flag` component to display a country's flag using the operating system's emojis.

 React component.

## Usage

```jsx
<Flag code="VU" size={ 48 } />
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`code` | String | `null` | Two letter, three letter or three digit country code
`order` | Object | `null` | An order can be passed instead of `code` and the code will automatically be pulled from the billing or shipping data
`className` | String | `null` | Additional CSS classes
`size` | Number | `null` | Supply a font size to be applied to the emoji flag
</file>

<file path="packages/js/components/src/form/stories/form.story.js">
const validate = ( values ) =>
⋮----
const onSubmit = ( values )
⋮----
export const Basic = () =>
⋮----
const handleChange = ( change, newValues ) =>
</file>

<file path="packages/js/components/src/form/form-context.ts">
import { createContext, useContext } from '@wordpress/element';
⋮----
import { FormContextType } from './types';
⋮----
export function useFormContext< Values extends Record< string, any > >()
</file>

<file path="packages/js/components/src/form/form.tsx">
import clsx from 'clsx';
import {
	useState,
	createElement,
	useCallback,
	useEffect,
	useMemo,
	forwardRef,
	useImperativeHandle,
} from '@wordpress/element';
import deprecated from '@wordpress/deprecated';
import { ChangeEvent, useRef } from 'react';
import _setWith from 'lodash/setWith';
import _get from 'lodash/get';
import _clone from 'lodash/clone';
import _toPath from 'lodash/toPath';
import _isEqual from 'lodash/isEqual';
import _isSymbol from 'lodash/isSymbol';
import _omit from 'lodash/omit';
⋮----
import { FormContext } from './form-context';
import {
	CheckboxProps,
	ConsumerInputProps,
	FormProps,
	FormRef,
	InputProps,
	PropsWithChildrenFunction,
	SelectControlProps,
	FormContextType,
... (54 lines truncated)
</file>

<file path="packages/js/components/src/form/index.ts">

</file>

<file path="packages/js/components/src/form/README.md">
# Form

A form component to handle form state and provide input helper props.

## Usage

```jsx
const initialValues = { firstName: '' };

<Form onSubmit={ ( values ) => {} } initialValues={ initialValues }>
	{ ( { getInputProps, values, errors, handleSubmit } ) => (
		<div>
			<TextControl
				label={ 'First Name' }
				{ ...getInputProps( 'firstName' ) }
			/>
			<Button
				isPrimary
				onClick={ handleSubmit }
				disabled={ Object.keys( errors ).length }
			>
				Submit
			</Button>
		</div>
	) }
</Form>;
```

## Usage with FormContext

... (59 lines truncated)
</file>

<file path="packages/js/components/src/form/types.ts">
import type { ChangeEvent } from 'react';
⋮----
export type FormErrors< Values > = {
	[ P in keyof Values ]?: FormErrors< Values[ P ] > | string;
};
⋮----
export type FormProps< Values > = {
	errors?: FormErrors< Values >;
	initialValues?: Values;
	touched?: Record< keyof Values, boolean >;
	onSubmitCallback?: ( values: Values ) => void;
	onSubmit?: ( values: Values ) => void;
	onChangeCallback?: () => void;
	onChange?: (
		value: { name: string; value: any },
		values: Values,
		isValid: boolean
	) => void;
	onChanges?: (
		changedValues: { name: string; value: any }[],
		values: Values,
		isValid: boolean
	) => void;
	validate?: ( values: Values ) => FormErrors< Values >;
};
⋮----
export type FormRef< Values > = {
	resetForm: ( initialValues: Values ) => void;
};
⋮----
... (73 lines truncated)
</file>

<file path="packages/js/components/src/form-section/stories/form-section.story.tsx">
import { Button, Card, CardBody, TextControl } from '@wordpress/components';
import { createElement } from '@wordpress/element';
⋮----
import { FormSection } from '../';
import Pill from '../../pill';
⋮----
export const Basic = () =>
⋮----
export const CustomElements = () =>
</file>

<file path="packages/js/components/src/form-section/form-section.tsx">
import { createElement } from '@wordpress/element';
import clsx from 'clsx';
⋮----
type FormSectionProps = {
	title: JSX.Element | string;
	description: JSX.Element | string;
	className?: string;
};
⋮----
export const FormSection = ( {
	title,
	description,
	className,
	children,
}: React.PropsWithChildren< FormSectionProps > ) =>
⋮----
<div className=
</file>

<file path="packages/js/components/src/form-section/index.ts">

</file>

<file path="packages/js/components/src/form-section/README.md">
FormSection
===

A layout wrapper to help align form title, description, and fields.

## Usage

```jsx
<FormSection
    title="My form section"
    description="Some text to describe what this section covers"
>
    <Card>
        <CardBody>
            My form fields
        </CardBody>
    </Card>
</FormSection>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`children` | JSX.Element | JSX.Element[] | `undefined` | The children to be rendered content area of the form section.
`description` | String | `undefined` | The description to be used beneath the section title.
`title` | String | `undefined` | The title of the form section.
</file>

<file path="packages/js/components/src/image-gallery/icons/cover-image-icon.js">
export const CoverImageIcon = () => (
	<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
		<mask id="path-1-inside-1_7913_41727" fill="white">
			<rect x="4" y="3" width="16" height="9" rx="1.11111" />
		</mask>
		<rect
			x="4"
			y="3"
			fill="none"
			width="16"
			height="9"
			rx="1.11111"
			stroke="currentColor"
			strokeWidth="3"
			mask="url(#path-1-inside-1_7913_41727)"
		/>
		<path
			d="M5 9.5L7.28571 7.83333L9 8.94444L11 7L15.25 11.25"
			stroke="currentColor"
			fill="none"
			strokeWidth="1.5"
			strokeLinejoin="round"
		/>
		<line
			x1="4"
			y1="19.25"
			x2="13"
			y2="19.25"
			stroke="currentColor"
			strokeWidth="1.5"
... (12 lines truncated)
</file>

<file path="packages/js/components/src/image-gallery/icons/index.ts">

</file>

<file path="packages/js/components/src/image-gallery/stories/image-gallery.story.tsx">
import { createElement } from '@wordpress/element';
⋮----
import { ImageGallery, ImageGalleryItem } from '../';
import { MockMediaUpload } from '../../media-uploader/stories/mock-media-uploader';
⋮----
export const Basic = () =>
⋮----
onOrderChange=
⋮----
export const Cover = () =>
⋮----
export const Columns = () =>
</file>

<file path="packages/js/components/src/image-gallery/image-gallery-item.tsx">
import { __ } from '@wordpress/i18n';
import { createElement, Fragment } from '@wordpress/element';
⋮----
import Pill from '../pill';
import { SortableHandle, NonSortableItem } from '../sortable';
import { ConditionalWrapper } from '../conditional-wrapper';
⋮----
export type ImageGalleryItemProps = {
	id?: string;
	alt: string;
	isCover?: boolean;
	isDraggable?: boolean;
	src: string;
	displayToolbar?: boolean;
	className?: string;
	onClick?: () => void;
	children?: JSX.Element;
} & React.HTMLAttributes< HTMLDivElement >;
⋮----
</file>

<file path="packages/js/components/src/image-gallery/image-gallery-toolbar-dropdown.tsx">
import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components';
import { moreVertical } from '@wordpress/icons';
import {
	Children,
	cloneElement,
	createElement,
	Fragment,
	isValidElement,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { type Attachment, MediaUpload } from '@wordpress/media-utils';
⋮----
import { MediaUploadComponentType } from './types';
⋮----
type ImageGalleryToolbarDropdownProps = {
	onReplace: ( media: { id: number } & Attachment ) => void;
	onRemove: () => void;
	canRemove?: boolean;
	removeBlockLabel?: string;
	MediaUploadComponent: MediaUploadComponentType;
	children?:
		| React.ReactNode
		| ( ( props: { onClose: () => void } ) => React.ReactNode );
};
⋮----
onReplace( media );
onClose();
⋮----
open();
⋮----
... (2 lines truncated)
</file>

<file path="packages/js/components/src/image-gallery/image-gallery-toolbar.tsx">
import { createElement } from '@wordpress/element';
import { chevronRight, chevronLeft, trash } from '@wordpress/icons';
import { type Attachment, MediaUpload } from '@wordpress/media-utils';
import { __ } from '@wordpress/i18n';
import {
	Toolbar,
	ToolbarButton,
	ToolbarGroup,
	ToolbarItem,
} from '@wordpress/components';
⋮----
import { SortableHandle } from '../sortable';
import { MediaUploadComponentType } from './types';
import { ImageGalleryToolbarDropdown } from './image-gallery-toolbar-dropdown';
⋮----
export type ImageGalleryToolbarProps = {
	childIndex: number;
	allowDragging?: boolean;
	value?: number;
	moveItem: ( fromIndex: number, toIndex: number ) => void;
	removeItem: ( removeIndex: number ) => void;
	replaceItem: (
		replaceIndex: number,
		media: { id: number } & Attachment
	) => void;
	setToolBarItem: ( key: string | null ) => void;
	lastChild: boolean;
	MediaUploadComponent: MediaUploadComponentType;
} & React.HTMLAttributes< HTMLDivElement >;
⋮----
... (14 lines truncated)
</file>

<file path="packages/js/components/src/image-gallery/image-gallery-wrapper.tsx">
import { createElement } from '@wordpress/element';
import { DragEventHandler } from 'react';
⋮----
import { Sortable } from '../sortable';
import { ImageGalleryChild } from './types';
⋮----
export type ImageGalleryWrapperProps = {
	children: JSX.Element[];
	allowDragging?: boolean;
	onDragStart?: DragEventHandler< HTMLDivElement >;
	onDragEnd?: DragEventHandler< HTMLDivElement >;
	onDragOver?: DragEventHandler< HTMLDivElement >;
	updateOrderedChildren?: ( items: ImageGalleryChild[] ) => void;
};
⋮----
updateOrderedChildren( items );
⋮----
onDragStart( event );
⋮----
onDragEnd( event );
</file>

<file path="packages/js/components/src/image-gallery/image-gallery.tsx">
import type { DragEventHandler } from 'react';
import {
	Children,
	createElement,
	cloneElement,
	useState,
	useMemo,
} from '@wordpress/element';
import clsx from 'clsx';
import { type Attachment, MediaUpload } from '@wordpress/media-utils';
⋮----
import { moveIndex } from '../sortable';
import { ImageGalleryWrapper } from './image-gallery-wrapper';
import { ImageGalleryToolbar } from './index';
import type { ImageGalleryChild, MediaUploadComponentType } from './types';
⋮----
export type ImageGalleryProps = {
	children: ImageGalleryChild | ImageGalleryChild[];
	columns?: number;
	onRemove?: ( props: {
		removeIndex: number;
		removedItem: ImageGalleryChild;
	} ) => void;
	onReplace?: ( props: {
		replaceIndex: number;
		media: { id: number } & Attachment;
	} ) => void;
	allowDragging?: boolean;
	onSelectAsCover?: ( itemId: string | null ) => void;
	onOrderChange?: ( items: ImageGalleryChild[] ) => void;
... (25 lines truncated)
</file>

<file path="packages/js/components/src/image-gallery/index.tsx">

</file>

<file path="packages/js/components/src/image-gallery/types.ts">
import type { MediaUploadComponentType } from '../media-uploader/types';
⋮----
export type ImageGalleryChild = JSX.Element;
</file>

<file path="packages/js/components/src/image-gallery/utils.ts">
import { cloneElement } from '@wordpress/element';
⋮----
export const removeItem = < T >( items: T[], removeIndex: number )
⋮----
export const replaceItem = < T extends Record< string, unknown > >(
	items: JSX.Element[],
	replaceIndex: number,
	newProps: T
) =>
</file>

<file path="packages/js/components/src/image-upload/stories/image-upload.story.js">
const ImageUploadExample = () =>
⋮----
export const Basic = ()
</file>

<file path="packages/js/components/src/image-upload/index.js">
class ImageUpload extends Component
⋮----
openModal()
⋮----
handleImageSelect()
⋮----
removeImage()
⋮----
render()
</file>

<file path="packages/js/components/src/image-upload/README.md">
ImageUpload
===

ImageUpload - Adds an upload area for selecting or uploading an image from the WordPress media gallery.

## Usage

```jsx
	<ImageUpload image={ image } onChange={ newImage => setState( { url: newImage } ) } />
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`image` | Object | `null` | Image information containing media gallery `id` and image `url`
`onChange` | Function | `null` | Function to trigger when the selected image changes
`className` | String | `null` | Additional class name to style the component
</file>

<file path="packages/js/components/src/link/stories/link.story.tsx">
import { createElement } from '@wordpress/element';
⋮----
import Link from '..';
⋮----
function logLinkClick( event )
⋮----
export const External = () =>
⋮----
export const WCAdmin = () =>
⋮----
export const WPAdmin = () =>
</file>

<file path="packages/js/components/src/link/index.tsx">
import { partial } from 'lodash';
import { createElement } from '@wordpress/element';
import { getHistory } from '@woocommerce/navigation';
⋮----
interface LinkProps {
	type?: 'wc-admin' | 'wp-admin' | 'external';
	href: string;
}
⋮----
type LinkOnClickHandlerFunction = ( ...props: any ) => any;
type LinkOnclickHandler = (
	onClick: LinkOnClickHandlerFunction | undefined,
	event: React.MouseEvent< Element > | undefined
) => void;
⋮----
export const Link = ( {
	href,
	children,
	type = 'wc-admin',
	...props
}: React.AnchorHTMLAttributes< HTMLAnchorElement > &
LinkProps ): React.ReactElement =>
⋮----
const wcAdminLinkHandler: LinkOnclickHandler = ( onClick, event ) =>
</file>

<file path="packages/js/components/src/link/README.md">
Link
===

Use `Link` to create a link to another resource. It accepts a type to automatically
create wp-admin links, wc-admin links, and external links.

## Usage

```jsx
<Link
	href="edit.php?post_type=shop_coupon"
	type="wp-admin"
>
	Coupons
</Link>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`href` | String | `null` | (required) The resource to link to
`type` | One of: 'wp-admin', 'wc-admin', 'external' | `'wc-admin'` | Type of link. For wp-admin and wc-admin, the correct prefix is appended
</file>

<file path="packages/js/components/src/list/stories/list.story.js">
function logItemClick( event )
⋮----
page: ()
⋮----
export const Default = () =>
⋮----
onClick: ( event ) =>
⋮----
export const BeforeAndAfter = () =>
⋮----
export const CustomStyleAndTags = () =>
</file>

<file path="packages/js/components/src/list/index.js">
function List( props )
</file>

<file path="packages/js/components/src/list/list-item.js">
export function handleKeyDown( event, onClick )
⋮----
function getItemLinkType( item )
⋮----
function ListItem( props )
⋮----
onKeyDown: ( e )
</file>

<file path="packages/js/components/src/list/README.md">
# List

List component to display a list of items.

## Usage

```jsx
const listItems = [
	{
		title: 'List item title',
		description: 'List item description text',
	},
	{
		before: <Gridicon icon="star" />,
		title: 'List item with before icon',
		description: 'List item description text',
	},
	{
		before: <Gridicon icon="star" />,
		after: <Gridicon icon="chevron-right" />,
		title: 'List item with before and after icons',
		description: 'List item description text',
	},
	{
		title: 'Clickable list item',
		description: 'List item description text',
		onClick: () => alert( 'List item clicked' ),
	},
];

... (31 lines truncated)
</file>

<file path="packages/js/components/src/list-item/stories/list-item.story.tsx">
import { createElement } from '@wordpress/element';
⋮----
import { ListItem } from '..';
import { Sortable } from '../../sortable';
⋮----
export const Basic = () =>
⋮----
export const Draggable = () =>
</file>

<file path="packages/js/components/src/list-item/index.ts">

</file>

<file path="packages/js/components/src/list-item/list-item.tsx">
import clsx from 'clsx';
import { createElement } from '@wordpress/element';
⋮----
import { SortableHandle } from '../sortable';
import { SortableItem, SortableItemProps } from '../sortable/sortable-item';
⋮----
export type ListItemProps = Omit< SortableItemProps, 'index' > & {
	index?: number;
};
</file>

<file path="packages/js/components/src/list-item/README.md">
ListItem
===

This component adds basic styles to list items and handles adding a handle when inside a `Sortable` container.

## Usage

You can use this list item directly and add your child content inside.

```jsx
<ListItem>
    Your content
</ListItem>
```

Or you can add this inside a sortable container to automatically add handles.

```jsx
<Sortable>
    <ListItem>Item 1 with handle</ListItem>
    <ListItem>Item 2 with handle</ListItem>
</Sortable>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`children` | JSX.Element \| JSX.Element[] \| string | `undefined` | The content to show inside the list item
`onDragEnd` | Function | `() => null` | A callback when an item is no longer being dragged
... (2 lines truncated)
</file>

<file path="packages/js/components/src/media-uploader/stories/media-uploader.story.tsx">
import { createElement } from 'react';
import { Notice } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { cloudUpload } from '@wordpress/icons';
import type { Attachment } from '@wordpress/media-utils';
⋮----
import { MediaUploader } from '../';
import { MockMediaUpload } from './mock-media-uploader';
⋮----
const mockUploadMedia = async ( {
	filesList,
	onFileChange,
}: {
	filesList: File[];
onFileChange?: ( files: Partial< Attachment >[] )
⋮----
onFileUploadChange=
⋮----
onUpload=
⋮----
onError=
</file>

<file path="packages/js/components/src/media-uploader/stories/mock-media-uploader.tsx">
import { createElement } from 'react';
import { Modal } from '@wordpress/components';
import { useState } from '@wordpress/element';
⋮----
⋮----
onSelect( {
										alt: 'Random',
										url: `https://picsum.photos/200?i=${ i }`,
									} );
setOpen( false );
event.stopPropagation();
</file>

<file path="packages/js/components/src/media-uploader/index.tsx">

</file>

<file path="packages/js/components/src/media-uploader/media-uploader.tsx">
import { __ } from '@wordpress/i18n';
import { Button, DropZone, FormFileUpload } from '@wordpress/components';
import { Fragment, createElement } from 'react';
import {
	type Attachment,
	MediaUpload,
	uploadMedia as wpUploadMedia,
} from '@wordpress/media-utils';
⋮----
import type { ErrorType, MediaUploadComponentType } from './types';
⋮----
export type MediaUploaderErrorCallback = ( error: ErrorType ) => void;
⋮----
type MediaUploaderProps = {
	allowedMediaTypes?: string[];
	buttonText?: string;
	buttonProps?: React.ComponentProps< typeof Button >;
	hasDropZone?: boolean;
	icon?: JSX.Element;
	label?: string | JSX.Element;
	maxUploadFileSize?: number;
	MediaUploadComponent?: MediaUploadComponentType;
	multipleSelect?: boolean | string;
	value?: number | number[];
	onSelect?: (
		value: ( { id: number } & { [ k: string ]: any } ) | Attachment[]
	) => void;
	onError?: MediaUploaderErrorCallback;
	onMediaGalleryOpen?: () => void;
	onUpload?: ( files: Attachment | Attachment[] ) => void;
... (37 lines truncated)
</file>

<file path="packages/js/components/src/media-uploader/README.md">
# MediaUploader

This component adds an upload button and a dropzone for uploading media to a site.

## Usage

By default this will use the functionality from `@wordpress/media-utils` which provides access and uploads to the WP media library and uses the WP media modal.

```jsx
<MediaUploader
	label={ 'Click the button below to upload' }
	onSelect={ ( file ) => setImages( [ ...images, file ] ) }
	onUpload={ ( files ) => setImages( [ ...images, ...files ] ) }
/>
```

### Props

| Name                   | Type        | Default                               | Description                                                                         |
| ---------------------- | ----------- | ------------------------------------- | ----------------------------------------------------------------------------------- |
| `allowedMediaTypes`    | String[]    | `[ 'image ]`                          | Allowed media types                                                                 |
| `buttonText`           | String      | `Choose images`                       | Text to use for button                                                              |
| `hasDropZone`          | Boolean     | `true`                                | Whether or not to allow the dropzone                                                |
| `label`                | String      | `Drag images here or click to upload` | String to use for the text shown inside the component                               |
| `MediaUploadComponent` | JSX.Element | `MediaModal`                          | The component to use for the media uploader                                         |
| `onError`              | Function    | `() => null`                          | Callback function to run when an error occurs                                       |
| `onUpload`             | Function    | `() => null`                          | Callback function to run when an upload occurs aftering dragging and dropping files |
| `onSelect`             | Function    | `() => null`                          | Callback function to run when selecting media from the opened media modal           |
</file>

<file path="packages/js/components/src/media-uploader/types.ts">
export type ErrorType = {
	code: string;
	message: string;
	file: File;
};
⋮----
export interface MediaUploadProps< T extends boolean = false > {
	addToGallery?: boolean;
	allowedTypes?: string[];
	gallery?: boolean;
	modalClass?: string;
	multiple?: T | string;
	value?: T extends true ? number[] : number;
	onSelect(
		value: T extends true
			?
			  Array< { id: number } & { [ k: string ]: any } >
			:
			  { id: number } & { [ k: string ]: any }
	): void;
	render( props: { open(): void } ): JSX.Element;
	title?: string;
}
⋮----
onSelect(
		value: T extends true
			?
			  Array< { id: number } & { [ k: string ]: any } >
			:
			  { id: number } & { [ k: string ]: any }
... (7 lines truncated)
</file>

<file path="packages/js/components/src/order-status/stories/order-status.story.js">
export const Basic = () => (
	<div>
		<OrderStatus
			order={ { status: 'processing' } }
			orderStatusMap={ orderStatusMap }
		/>
		<OrderStatus
			order={ { status: 'pending' } }
			orderStatusMap={ orderStatusMap }
		/>
		<OrderStatus
			order={ { status: 'completed' } }
			orderStatusMap={ orderStatusMap }
		/>
	</div>
);
</file>

<file path="packages/js/components/src/order-status/index.js">
const OrderStatus = ( {
	order: { status },
	className,
	orderStatusMap,
	labelPositionToLeft = false,
} ) =>
</file>

<file path="packages/js/components/src/order-status/README.md">
# OrderStatus

Use `OrderStatus` to display a badge with human-friendly text describing the current order status.

## Usage

```jsx
const order = { status: 'processing' }; // Use a real WooCommerce Order here.

<OrderStatus order={ order } />
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`order` | Object | `null` | (required) The order to display a status for. See the [Order properties documentation](https://developer.woocommerce.com/docs/apis/rest-api/v3/orders/#order-properties).
`className` | String | `null` | Additional CSS classes
`orderStatusMap` | Object | {} | A map of order status to human-friendly label.
</file>

<file path="packages/js/components/src/pagination/stories/pagination.story.js">
export const Default = ( args ) =>
⋮----
export const CustomWithHook = ( args ) =>
</file>

<file path="packages/js/components/src/pagination/index.ts">

</file>

<file path="packages/js/components/src/pagination/page-arrows-with-picker.tsx">
import { Button } from '@wordpress/components';
import { createElement, useEffect, useState } from '@wordpress/element';
import { chevronLeft, chevronRight } from '@wordpress/icons';
import { sprintf, __, isRTL } from '@wordpress/i18n';
import clsx from 'clsx';
import { uniqueId } from 'lodash';
⋮----
type PageArrowsWithPickerProps = {
	currentPage: number;
	pageCount: number;
	setCurrentPage: (
		page: number,
		action?: 'previous' | 'next' | 'goto'
	) => void;
};
⋮----
function onInputChange( event: React.FormEvent< HTMLInputElement > )
⋮----
function onInputBlur( event: React.FocusEvent< HTMLInputElement > )
⋮----
function previousPage( event: React.MouseEvent )
⋮----
function nextPage( event: React.MouseEvent )
⋮----
</file>

<file path="packages/js/components/src/pagination/page-arrows.tsx">
import { Button, Icon } from '@wordpress/components';
import { createElement } from '@wordpress/element';
import { chevronLeft, chevronRight } from '@wordpress/icons';
import { sprintf, __, isRTL } from '@wordpress/i18n';
import clsx from 'clsx';
⋮----
type PageArrowsProps = {
	currentPage: number;
	pageCount: number;
	showPageArrowsLabel?: boolean;
	setCurrentPage: (
		page: number,
		action?: 'previous' | 'next' | 'goto'
	) => void;
};
⋮----
function previousPage( event: React.MouseEvent )
⋮----
function nextPage( event: React.MouseEvent )
⋮----
<Icon icon=
</file>

<file path="packages/js/components/src/pagination/page-picker.tsx">
import { createElement, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
import { uniqueId } from 'lodash';
⋮----
type PagePickerProps = {
	currentPage: number;
	pageCount: number;
	setCurrentPage: (
		page: number,
		action?: 'previous' | 'next' | 'goto'
	) => void;
};
⋮----
function onInputChange( event: React.FormEvent< HTMLInputElement > )
⋮----
function onInputBlur( event: React.FocusEvent< HTMLInputElement > )
⋮----
function selectInputValue( event: React.MouseEvent< HTMLInputElement > )
</file>

<file path="packages/js/components/src/pagination/page-size-picker.tsx">
import { SelectControl } from '@wordpress/components';
import { createElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
⋮----
type PageSizePickerProps = {
	currentPage: number;
	perPage: number;
	total: number;
	setCurrentPage: (
		page: number,
		action?: 'previous' | 'next' | 'goto'
	) => void;
	setPerPageChange?: ( perPage: number ) => void;
	perPageOptions?: number[];
	label?: string;
};
⋮----
export function PageSizePicker( {
	perPage,
	currentPage,
	total,
	setCurrentPage,
	setPerPageChange = () => {},
	perPageOptions = DEFAULT_PER_PAGE_OPTIONS,
	label = __( 'Rows per page', 'woocommerce' ),
}: PageSizePickerProps )
⋮----
function perPageChange( newPerPage: string )
</file>

<file path="packages/js/components/src/pagination/pagination.tsx">
import { createElement } from '@wordpress/element';
import clsx from 'clsx';
⋮----
import { PageArrows } from './page-arrows';
import { PagePicker } from './page-picker';
import { DEFAULT_PER_PAGE_OPTIONS, PageSizePicker } from './page-size-picker';
⋮----
export type PaginationProps = {
	page: number;
	perPage: number;
	total: number;
	onPageChange?: (
		page: number,
		action?: 'previous' | 'next' | 'goto'
	) => void;
	onPerPageChange?: ( perPage: number ) => void;
	className?: string;
	showPagePicker?: boolean;
	showPerPagePicker?: boolean;
	showPageArrowsLabel?: boolean;
	perPageOptions?: number[];
	children?: ( props: { pageCount: number } ) => JSX.Element;
};
⋮----
export function Pagination( {
	page,
	onPageChange = () => {},
	total,
	perPage,
	onPerPageChange = () => {},
... (8 lines truncated)
</file>

<file path="packages/js/components/src/pagination/README.md">
# Pagination

Use `Pagination` to allow navigation between pages that represent a collection of items.
The component allows for selecting a new page and items per page options.

You can also make use of the `usePagination` hook and the custom components:

-   `PaginationPageArrowsWithPicker`
-   `PaginationPageArrows`
-   `PaginationPagePicker`
-   `PaginationPageSizePicker`

## Usage

```jsx
<Pagination
	page={ 1 }
	perPage={ 10 }
	total={ 500 }
	onPageChange={ ( newPage ) => setState( { page: newPage } ) }
	onPerPageChange={ ( newPerPage ) => setState( { perPage: newPerPage } ) }
/>
```

## Custom Example

```jsx
const paginationProps = usePagination( {
	totalCount: 200,
	defaultPerPage: 25,
... (33 lines truncated)
</file>

<file path="packages/js/components/src/pagination/use-pagination.ts">
import { useState } from '@wordpress/element';
⋮----
export type usePaginationProps = {
	totalCount: number;
	defaultPerPage?: number;
	onPageChange?: ( page: number ) => void;
	onPerPageChange?: ( page: number ) => void;
};
⋮----
export function usePagination( {
	totalCount,
	defaultPerPage = 25,
	onPageChange,
	onPerPageChange,
}: usePaginationProps )
</file>

<file path="packages/js/components/src/phone-number-input/stories/phone-number-input.story.tsx">
import { createElement } from '@wordpress/element';
import { useState } from 'react';
⋮----
import PhoneNumberInput from '../';
import { validatePhoneNumber } from '../validation';
⋮----
const PNI = ( {
	children,
	onChange,
	...rest
}: Partial< React.ComponentPropsWithoutRef< typeof PhoneNumberInput > > ) =>
⋮----
const handleChange = ( value, i164, country ) =>
⋮----
export const Examples = () =>
⋮----
const handleValidation = ( _, i164, country ) =>
⋮----
<pre>valid:
⋮----
arrowRender=
itemRender=
selectedRender=
</file>

<file path="packages/js/components/src/phone-number-input/data.ts">
import type { DataType } from "./types";
⋮----
const parse = ( data: any[] ): DataType
</file>

<file path="packages/js/components/src/phone-number-input/defaults.tsx">
import { createElement, Fragment } from '@wordpress/element';
import { Icon, chevronDown } from '@wordpress/icons';
⋮----
import { Country } from './utils';
</file>

<file path="packages/js/components/src/phone-number-input/index.tsx">
import {
	createElement,
	useState,
	useRef,
	useLayoutEffect,
} from '@wordpress/element';
import { useSelect } from 'downshift';
import clsx from 'clsx';
⋮----
import data from './data';
import {
	parseData,
	Country,
	sanitizeInput,
	guessCountryKey,
	numberToE164,
} from './utils';
import {
	defaultSelectedRender,
	defaultItemRender,
	defaultArrowRender,
} from './defaults';
⋮----
interface Props {
	value: string;
	onChange: ( value: string, e164: string, country: string ) => void;
	id?: string;
	className?: string;
	selectedRender?: ( country: Country ) => React.ReactNode;
	itemRender?: ( country: Country ) => React.ReactNode;
... (18 lines truncated)
</file>

<file path="packages/js/components/src/phone-number-input/README.md">
# PhoneNumberInput

An international phone number input with a country code select and a phone textfield which supports numbers, spaces and hyphens. And returns the full number as it is, in E.164 format, and the selected country alpha2.

Includes mobile phone numbers validation.

## Usage

```jsx
<PhoneNumberInput
	value={ phoneNumber }
	onChange={ ( value, e164, country ) => setState( value ) }
/>
```

### Props

| Name             | Type     | Default                 | Description                                                                                             |
| ---------------- | -------- | ----------------------- | ------------------------------------------------------------------------------------------------------- |
| `value`          | String   | `undefined`             | (Required) Phone number with spaces and hyphens                                                         |
| `onChange`       | Function | `undefined`             | (Required) Callback function when the value changes                                                     |
| `id`             | String   | `undefined`             | ID for the input element, to bind a `<label>`                                                           |
| `className`      | String   | `undefined`             | Additional class name applied to parent `<div>`                                                         |
| `selectedRender` | Function | `defaultSelectedRender` | Render function for the selected country, displays the country flag and code by default.                |
| `itemRender`     | Function | `itemRender`            | Render function for each country in the dropdown, displays the country flag, name, and code by default. |
| `arrowRender`    | Function | `defaultArrowRender`    | Render function for the dropdown arrow, displays a chevron down icon by default.                        |

### `onChange` params

-   `value`: Phone number with spaces and hyphens. e.g. `+1 234-567-8901`
... (3 lines truncated)
</file>

<file path="packages/js/components/src/phone-number-input/types.ts">
export type DataType = Record<
	string,
	{
		alpha2: string;
		code: string;
		priority: number;
		start?: string[];
		lengths?: number[];
	}
>;
</file>

<file path="packages/js/components/src/phone-number-input/utils.ts">
import type { DataType } from './types';
⋮----
const mapValues = < T, U >(
	object: Record< string, T >,
	iteratee: ( value: T ) => U
): Record< string, U > =>
⋮----
export const sanitizeNumber = ( number: string ): string
⋮----
/**
 * Removes any non-digit character, except space and hyphen.
 */
export const sanitizeInput = ( number: string ): string
⋮----
/**
 * Converts a valid phone number to E.164 format.
 */
export const numberToE164 = ( number: string ): string
⋮----
/**
 * Guesses the country code from a phone number.
 * If no match is found, it will fallback to US.
 *
 * @param number       Phone number including country code.
 * @param countryCodes List of country codes.
 * @return Country code in ISO 3166-1 alpha-2 format. e.g. US
 */
export const guessCountryKey = (
	number: string,
	countryCodes: Record< string, string[] >
... (21 lines truncated)
</file>

<file path="packages/js/components/src/phone-number-input/validation.ts">
import data from './data';
import { guessCountryKey, parseData } from './utils';
⋮----
export const validatePhoneNumber = (
	number: string,
	countryAlpha2?: string
): boolean =>
</file>

<file path="packages/js/components/src/pill/stories/pill.story.js">
export function Default()
</file>

<file path="packages/js/components/src/pill/index.js">

</file>

<file path="packages/js/components/src/pill/pill.js">
export function Pill(
</file>

<file path="packages/js/components/src/pill/README.md">
# Pill

Use `Pill` to display a pill element containing child content.

## Usage

```jsx
<Pill>Content</Pill>
```
</file>

<file path="packages/js/components/src/plugins/index.tsx">
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import {
	createElement,
	Fragment,
	useState,
	useEffect,
} from '@wordpress/element';
import { SyntheticEvent, useCallback } from 'react';
import { useDispatch, useSelect } from '@wordpress/data';
import { pluginsStore } from '@woocommerce/data';
import type { InstallPluginsResponse } from '@woocommerce/data';
⋮----
type ButtonProps = React.ComponentProps< typeof Button >;
⋮----
type PluginsProps = {
	onComplete: (
		activePlugins: string[],
		response: InstallPluginsResponse
	) => void;
	onError: ( errors: unknown, response: InstallPluginsResponse ) => void;
	onClick?: () => void;
	onSkip?: () => void;
	skipText?: string;
	autoInstall?: boolean;
	pluginSlugs?: string[];
	onAbort?: () => void;
	abortText?: string;
	installText?: string;
	installButtonVariant?: ButtonProps[ 'variant' ];
... (8 lines truncated)
</file>

<file path="packages/js/components/src/plugins/README.md">
# Plugins

Use `Plugins` to install and activate a list of plugins.

## Usage

```jsx
<Plugins
	onComplete={ this.complete }
	pluginSlugs={ [ 'jetpack', 'woocommerce-services' ] }
/>
```

### Props

| Name          | Type     | Default                                  | Description                                                               |
| ------------- | -------- | ---------------------------------------- | ------------------------------------------------------------------------- |
| `onComplete`  | Function |                                          | Called when the plugin installer is completed                             |
| `onError`     | Function |                                          | Called when the plugin installer completes with an error                  |
| `onSkip`      | Function | `noop`                                   | Called when the plugin installer is skipped                               |
| `skipText`    | String   |                                          | Text used for the skip installer button                                   |
| `autoInstall` | Boolean  | false                                    | If installation should happen automatically, or require user confirmation |
| `pluginSlugs` | Array    | `[ 'jetpack', 'woocommerce-services' ],` | An array of plugin slugs to install.                                      |
</file>

<file path="packages/js/components/src/product-fields/api/index.ts">

</file>

<file path="packages/js/components/src/product-fields/api/registration.ts">
import { select, dispatch } from '@wordpress/data';
⋮----
import { store as productFieldStore } from '../store';
import { ProductFieldDefinition } from '../store/types';
⋮----
export function registerProductField(
	fieldName: string,
	settings: ProductFieldDefinition
)
</file>

<file path="packages/js/components/src/product-fields/api/render.tsx">
import { select } from '@wordpress/data';
import { createElement } from '@wordpress/element';
import { __experimentalInputControl as InputControl } from '@wordpress/components';
⋮----
import { store as productFieldStore } from '../store';
import { ProductFieldDefinition } from '../store/types';
⋮----
export function renderField( name: string, props: Record< string, any > )
</file>

<file path="packages/js/components/src/product-fields/fields/basic-select-control/index.ts">
import { ComponentType } from 'react';
⋮----
import { ProductFieldDefinition } from '../../store/types';
import render from './render';
</file>

<file path="packages/js/components/src/product-fields/fields/basic-select-control/render.tsx">
import { createElement, Fragment } from '@wordpress/element';
import { SelectControl } from '@wordpress/components';
⋮----
import { BaseProductFieldProps } from '../types';
⋮----
type SelectControlProps = React.ComponentProps< typeof SelectControl >;
type SelectControlFieldProps = BaseProductFieldProps< string | string[] > & {
	multiple?: boolean;
	options: SelectControlProps[ 'options' ];
};
const SelectControlField = ( {
	label,
	value,
	onChange,
	multiple,
	options = [],
}: SelectControlFieldProps ) =>
</file>

<file path="packages/js/components/src/product-fields/fields/checkbox/index.ts">
import { ComponentType } from 'react';
⋮----
import { ProductFieldDefinition } from '../../store/types';
import render from './render';
</file>

<file path="packages/js/components/src/product-fields/fields/checkbox/render.tsx">
import { createElement } from '@wordpress/element';
import { CheckboxControl } from '@wordpress/components';
⋮----
import { BaseProductFieldProps } from '../types';
⋮----
type CheckboxFieldProps = BaseProductFieldProps< boolean >;
⋮----
const CheckboxField = (
</file>

<file path="packages/js/components/src/product-fields/fields/radio/index.ts">
import { ComponentType } from 'react';
⋮----
import { ProductFieldDefinition } from '../../store/types';
import render from './render';
</file>

<file path="packages/js/components/src/product-fields/fields/radio/render.tsx">
import { createElement } from '@wordpress/element';
import { RadioControl } from '@wordpress/components';
⋮----
import { BaseProductFieldProps } from '../types';
⋮----
type RadioFieldProps = BaseProductFieldProps< string > & {
	options: {
		label: string;
		value: string;
	}[];
};
const RadioField = ( {
	label,
	value,
	onChange,
	options = [],
}: RadioFieldProps ) =>
</file>

<file path="packages/js/components/src/product-fields/fields/text/index.ts">
import { ComponentType } from 'react';
⋮----
import { ProductFieldDefinition } from '../../store/types';
import render from './render';
</file>

<file path="packages/js/components/src/product-fields/fields/text/render.tsx">
import { createElement } from '@wordpress/element';
import { TextControl } from '@wordpress/components';
⋮----
import { BaseProductFieldProps } from '../types';
⋮----
type TextFieldProps = BaseProductFieldProps< string >;
⋮----
const TextField = (
</file>

<file path="packages/js/components/src/product-fields/fields/toggle/index.ts">
import { ComponentType } from 'react';
⋮----
import { ProductFieldDefinition } from '../../store/types';
import render from './render';
</file>

<file path="packages/js/components/src/product-fields/fields/toggle/render.tsx">
import { createElement, Fragment } from '@wordpress/element';
import { ToggleControl } from '@wordpress/components';
⋮----
import { BaseProductFieldProps } from '../types';
import { Tooltip } from '../../../tooltip';
⋮----
type ToggleFieldProps = BaseProductFieldProps< boolean > & {
	tooltip?: string;
};
const ToggleField = ( {
	label,
	value,
	onChange,
	tooltip,
	disabled = false,
}: ToggleFieldProps ) =>
</file>

<file path="packages/js/components/src/product-fields/fields/index.ts">
import { registerProductField } from '../api';
import { ProductFieldDefinition } from '../store/types';
import { basicSelectControlSettings } from './basic-select-control';
import { checkboxSettings } from './checkbox';
import { radioSettings } from './radio';
import { textSettings } from './text';
import { toggleSettings } from './toggle';
⋮----
const getAllProductFields = (): ProductFieldDefinition[]
⋮----
export const registerCoreProductFields = ( fields = getAllProductFields() ) =>
</file>

<file path="packages/js/components/src/product-fields/fields/types.ts">
export type BaseProductFieldProps< T > = {
	value: T;
	onChange: ( value: T ) => void;
	label: string;
	disabled?: boolean;
};
</file>

<file path="packages/js/components/src/product-fields/store/action-types.ts">
export enum TYPES {
	REGISTER_FIELD = 'REGISTER_FIELD',
}
</file>

<file path="packages/js/components/src/product-fields/store/actions.ts">
import TYPES from './action-types';
import { ProductFieldDefinition } from './types';
⋮----
export function registerProductField( field: ProductFieldDefinition )
⋮----
export type Actions = ReturnType< typeof registerProductField >;
</file>

<file path="packages/js/components/src/product-fields/store/constants.ts">

</file>

<file path="packages/js/components/src/product-fields/store/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import type { Reducer } from 'redux';
⋮----
import reducer from './reducer';
⋮----
import { STORE_NAME } from './constants';
import type { ProductFieldState } from './types';
</file>

<file path="packages/js/components/src/product-fields/store/reducer.ts">
import TYPES from './action-types';
import { Actions } from './actions';
import { ProductFieldState } from './types';
⋮----
const reducer = (
	state: ProductFieldState = {
		fields: {},
	},
	payload: Actions
) =>
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="packages/js/components/src/product-fields/store/selectors.ts">
import memoize from 'memoize-one';
⋮----
import { ProductFieldState } from './types';
⋮----
export function getProductField( state: ProductFieldState, name: string )
</file>

<file path="packages/js/components/src/product-fields/store/types.ts">
import { ComponentType, HTMLInputTypeAttribute } from 'react';
⋮----
export type ProductFieldDefinition = {
	name: string;
	type?: HTMLInputTypeAttribute;
	render?: ComponentType;
	attributes?: Record< string, string >;
};
⋮----
export type ProductFieldState = {
	fields: Record< string, ProductFieldDefinition >;
};
</file>

<file path="packages/js/components/src/product-fields/stories/product-fields.story.tsx">
import { useState, createElement } from '@wordpress/element';
import { createRegistry, RegistryProvider } from '@wordpress/data';
⋮----
import { store } from '../store';
import { renderField } from '../api';
import { registerCoreProductFields } from '../fields';
⋮----
const RenderField = () =>
⋮----
const handleChange = ( event ) =>
⋮----
export const Basic = () =>
</file>

<file path="packages/js/components/src/product-fields/index.ts">

</file>

<file path="packages/js/components/src/product-fields/README.md">
# Product Fields

Product Fields are used within the WooCommerce Admin product editor, for rendering new fields using PHP.

## Example

```js
// product-field.js
( function ( element ) {
	const el = element.createElement;

	registerProductField( 'number', {
		name: 'number',
		render: () => {
			return <InputControl type="number" />;
		},
	} );
} )( window.wp.element );
```

## API

### registerProductField

Registers a new product field provided a unique name and an object defining its
behavior.

_Usage_

```js
... (17 lines truncated)
</file>

<file path="packages/js/components/src/product-image/stories/product-image.story.tsx">
import { ProductImage } from '@woocommerce/components';
import { createElement } from '@wordpress/element';
⋮----
export const Basic = () => (
	<div>
		<ProductImage product={ null } />
		<ProductImage product={ { images: [] } } />
		<ProductImage
			product={ {
				images: [
					{
						src: 'https://cldup.com/6L9h56D9Bw.jpg',
					},
				],
			} }
		/>
	</div>
);
</file>

<file path="packages/js/components/src/product-image/index.tsx">
import clsx from 'clsx';
import { get } from 'lodash';
import { createElement } from '@wordpress/element';
⋮----
import { placeholderWhiteBackground as placeholder } from './placeholder';
⋮----
type Image = {
	src?: string;
	alt?: string;
};
⋮----
type ProductImageProps = {
	product?: {
		images?: Array< Image >;
		image?: Image;
	} & Record< string, any >;
	width?: number | string;
	height?: number | string;
	className?: string;
	alt?: string;
	style?: React.CSSProperties;
};
⋮----
const ProductImage: React.VFC< ProductImageProps > = ( {
	product,
	width = 33,
	height = 'auto',
	className = '',
	alt,
	...props
... (4 lines truncated)
</file>

<file path="packages/js/components/src/product-image/placeholder.tsx">

</file>

<file path="packages/js/components/src/product-image/README.md">
# ProductImage

Use `ProductImage` to display a product's or variation's featured image.
If no image can be found, a placeholder matching the front-end image
placeholder will be displayed.

## Usage

```jsx
// Use a real WooCommerce Product here.
const product = {
	images: [
		{
			src: 'https://cldup.com/6L9h56D9Bw.jpg',
		},
	],
};

<ProductImage product={ product } />
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`width` | Number | `60` | The width of image to display
`height` | Number | `60` | The height of image to display
`className` | String | `''` | Additional CSS classes
`product` | Object | `null` | Product or variation object. The image to display will be pulled from `product.images` or `variation.image`. See [Product properties](https://developer.woocommerce.com/docs/apis/rest-api/v3/products/#product-properties) and [Product variation properties](https://developer.woocommerce.com/docs/apis/rest-api/v3/product-variations/#product-variation-properties).
`alt` | String | `null` | Text to use as the image alt attribute
... (1 lines truncated)
</file>

<file path="packages/js/components/src/progress-bar/stories/progress-bar.story.tsx">
import { ProgressBar } from '@woocommerce/components';
import { createElement } from '@wordpress/element';
</file>

<file path="packages/js/components/src/progress-bar/index.tsx">
import { HTMLAttributes, createElement } from 'react';
⋮----
type ProgressBarProps = {
	className?: string;
	percent?: number;
	color?: string;
	bgcolor?: string;
};
⋮----
export const ProgressBar = ( {
	className = '',
	percent = 0,
	color = '#674399',
	bgcolor = 'var(--wp-admin-theme-color)',
}: ProgressBarProps ) =>
</file>

<file path="packages/js/components/src/rating/stories/rating.story.tsx">
import { createElement } from '@wordpress/element';
⋮----
import Rating from '..';
⋮----
export const Default = ( args ) => <Rating
</file>

<file path="packages/js/components/src/rating/index.tsx">
import { __, sprintf } from '@wordpress/i18n';
import clsx from 'clsx';
import { createElement } from '@wordpress/element';
import StarIcon from 'gridicons/dist/star';
⋮----
type RatingProps = {
	rating?: number;
	totalStars?: number;
	size?: number;
	className?: string;
	icon?: React.ReactNode;
	outlineIcon?: React.ReactNode;
};
</file>

<file path="packages/js/components/src/rating/product.tsx">
import { createElement } from '@wordpress/element';
⋮----
import Rating from './index';
⋮----
export type ProductRatingProps = {
	product: {
		average_rating?: number;
	};
};
⋮----
export default function ProductRating( {
	product,
	...props
}: ProductRatingProps )
</file>

<file path="packages/js/components/src/rating/README.md">
# Rating

Use `Rating` to display a set of stars, filled, empty or half-filled, that represents a
rating in a scale between 0 and the prop `totalStars` (default 5).

## Usage

```jsx
<Rating rating={ 2.5 } totalStars={ 6 } />
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`rating` | Number | `0` | Number of stars that should be filled. You can pass a partial number of stars like `2.5`
`totalStars` | Number | `5` | The total number of stars the rating is out of
`size` | Number | `18` | The size in pixels the stars should be rendered at
`className` | String | `null` | Additional CSS classes


## ProductRating

Display a set of stars representing the product's average rating.

### Usage

```jsx
// Use a real WooCommerce Product here.
const product = { average_rating: 3.5 };
... (30 lines truncated)
</file>

<file path="packages/js/components/src/rating/review.tsx">
import { createElement } from '@wordpress/element';
⋮----
import Rating from './index';
⋮----
type ReviewRatingProps = {
	review: {
		rating?: number;
	};
};
⋮----
export default function ReviewRating( {
	review,
	...props
}: ReviewRatingProps )
</file>

<file path="packages/js/components/src/scroll-to/stories/scroll-to.story.js">
export const Basic = () => (
	<ScrollTo>
		<div>
			Have the web browser automatically scroll to this component on page
			render.
		</div>
	</ScrollTo>
);
</file>

<file path="packages/js/components/src/scroll-to/index.js">
class ScrollTo extends Component
⋮----
componentDidMount()
⋮----
scrollTo()
⋮----
render()
</file>

<file path="packages/js/components/src/scroll-to/README.md">
ScrollTo
===



## Usage

```jsx
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`offset` | String | ``'0'`` | The offset from the top of the component
</file>

<file path="packages/js/components/src/search/autocompleters/attributes.tsx">
import { __ } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import interpolateComponents from '@automattic/interpolate-components';
import { createElement } from '@wordpress/element';
⋮----
import { computeSuggestionMatch } from './utils';
import { AutoCompleter } from './types';
⋮----
options( search )
⋮----
getOptionIdentifier( attribute )
getOptionKeywords( attribute )
</file>

<file path="packages/js/components/src/search/autocompleters/categories.tsx">
import { __ } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import interpolateComponents from '@automattic/interpolate-components';
import { createElement } from '@wordpress/element';
⋮----
import { computeSuggestionMatch } from './utils';
import { AutoCompleter } from './types';
⋮----
options( search )
⋮----
getOptionIdentifier( category )
getOptionKeywords( cat )
</file>

<file path="packages/js/components/src/search/autocompleters/countries.tsx">
import { decodeEntities } from '@wordpress/html-entities';
import { createElement, Fragment } from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';
import { Country } from '@woocommerce/data';
⋮----
import { computeSuggestionMatch } from './utils';
import Flag from '../../flag';
import { AutoCompleter } from './types';
⋮----
const isCountries = ( value: unknown ): value is Country[] =>
⋮----
options()
getOptionIdentifier( country )
getSearchExpression( query )
getOptionKeywords( country )
</file>

<file path="packages/js/components/src/search/autocompleters/coupons.tsx">
import { __ } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import interpolateComponents from '@automattic/interpolate-components';
import { createElement } from '@wordpress/element';
⋮----
import { computeSuggestionMatch } from './utils';
import { AutoCompleter } from './types';
⋮----
options( search )
⋮----
getOptionIdentifier( coupon )
getOptionKeywords( coupon )
</file>

<file path="packages/js/components/src/search/autocompleters/customer-names.tsx">
import { __ } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import interpolateComponents from '@automattic/interpolate-components';
import { createElement } from '@wordpress/element';
⋮----
import { computeSuggestionMatch } from './utils';
import { AutoCompleter } from './types';
⋮----
options( name )
⋮----
getOptionIdentifier( customer )
getOptionKeywords( customer )
</file>

<file path="packages/js/components/src/search/autocompleters/customers.tsx">
import customerNames from './customer-names';
import { AutoCompleter } from './types';
</file>

<file path="packages/js/components/src/search/autocompleters/download-ips.tsx">
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import { createElement } from '@wordpress/element';
⋮----
import { computeSuggestionMatch } from './utils';
import { AutoCompleter } from './types';
⋮----
options( match )
⋮----
getOptionIdentifier( download )
getOptionKeywords( download )
getOptionLabel( download, query )
getOptionCompletion( download )
</file>

<file path="packages/js/components/src/search/autocompleters/emails.tsx">
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import { createElement } from '@wordpress/element';
⋮----
import { computeSuggestionMatch } from './utils';
import { AutoCompleter } from './types';
⋮----
options( search )
⋮----
getOptionIdentifier( customer )
getOptionKeywords( customer )
getOptionLabel( customer, query )
⋮----
getOptionCompletion( customer )
</file>

<file path="packages/js/components/src/search/autocompleters/index.ts">

</file>

<file path="packages/js/components/src/search/autocompleters/orders.tsx">
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import { createElement } from '@wordpress/element';
⋮----
import { computeSuggestionMatch } from './utils';
import { AutoCompleter } from './types';
⋮----
options( search )
⋮----
getOptionIdentifier( order )
getOptionKeywords( order )
getOptionLabel( order, query )
getOptionCompletion( order )
</file>

<file path="packages/js/components/src/search/autocompleters/product.tsx">
import { __ } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import { createElement, Fragment } from '@wordpress/element';
import interpolateComponents from '@automattic/interpolate-components';
⋮----
import { computeSuggestionMatch } from './utils';
import ProductImage from '../../product-image';
import { AutoCompleter } from './types';
⋮----
options( search )
⋮----
getOptionIdentifier( product )
getOptionKeywords( product )
</file>

<file path="packages/js/components/src/search/autocompleters/registered-customers.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';
import { decodeEntities } from '@wordpress/html-entities';
import apiFetch from '@wordpress/api-fetch';
import { createElement } from '@wordpress/element';
⋮----
import { computeSuggestionMatch } from './utils';
import { AutoCompleter } from './types';
⋮----
type Customer = {
	id: number;
	name?: string;
	username?: string;
	email?: string;
};
⋮----
const getCustomerName = ( customer: Customer )
⋮----
/**
 * Get the text of a suggestion. The name is used on its own when it matches the
 * search term, otherwise the username or email that did match is appended so
 * it's clear why the customer is listed.
 *
 * @param customer Customer as returned by the API.
 * @param query    The search term.
 * @return The suggestion text.
 */
const getSuggestion = ( customer: Customer, query: string ) =>
⋮----
options( search )
... (7 lines truncated)
</file>

<file path="packages/js/components/src/search/autocompleters/taxes.tsx">
import { __ } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import interpolateComponents from '@automattic/interpolate-components';
import { createElement } from '@wordpress/element';
⋮----
import { computeSuggestionMatch, getTaxCode } from './utils';
import { AutoCompleter } from './types';
⋮----
options( search )
⋮----
getOptionIdentifier( tax )
getOptionKeywords( tax )
</file>

<file path="packages/js/components/src/search/autocompleters/types.ts">
import { ReactNode, ReactElement } from 'react';
⋮----
export type CompleterOption = any;
export type FnGetOptions = (
	query?: string
) => CompleterOption[] | Promise< CompleterOption[] >;
export type OptionCompletionValue = string | ReactElement | object;
export type OptionCompletion = {
	action: 'insert-at-caret' | 'replace';
	value: OptionCompletionValue;
};
export type FnGetOptionCompletion = (
	value: CompleterOption
) => OptionCompletion | OptionCompletionValue;
⋮----
export type AutoCompleter = {
	name: string;
	options: CompleterOption[] | FnGetOptions;
	getOptionIdentifier: ( option: CompleterOption ) => string | number;
	getOptionLabel: ( option: CompleterOption, query: string ) => ReactNode;
	getOptionCompletion: FnGetOptionCompletion;
	getOptionKeywords: ( option: CompleterOption ) => string[];
	isOptionDisabled?: ( option: CompleterOption ) => boolean;
	allowContext?: ( before: string, after: string ) => boolean;
	getFreeTextOptions?: ( query: string ) => [
		{
			key: string;
			label: JSX.Element;
			value: unknown;
		},
... (7 lines truncated)
</file>

<file path="packages/js/components/src/search/autocompleters/usernames.tsx">
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import { createElement } from '@wordpress/element';
⋮----
import { computeSuggestionMatch } from './utils';
import { AutoCompleter } from './types';
⋮----
options( search )
⋮----
getOptionIdentifier( customer )
getOptionKeywords( customer )
getOptionLabel( customer, query )
⋮----
getOptionCompletion( customer )
</file>

<file path="packages/js/components/src/search/autocompleters/utils.ts">
import { __ } from '@wordpress/i18n';
import { decodeEntities } from '@wordpress/html-entities';
⋮----
export function computeSuggestionMatch( suggestion: string, query: string )
⋮----
type Tax = Partial< {
	country: string;
	state: string;
	name: string;
	priority: number;
} >;
⋮----
export function getTaxCode( tax: Tax )
</file>

<file path="packages/js/components/src/search/autocompleters/variable-product.tsx">
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
⋮----
import productsAutocompleter from './product';
import { AutoCompleter } from './types';
⋮----
options( search )
</file>

<file path="packages/js/components/src/search/autocompleters/variations.tsx">
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
import { createElement, Fragment } from '@wordpress/element';
import { getQuery } from '@woocommerce/navigation';
⋮----
import { computeSuggestionMatch } from './utils';
import ProductImage from '../../product-image';
import { AutoCompleter } from './types';
⋮----
function getVariationName( {
	attributes,
	name,
}: {
	attributes: Array< { option: string } >;
	name: string;
} )
⋮----
options( search )
⋮----
getOptionIdentifier( variation )
getOptionKeywords( variation )
getOptionLabel( variation, query )
⋮----
getOptionCompletion( variation )
</file>

<file path="packages/js/components/src/search/stories/search.story.js">
const SearchExample = () =>
⋮----
export const Basic = ()
</file>

<file path="packages/js/components/src/search/index.tsx">
import { Search } from './search';
</file>

<file path="packages/js/components/src/search/README.md">
# Search

A search box which autocompletes results while typing, allowing for the user to select an existing object
(product, order, customer, etc). The `type` prop lists the objects that can be searched.

## Usage

```jsx
<Search
 type="products"
 placeholder="Search for a product"
 selected={ selected }
 onChange={ items => setState( { selected: items } ) }
/>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`allowFreeTextSearch` | Boolean | `false` | Render additional options in the autocompleter to allow free text entering depending on the type
`className` | String | `null` | Class name applied to parent div
`onChange` | Function | `noop` | Function called when selected results change, passed result list
`type` | One of: 'attributes', 'categories', 'countries', 'coupons', 'customerNames', 'customers', 'downloadIps', 'emails', 'orders', 'products', 'registeredCustomers', 'taxes', 'usernames', 'variableProducts', 'variations', 'custom' | `null` | (required) The object type to be used in searching
`autocompleter` | Completer | `null` | Custom [completer](https://github.com/WordPress/gutenberg/tree/trunk/packages/components/src/autocomplete#the-completer-interface) to be used in searching. Required when `type` is 'custom'
`placeholder` | String | `null` | A placeholder for the search input
`selected` | Array | `[]` | An array of objects describing selected values. If the label of the selected value is omitted, the Tag of that value will not be rendered inside the search box.
`inlineTags` | Boolean | `false` | Render tags inside input, otherwise render below input
`showClearButton` | Boolean | `false` | Render a 'Clear' button next to the input box to remove its contents
`staticResults` | Boolean | `false` | Render results list positioned statically instead of absolutely
... (22 lines truncated)
</file>

<file path="packages/js/components/src/search/search.tsx">
import { createElement, Component } from '@wordpress/element';
import { noop } from 'lodash';
import clsx from 'clsx';
⋮----
import SelectControl from '../select-control';
import type { Option } from '../select-control/types';
import {
	attributes,
	countries,
	coupons,
	customerNames,
	customers,
	downloadIps,
	emails,
	orders,
	product,
	productCategory,
	registeredCustomers,
	taxes,
	usernames,
	variableProduct,
	variations,
	type OptionCompletionValue,
} from './autocompleters';
import type { SearchProps, SearchState } from './types';
⋮----
constructor( props: SearchProps )
⋮----
getAutocompleter()
⋮----
... (12 lines truncated)
</file>

<file path="packages/js/components/src/search/types.ts">
import type { Option } from '../select-control/types';
import type { AutoCompleter, OptionCompletionValue } from './autocompleters';
⋮----
export type SearchType =
	| 'attributes'
	| 'categories'
	| 'countries'
	| 'coupons'
	| 'customerNames'
	| 'customers'
	| 'downloadIps'
	| 'emails'
	| 'orders'
	| 'products'
	| 'registeredCustomers'
	| 'taxes'
	| 'usernames'
	| 'variableProducts'
	| 'variations'
	| 'custom';
⋮----
export type SearchState = {
	options: Option[];
};
⋮----
export type SearchProps = {
	allowFreeTextSearch?: boolean;
	className?: string;
	onChange?( value: Option | OptionCompletionValue[] ): unknown;
	type: SearchType;
... (17 lines truncated)
</file>

<file path="packages/js/components/src/search-list-control/stories/search-list-control.story.js">
const SearchListControlExample = (
⋮----
export const Basic = ( args ) => <SearchListControlExample
</file>

<file path="packages/js/components/src/search-list-control/hierarchy.js">
export function buildTermsTree( filteredList, list = filteredList )
⋮----
const getParentsName = ( term =
⋮----
const fillWithChildren = ( terms ) =>
</file>

<file path="packages/js/components/src/search-list-control/index.js">
selected: ( n )
⋮----
export const SearchListControl = ( props ) =>
⋮----
const onRemove = ( id ) =>
⋮----
const isSelected = ( item )
⋮----
const getFilteredList = ( list, search ) =>
⋮----
const onSelect = ( item ) =>
⋮----
const defaultRenderItem = ( args ) =>
⋮----
const renderList = ( list, depth = 0 ) =>
⋮----
const renderListSection = () =>
⋮----
const renderSelectedSection = () =>
</file>

<file path="packages/js/components/src/search-list-control/item.js">
function getHighlightedName( name, search )
⋮----
function getBreadcrumbsForDisplay( breadcrumbs )
⋮----
const SearchListItem = ( {
	countLabel,
	className,
	depth = 0,
	controlId = '',
	item,
	isSelected,
	isSingle,
	onSelect,
	search = '',
	...props
} ) =>
</file>

<file path="packages/js/components/src/search-list-control/README.md">
SearchListControl
===

Component to display a searchable, selectable list of items.

## Usage

```jsx
<SearchListControl
	list={ list }
	isLoading={ loading }
	selected={ selected }
	onChange={ items => setState( { selected: items } ) }
/>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`className` | String | `null` | Additional CSS classes
`isHierarchical` | Boolean | `null` | Whether the list of items is hierarchical or not. If true, each list item is expected to have a parent property
`isLoading` | Boolean | `null` | Whether the list of items is still loading
`isSingle` | Boolean | `null` | Restrict selections to one item
`list` | Array | `null` | A complete list of item objects, each with id, name properties. This is displayed as a clickable/keyboard-able list, and possibly filtered by the search term (searches name)
`messages` | Object | `null` | Messages displayed or read to the user. Configure these to reflect your object type. See `defaultMessages` above for examples
`onChange` | Function | `null` | (required) Callback fired when selected items change, whether added, cleared, or removed. Passed an array of item objects (as passed in via props.list)
`onSearch` | Function | `null` | Callback fired when the search field is used
`renderItem` | Function | `null` | Callback to render each item in the selection list, allows any custom object-type rendering
`selected` | Array | `null` | (required) The list of currently selected items
... (43 lines truncated)
</file>

<file path="packages/js/components/src/section/stories/section.story.tsx">
import { H, Section } from '@woocommerce/components';
import { createElement } from '@wordpress/element';
</file>

<file path="packages/js/components/src/section/context.tsx">
import { createContext } from '@wordpress/element';
</file>

<file path="packages/js/components/src/section/header.tsx">
import { createElement, useContext } from '@wordpress/element';
⋮----
import { Level } from './context';
⋮----
export function H( props: React.HTMLAttributes< HTMLHeadingElement > )
</file>

<file path="packages/js/components/src/section/index.tsx">

</file>

<file path="packages/js/components/src/section/README.md">
H
===

These components are used to frame out the page content for accessible heading hierarchy. Instead of defining fixed heading levels
(`h2`, `h3`, …) you can use `<H />` to create "section headings", which look to the parent `<Section />`s for the appropriate
heading level.

## Usage

```jsx
<div>
	<H>Header using a contextual level (h3)</H>
	<Section component="article">
		<p>This is an article component wrapper.</p>
		<H>Another header with contextual level (h4)</H>
		<Section component={ false }>
			<p>There is no wrapper component here.</p>
			<H>This is an h5</H>
		</Section>
	</Section>
</div>
```

Section
===

The section wrapper, used to indicate a sub-section (and change the header level context).

## Usage

... (9 lines truncated)
</file>

<file path="packages/js/components/src/section/section.tsx">
import { createElement } from '@wordpress/element';
⋮----
import { Level } from './context';
⋮----
type SectionProps = {
	component?: React.ComponentType< { className?: string } > | string | false;
	className?: string;
	children: React.ReactNode;
};
⋮----
export const Section: React.VFC< SectionProps > = ( {
	component,
	children,
	...props
} ) =>
</file>

<file path="packages/js/components/src/section-header/stories/section-header.story.js">
export const Basic = () => <SectionHeader title=
</file>

<file path="packages/js/components/src/section-header/index.js">
class SectionHeader extends Component
⋮----
render()
</file>

<file path="packages/js/components/src/section-header/README.md">
SectionHeader
===

A header component. The header can contain a title, actions via children, and an `EllipsisMenu` menu.

## Usage

```jsx
<SectionHeader title="Section title" />
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`className` | String | `null` | Additional CSS classes
`menu` | (custom validator) | `null` | An `EllipsisMenu`, with filters used to control the content visible in this card
`title` | One of type: string, node | `null` | (required) The title to use for this card
</file>

<file path="packages/js/components/src/segmented-selection/stories/segmented-selection.story.js">
const SegmentedSelectionExample = () =>
⋮----
export const Basic = ()
</file>

<file path="packages/js/components/src/segmented-selection/index.js">
class SegmentedSelection extends Component
⋮----
render()
</file>

<file path="packages/js/components/src/segmented-selection/README.md">
SegmentedSelection
===

Create a panel of styled selectable options rendering stylized checkboxes and labels

## Usage

```jsx
<SegmentedSelection
	options={ [
		{ value: 'one', label: 'One' },
		{ value: 'two', label: 'Two' },
		{ value: 'three', label: 'Three' },
		{ value: 'four', label: 'Four' },
	] }
	selected={ selected }
	legend="Select a number"
	onSelect={ ( data ) => setState( { selected: data[ name ] } ) }
	name={ name }
/>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`className` | String | `null` | Additional CSS classes
`options` | Array | `null` | (required) An Array of options to render. The array needs to be composed of objects with properties `label` and `value`
`selected` | String | `null` | Value of selected item
`onSelect` | Function | `null` | (required) Callback to be executed after selection
... (10 lines truncated)
</file>

<file path="packages/js/components/src/select-control/stories/select-control.story.tsx">
import { createElement, useState } from '@wordpress/element';
⋮----
import SelectControl from '../';
⋮----
const SelectControlExample = () =>
⋮----
onChange=
⋮----
export const Basic = ()
⋮----
export const SingleSelectWithInlineTag = () =>
</file>

<file path="packages/js/components/src/select-control/control.tsx">
import { __ } from '@wordpress/i18n';
import { BACKSPACE, DOWN, UP } from '@wordpress/keycodes';
import { createElement, Component, createRef } from '@wordpress/element';
import { Icon, search } from '@wordpress/icons';
import clsx from 'clsx';
import { isArray } from 'lodash';
import {
	RefObject,
	ChangeEvent,
	FocusEvent,
	KeyboardEvent,
	InputHTMLAttributes,
} from 'react';
⋮----
import Tags from './tags';
import { Selected, Option } from './types';
⋮----
type Props = {
	hasTags?: boolean;
	help?: React.ReactNode;
	inlineTags?: boolean;
	isSearchable?: boolean;
	instanceId?: number;
	label?: string;
	listboxId?: string;
	onBlur?: () => void;
	onChange: ( selected: Option[] ) => void;
	onSearch: ( query: string ) => void;
	placeholder?: string;
	query?: string | null;
... (49 lines truncated)
</file>

<file path="packages/js/components/src/select-control/index.tsx">
import { __, _n, sprintf } from '@wordpress/i18n';
import clsx from 'clsx';
import { Component, createElement } from '@wordpress/element';
import {
	debounce,
	escapeRegExp,
	identity,
	isArray,
	isNumber,
	noop,
} from 'lodash';
import { withFocusOutside, withSpokenMessages } from '@wordpress/components';
import { withInstanceId, compose } from '@wordpress/compose';
import { ChangeEvent, InputHTMLAttributes } from 'react';
⋮----
import { Option, Selected } from './types';
import List from './list';
import Tags from './tags';
import Control from './control';
⋮----
type Props = {
	autofill?: string;
	children?: React.ReactNode;
	className?: string;
	controlClassName?: string;
	ignoreDiacritics?: boolean;
	disabled?: boolean;
	excludeSelectedOptions?: boolean;
	onFilter?: (
		options: Array< Option >,
... (94 lines truncated)
</file>

<file path="packages/js/components/src/select-control/list.tsx">
import { Button } from '@wordpress/components';
import { RefObject } from 'react';
import clsx from 'clsx';
import { createElement, Component, createRef } from '@wordpress/element';
import { isEqual, isNumber } from 'lodash';
import { ENTER, ESCAPE, UP, DOWN, LEFT, RIGHT, TAB } from '@wordpress/keycodes';
import { FixedSizeList } from 'react-window';
⋮----
import { Option } from './types';
⋮----
type Props = {
	listboxId?: string;
	instanceId: number;
	node: HTMLElement | null;
	onSelect: ( option: Option ) => void;
	options: Array< Option >;
	selectedIndex: number | null | undefined;
	staticList: boolean;
	decrementSelectedIndex: () => void;
	incrementSelectedIndex: () => void;
	onSearch: ( option: string | null ) => void;
	setExpanded: ( expanded: boolean ) => void;
	virtualScroll?: boolean;
	virtualItemHeight?: number;
	virtualListHeight?: number;
};
⋮----
const VirtualOption = ( {
	index,
	style,
... (32 lines truncated)
</file>

<file path="packages/js/components/src/select-control/README.md">
# SelectControl

A search box which filters options while typing,
allowing a user to select from an option from a filtered list.

## Usage

```jsx
const options = [
	{
		key: 'apple',
		label: 'Apple',
		value: { id: 'apple' },
	},
	{
		key: 'apricot',
		label: 'Apricot',
		value: { id: 'apricot' },
	},
];

<SelectControl
	label="Single value"
	onChange={ ( selected ) => setState( { singleSelected: selected } ) }
	options={ options }
	placeholder="Start typing to filter options..."
	selected={ singleSelected }
/>;
```

... (49 lines truncated)
</file>

<file path="packages/js/components/src/select-control/tags.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { Icon, cancelCircleFilled } from '@wordpress/icons';
import { createElement, Component, Fragment } from '@wordpress/element';
import { findIndex, isArray } from 'lodash';
⋮----
import Tag from '../tag';
import { Option, Selected } from './types';
⋮----
type Props = {
	onChange: ( selected: Option[] ) => void;
	selected?: Selected;
	showClearButton?: boolean;
};
⋮----
constructor( props: Props )
⋮----
removeAll()
⋮----
removeResult( key: string | undefined )
</file>

<file path="packages/js/components/src/select-control/types.ts">
export type Option = {
	key: string;
	label: string | React.ReactNode;
	isDisabled?: boolean;
	keywords?: Array< string >;
	value?: unknown;
};
⋮----
type SelectedOption = Omit< Option, 'label' > & {
	label: string;
};
⋮----
export type Selected = string | SelectedOption[];
</file>

<file path="packages/js/components/src/slot-context/index.ts">

</file>

<file path="packages/js/components/src/slot-context/slot-context.tsx">
import {
	createElement,
	createContext,
	useContext,
	useCallback,
	useReducer,
} from '@wordpress/element';
⋮----
type FillConfigType = {
	visible: boolean;
};
⋮----
type FillType = Record< string, FillConfigType >;
⋮----
type FillCollection = readonly ( readonly JSX.Element[] )[];
⋮----
export type SlotContextHelpersType = {
	hideFill: ( id: string ) => void;
	showFill: ( id: string ) => void;
	getFills: () => FillType;
};
⋮----
export type SlotContextType = {
	fills: FillType;
	getFillHelpers: () => SlotContextHelpersType;
	registerFill: ( id: string ) => void;
	filterRegisteredFills: ( fillsArrays: FillCollection ) => FillCollection;
};
⋮----
export const SlotContextProvider = ( {
... (12 lines truncated)
</file>

<file path="packages/js/components/src/sortable/stories/sortable.story.tsx">
import { createElement, Fragment } from '@wordpress/element';
import { DragEventHandler } from 'react';
import { Icon, wordpress } from '@wordpress/icons';
⋮----
import { Sortable, SortableHandle } from '..';
import { ListItem } from '../../list-item';
⋮----
export const Basic = () =>
⋮----
console.log(
⋮----
export const CustomHandle = () =>
⋮----
type CustomListItemProps = {
		children: React.ReactNode;
		onDragEnd?: DragEventHandler< Element >;
		onDragStart?: DragEventHandler< Element >;
	};
const CustomListItem = (
</file>

<file path="packages/js/components/src/sortable/draggable-icon.tsx">
import { createElement } from '@wordpress/element';
</file>

<file path="packages/js/components/src/sortable/index.ts">

</file>

<file path="packages/js/components/src/sortable/non-sortable-item.tsx">
import { createElement, cloneElement } from '@wordpress/element';
⋮----
type NonSortableItemProps = {
	children: JSX.Element;
};
⋮----
export const NonSortableItem = (
</file>

<file path="packages/js/components/src/sortable/README.md">
Sortable
===

This component provides a wrapper to allow dragging and sorting of items.

## Usage

This component accepts any valid JSX elements as children.  Adding a `key` to elements will provide a way to later identify the order of these elements in callbacks.

```jsx
<Sortable onOrderChange={ ( items ) => console.log( 'Items have been reordered:', items ) }>
    <div key="item-1">List item 1</div>
    <div key="item-2">List item 2</div>
    <div key="item-3">List item 3</div>
</Sortable>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`children` | JSX.Element \| JSX.Element[] | `undefined` | The draggable items in the list
`isHorizontal` | boolean | `false` | Determines if the sortable container should be droppable horizontally
`onDragEnd` | Function | `() => null` | A callback when an item is no longer being dragged
`onDragOver` | Function | `() => null` | A callback when an item is being dragged over by another item
`onDragStart` | Function | `() => null` | A callback when an item starts being dragged
`onOrderChange` | Function | `() => null` | A callback when the order of the items has been updated
</file>

<file path="packages/js/components/src/sortable/sortable-handle.tsx">
import { createElement, useContext } from '@wordpress/element';
⋮----
import { DraggableIcon } from './draggable-icon';
import { SortableContext } from './index';
import { SortableContextType } from './types';
⋮----
type SortableHandleProps = {
	children?: React.ReactNode;
	itemIndex?: number;
};
⋮----
export const SortableHandle = ( {
	children,
	itemIndex,
}: SortableHandleProps ) =>
</file>

<file path="packages/js/components/src/sortable/sortable-item.tsx">
import { __ } from '@wordpress/i18n';
import { DragEvent, useEffect } from 'react';
import clsx from 'clsx';
import { createElement, useRef, useContext } from '@wordpress/element';
import { Draggable } from '@wordpress/components';
⋮----
import { SortableContext } from './sortable';
⋮----
export type SortableItemProps = React.DetailedHTMLProps<
	React.HTMLAttributes< HTMLDivElement >,
	HTMLDivElement
> & {
	index: number;
	isDragging?: boolean;
	isSelected?: boolean;
};
⋮----
const handleDragStart = ( event: DragEvent< HTMLDivElement > ) =>
⋮----
const handleDragEnd = ( event: DragEvent< HTMLDivElement > ) =>
⋮----
className=
</file>

<file path="packages/js/components/src/sortable/sortable.tsx">
import { __, sprintf } from '@wordpress/i18n';
import clsx from 'clsx';
import {
	createElement,
	useCallback,
	useEffect,
	useRef,
	useState,
	createContext,
	cloneElement,
} from '@wordpress/element';
import { DragEvent, KeyboardEvent } from 'react';
import { speak } from '@wordpress/a11y';
import { throttle } from 'lodash';
import { v4 } from 'uuid';
⋮----
import {
	getItemName,
	getNextIndex,
	getPreviousIndex,
	isBefore,
	isDraggingOverAfter,
	isDraggingOverBefore,
	isLastDroppable,
	moveIndex,
} from './utils';
import { SortableChild } from './types';
⋮----
export type SortableProps = React.DetailedHTMLProps<
	React.HTMLAttributes< HTMLDivElement >,
... (24 lines truncated)
</file>

<file path="packages/js/components/src/sortable/types.ts">
import { DragEventHandler } from 'react';
⋮----
export type SortableChild = JSX.Element;
⋮----
export type SortableContextType = {
	onDragEnd?: DragEventHandler< HTMLDivElement >;
	onDragStart?: DragEventHandler< HTMLDivElement >;
};
</file>

<file path="packages/js/components/src/sortable/utils.ts">
import { __ } from '@wordpress/i18n';
import { DragEvent } from 'react';
⋮----
export const moveIndex = < T >(
	fromIndex: number,
	toIndex: number,
	arr: T[]
) =>
⋮----
export const isBefore = (
	event: DragEvent< HTMLDivElement >,
	isHorizontal = false
) =>
⋮----
export const isDraggingOverAfter = (
	index: number,
	dragIndex: number | null,
	dropIndex: number | null
) =>
⋮----
export const isDraggingOverBefore = (
	index: number,
	dragIndex: number | null,
	dropIndex: number | null
) =>
⋮----
export const isLastDroppable = (
	index: number,
	dragIndex: number | null,
	itemCount: number
... (11 lines truncated)
</file>

<file path="packages/js/components/src/spinner/stories/spinner.story.js">
export const Basic = () => (
	<div>
		<Spinner />
	</div>
);
</file>

<file path="packages/js/components/src/spinner/index.js">
class Spinner extends Component
⋮----
render()
</file>

<file path="packages/js/components/src/spinner/README.md">
Spinner
===

Spinner - An indeterminate circular progress indicator.

## Usage

```jsx
<Spinner />
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`className` | String | `null` | Additional class name to style the component
</file>

<file path="packages/js/components/src/stepper/stories/stepper.story.js">
const BasicExamples = () =>
⋮----
const goToStep = ( key ) =>
⋮----
export const Examples = ()
</file>

<file path="packages/js/components/src/stepper/check-icon.tsx">
import { createElement } from '@wordpress/element';
</file>

<file path="packages/js/components/src/stepper/index.tsx">
import clsx from 'clsx';
import { createElement, Fragment } from '@wordpress/element';
import type React from 'react';
⋮----
import Spinner from '../spinner';
import CheckIcon from './check-icon';
⋮----
export interface StepperProps {
	className?: string;
	currentStep: string;
	steps: Array< {
		content: React.ReactNode;
		description: string | Array< string >;
		isComplete?: boolean;
		key: string;
		label: string;
		onClick?: ( key: string ) => void;
	} >;
	isVertical?: boolean;
	isPending?: boolean;
}
⋮----
const renderCurrentStepContent = () =>
</file>

<file path="packages/js/components/src/stepper/README.md">
Stepper
===

A stepper component to indicate progress in a set number of steps.

## Usage

```jsx
const steps = [
	{
		key: 'first',
		label: 'First',
		description: 'Step item description',
		content: <div>First step content.</div>,
	},
	{
		key: 'second',
		label: 'Second',
		description: 'Step item description',
		content: <div>Second step content.</div>,
	},
];

<Stepper
	steps={ steps }
	currentStep="first"
	isPending={ true }
/>
```

... (20 lines truncated)
</file>

<file path="packages/js/components/src/summary/stories/summary.story.js">
export const Basic = () => (
	<SummaryList>
</file>

<file path="packages/js/components/src/summary/index.js">
const SummaryList = ( {
	children,
	isDropdownBreakpoint,
	label = __( 'Performance Indicators', 'woocommerce' ),
} ) =>
</file>

<file path="packages/js/components/src/summary/menu.js">
const Menu = (
</file>

<file path="packages/js/components/src/summary/number.js">
const SummaryNumber = ( {
	children,
	delta,
	href = '',
	hrefType = 'wc-admin',
	isOpen = false,
	label,
	labelTooltipText,
	onToggle,
	prevLabel = __( 'Previous period:', 'woocommerce' ),
	prevValue,
	reverseTrend = false,
	selected = false,
	value,
	onLinkClickCallback = noop,
} ) =>
</file>

<file path="packages/js/components/src/summary/placeholder.js">
export const SummaryNumberPlaceholder = ( { className } ) => (
	<li
		data-testid="summary-placeholder"
		className={ clsx(
			'woocommerce-summary__item-container is-placeholder',
			className
		) }
	>
		<div className="woocommerce-summary__item">
			<div className="woocommerce-summary__item-label" />
			<div className="woocommerce-summary__item-data">
				<div className="woocommerce-summary__item-value" />
				<div className="woocommerce-summary__item-delta" />
			</div>
		</div>
	</li>
);
⋮----
class SummaryListPlaceholder extends Component
⋮----
render()
</file>

<file path="packages/js/components/src/summary/README.md">
SummaryList
===

A container element for a list of SummaryNumbers. This component handles detecting & switching to the mobile format on smaller screens.

## Usage

```jsx
<SummaryList>
	{ () => {
		return [
			<SummaryNumber
				key="revenue"
				value={ '$829.40' }
				label="Total sales"
				delta={ 29 }
				href="/analytics/report"
			>
				<span>27 orders</span>
			</SummaryNumber>,
			<SummaryNumber
				key="refunds"
				value={ '$24.00' }
				label="Refunds"
				delta={ -10 }
				href="/analytics/report"
				selected
			/>,
		];
	} }
... (55 lines truncated)
</file>

<file path="packages/js/components/src/summary/utils.js">
export function getHasItemsClass( count )
</file>

<file path="packages/js/components/src/table/stories/empty-table.story.tsx">
import { EmptyTable } from '@woocommerce/components';
import { createElement } from '@wordpress/element';
⋮----
export const Basic = ()
</file>

<file path="packages/js/components/src/table/stories/index.ts">

</file>

<file path="packages/js/components/src/table/stories/table-card.story.tsx">
import { TableCard } from '@woocommerce/components';
import { useState, createElement } from '@wordpress/element';
import { Button, Notice } from '@wordpress/components';
⋮----
import { headers, rows, summary } from './index';
⋮----
setAction1Text( 'Action 1 Clicked' );
⋮----
export const Actions = ()
⋮----
export const TablePreface = ()
⋮----
export const WideTable = ()
</file>

<file path="packages/js/components/src/table/stories/table-placeholder.story.tsx">
import { Card } from '@wordpress/components';
import { TablePlaceholder } from '@woocommerce/components';
import { createElement } from '@wordpress/element';
⋮----
import { headers } from './index';
⋮----
export const Basic = () =>
</file>

<file path="packages/js/components/src/table/stories/table-summary-placeholder.story.tsx">
import { Card, CardFooter } from '@wordpress/components';
import { TableSummaryPlaceholder } from '@woocommerce/components';
import { createElement } from '@wordpress/element';
⋮----
export const Basic = () =>
</file>

<file path="packages/js/components/src/table/stories/table-summary.story.jsx">
export const Basic = () => (
	<Card>
		<CardFooter justify="center">
			<TableSummary data={ summary } />
		</CardFooter>
	</Card>
);
</file>

<file path="packages/js/components/src/table/stories/table.story.tsx">
import { Card } from '@wordpress/components';
import { Table } from '@woocommerce/components';
import { createElement } from '@wordpress/element';
⋮----
import { rows, headers } from './index';
⋮----
export const Basic = () => (
	<Card size="none">
		<Table
			caption="Revenue last week"
			rows={ rows }
			headers={ headers }
			rowKey={ ( row ) => row[ 0 ].value }
		/>
	</Card>
);
⋮----
export const NoDataCustomMessage = () =>
</file>

<file path="packages/js/components/src/table/empty.tsx">
import { createElement } from '@wordpress/element';
⋮----
type EmptyTableProps = {
	children: React.ReactNode;
	numberOfRows?: number;
};
⋮----
const EmptyTable = (
</file>

<file path="packages/js/components/src/table/index.tsx">
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
import { createElement, Fragment, useState } from '@wordpress/element';
import { find, first, without } from 'lodash';
import {
	Card,
	CardBody,
	CardFooter,
	CardHeader,
	__experimentalText as Text,
} from '@wordpress/components';
⋮----
import EllipsisMenu from '../ellipsis-menu';
import MenuItem from '../ellipsis-menu/menu-item';
import MenuTitle from '../ellipsis-menu/menu-title';
import { Pagination } from '../pagination';
import Table from './table';
import TablePlaceholder from './placeholder';
import TableSummary, { TableSummaryPlaceholder } from './summary';
import { TableCardProps } from './types';
⋮----
const defaultOnQueryChange: (
	param: string
) => ( path?: string, direction?: string ) => void = () => () =>
⋮----
const defaultOnColumnsChange: (
	showCols: Array< string >,
	key?: string
) => void = () =>
⋮----
... (9 lines truncated)
</file>

<file path="packages/js/components/src/table/placeholder.tsx">
import { createElement } from '@wordpress/element';
import { range } from 'lodash';
⋮----
import Table from './table';
import { QueryProps, TableHeader } from './types';
⋮----
type TablePlaceholderProps = {
	query?: QueryProps;
	caption: string;
	numberOfRows?: number;
	rowHeader?: number | false;
	headers: Array< TableHeader >;
};
⋮----
const TablePlaceholder: React.FC< TablePlaceholderProps > = ( {
	query,
	caption,
	headers,
	numberOfRows = 5,
	...props
} ) =>
</file>

<file path="packages/js/components/src/table/README.md">
# TableCard

This is an accessible, sortable, and scrollable table for displaying tabular data (like revenue and other analytics data).
It accepts `headers` for column headers, and `rows` for the table content.
`rowHeader` can be used to define the index of the row header (or false if no header).

`TableCard` serves as Card wrapper & contains a card header, `<Table />`, `<TableSummary />`, and `<Pagination />`.
This includes filtering and comparison functionality for report pages.

## Usage

```jsx
const headers = [
	{ key: 'month', label: 'Month' },
	{ key: 'orders', label: 'Orders' },
	{ key: 'revenue', label: 'Revenue' },
];
const rows = [
	[
		{ display: 'January', value: 1 },
		{ display: 10, value: 10 },
		{ display: '$530.00', value: 530 },
	],
	[
		{ display: 'February', value: 2 },
		{ display: 13, value: 13 },
		{ display: '$675.00', value: 675 },
	],
	[
		{ display: 'March', value: 3 },
... (244 lines truncated)
</file>

<file path="packages/js/components/src/table/summary.tsx">
import { createElement } from '@wordpress/element';
⋮----
import { TableSummaryProps } from './types';
⋮----
const TableSummary = (
⋮----
export const TableSummaryPlaceholder = () =>
</file>

<file path="packages/js/components/src/table/table.tsx">
import { __, sprintf } from '@wordpress/i18n';
import {
	createElement,
	useRef,
	Fragment,
	useState,
	useEffect,
} from '@wordpress/element';
import clsx from 'clsx';
import { Button } from '@wordpress/components';
import { find, get, noop } from 'lodash';
import { withInstanceId } from '@wordpress/compose';
import { Icon, chevronUp, chevronDown } from '@wordpress/icons';
import deprecated from '@wordpress/deprecated';
⋮----
import { TableRow, TableProps } from './types';
⋮----
const getDisplay = ( cell:
⋮----
const Table: React.FC< TableProps > = ( {
	instanceId,
	headers = [],
	rows = [],
	ariaHidden,
	caption,
	className,
	onSort = ( f ) => f,
	query = {},
	rowHeader,
	rowKey,
... (18 lines truncated)
</file>

<file path="packages/js/components/src/table/types.ts">
export type QueryProps = {
	orderby?: string;
	order?: string;
	page?: string;
	per_page?: number;
	paged?: number | string;
};
⋮----
export type TableHeader = {
	defaultSort?: boolean;
	defaultOrder?: string;
	isLeftAligned?: boolean;
	isNumeric?: boolean;
	isSortable?: boolean;
	key: string;
	label?: React.ReactNode;
	required?: boolean;
	screenReaderLabel?: string;
	cellClassName?: string;
	visible?: boolean;
};
⋮----
export type TableRow = {
	display?: React.ReactNode;
	value?: string | number | boolean;
};
⋮----
type CommonTableProps = {
	rowKey?: ( row: TableRow[], index: number ) => number;
	emptyMessage?: string;
... (41 lines truncated)
</file>

<file path="packages/js/components/src/tag/stories/tag.story.tsx">
import { createElement } from '@wordpress/element';
⋮----
import Tag from '../';
⋮----
remove=
</file>

<file path="packages/js/components/src/tag/index.tsx">
import { __, sprintf } from '@wordpress/i18n';
import {
	createElement,
	forwardRef,
	Fragment,
	useState,
} from '@wordpress/element';
import clsx from 'clsx';
import { Button, Popover } from '@wordpress/components';
import { Icon, closeSmall } from '@wordpress/icons';
import { decodeEntities } from '@wordpress/html-entities';
import { Ref } from 'react';
import { useInstanceId } from '@wordpress/compose';
⋮----
type Props = {
	label: string;
	id?: number | string;
	popoverContents?: React.ReactNode;
	remove?: (
		id: number | string | undefined
	) => React.MouseEventHandler< HTMLButtonElement >;
	screenReaderLabel?: string;
	className?: string;
};
⋮----
<Popover onClose=
⋮----
label=
</file>

<file path="packages/js/components/src/tag/README.md">
Tag
===

This component can be used to show an item styled as a "tag", optionally with an `X` + "remove"
or with a popover that is shown on click.



## Usage

```jsx
<Tag label="My tag" id={ 1 } />
<Tag label="Removable tag" id={ 2 } remove={ noop } />
<Tag label="Tag with popover" popoverContents={ ( <p>This is a popover</p> ) } />
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`id` | One of type: number, string | `null` | The ID for this item, used in the remove function
`label` | String | `null` | (required) The name for this item, displayed as the tag's text
`popoverContents` | ReactNode | `null` | Contents to display on click in a popover
`remove` | Function | `null` | A function called when the remove X is clicked. If not used, no X icon will display
`screenReaderLabel` | String | `null` | A more descriptive label for screen reader users. Defaults to the `name` prop
</file>

<file path="packages/js/components/src/text-control/stories/text-control.story.js">
const Example = () =>
⋮----
export const Basic = ()
</file>

<file path="packages/js/components/src/text-control/index.js">
handleFocusOutside()
⋮----
handleOnClick( event, onClick )
⋮----
render()
</file>

<file path="packages/js/components/src/text-control/README.md">
TextControl
===

An input field use for text inputs in forms.

## Usage

```jsx
<TextControl
	label="Input label"
	value={ value }
	onChange={ value => setState( { value } ) }
/>;
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`className` | String | ``null`` | Additional CSS classes
`disabled` | Boolean | ``null`` | Disables the field
`label` | String | ``null`` | Input label used as a placeholder
`onClick` | Function | ``null`` | On click handler called when the component is clicked, passed the click event
`value` | String | ``null`` | The value of the input field
</file>

<file path="packages/js/components/src/text-control-with-affixes/stories/text-control-with-affixes.story.js">
const Examples = () =>
⋮----
const partialUpdate = ( partial ) =>
⋮----
export const Basic = ()
</file>

<file path="packages/js/components/src/text-control-with-affixes/index.js">
class TextControlWithAffixes extends Component
⋮----
handleFocusOutside()
⋮----
handleOnClick( event, onClick )
⋮----
render()
⋮----
const onChangeValue = ( event )
</file>

<file path="packages/js/components/src/text-control-with-affixes/README.md">
TextControlWithAffixes
===

This component is essentially a wrapper (really a reimplementation) around the
TextControl component that adds support for affixes, i.e. the ability to display
a fixed part either at the beginning or at the end of the text input.

## Usage

```jsx
<TextControlWithAffixes
    suffix="%"
    label="Text field with a suffix"
    value={ fourth }
    onChange={ value => setState( { fourth: value } ) }
/>
<TextControlWithAffixes
    prefix="$"
    label="Text field with prefix and help text"
    value={ fifth }
    onChange={ value => setState( { fifth: value } ) }
    help="This is some help text."
/>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`label` | String | `null` | If this property is added, a label will be generated using label property as the content
... (9 lines truncated)
</file>

<file path="packages/js/components/src/timeline/stories/timeline.story.js">
export const Filled = () =>
⋮----
export const Empty = ()
</file>

<file path="packages/js/components/src/timeline/index.js">
const Timeline = ( {
	className = '',
	items = [],
	groupBy = 'day',
	orderBy = 'desc',
	dateFormat = __( 'F j, Y', 'woocommerce' ),
	clockFormat = __( 'g:ia', 'woocommerce' ),
	timezone = 'browser',
} ) =>
⋮----
const addGroupTitles = ( group ) =>
</file>

<file path="packages/js/components/src/timeline/README.md">
# Timeline

This is a timeline for displaying data, such as events, in chronological order.
It accepts `items` for the timeline content and will order the data for you.

## Usage

```jsx
import Timeline from './Timeline';
import { orderByOptions, groupByOptions } from './Timeline';
import GridIcon from 'gridicons';

const items = [
  {
    date: new Date( 2019, 9, 28, 9, 0 ),
    icon: <GridIcon icon={ 'checkmark' } />,
    headline: 'A payment of $90.00 was successfully charged',
    body: [
      <p key={ '1' }>{ 'Fee: $2.91 ( 2.9% + $0.30 )' }</p>,
      <p key={ '2' }>{ 'Net deposit: $87.09' }</p>,
    ],
  },
  {
    date: new Date( 2019, 9, 28, 9, 32 ),
    icon: <GridIcon icon={ 'plus' } />,
    headline: '$94.16 was added to your October 29, 2019 deposit',
    body: [],
  },
  {
    date: new Date( 2019, 9, 27, 20, 9 ),
... (45 lines truncated)
</file>

<file path="packages/js/components/src/timeline/timeline-group.js">
const TimelineGroup = ( {
	group = { title: '', items: [] },
	className = '',
	orderBy = 'desc',
	clockFormat,
	timezone,
} ) =>
⋮----
const itemsToTimelineItem = ( item, itemIndex ) =>
</file>

<file path="packages/js/components/src/timeline/timeline-item.js">
const TimelineItem = ( {
	item = {},
	className = '',
	clockFormat,
	timezone = 'browser',
} ) =>
</file>

<file path="packages/js/components/src/timeline/util.js">
const sortAscending = ( groupA, groupB )
const sortDescending = ( groupA, groupB )
⋮----
const sortByDateUsing = ( orderBy ) =>
⋮----
const getSiteGroupKey = ( date, groupBy )
⋮----
const getBrowserTimezone = () =>
⋮----
const formatTimelineDate = ( dateFormat, dateValue, timezone = 'browser' ) =>
⋮----
const groupItemsUsing =
( groupBy, timezone = 'browser' )
⋮----
const hasSameGroupKey = ( group, item ) =>
const groupIndexExists = ( index )
</file>

<file path="packages/js/components/src/tooltip/stories/tooltip.story.tsx">
import { createElement } from '@wordpress/element';
import { Icon, warning } from '@wordpress/icons';
⋮----
import { Tooltip } from '../';
⋮----
export const Basic = () =>
⋮----
export const CustomIcon = () =>
</file>

<file path="packages/js/components/src/tooltip/index.ts">

</file>

<file path="packages/js/components/src/tooltip/tooltip.tsx">
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
import { Button, Popover } from '@wordpress/components';
import { createElement, Fragment, useState } from '@wordpress/element';
import { KeyboardEvent } from 'react';
import { Icon, help } from '@wordpress/icons';
import { useInstanceId } from '@wordpress/compose';
⋮----
type Position =
	| 'top left'
	| 'top right'
	| 'top center'
	| 'middle left'
	| 'middle right'
	| 'middle center'
	| 'bottom left'
	| 'bottom right'
	| 'bottom center';
⋮----
type TooltipProps = {
	children?: JSX.Element | string;
	helperText?: string;
	position?: Position;
	text: JSX.Element | string;
	className?: string;
};
⋮----
<div className=
⋮----
className=
... (5 lines truncated)
</file>

<file path="packages/js/components/src/tour-kit/components/step-controls.tsx">
import { Button, Flex, Icon } from '@wordpress/components';
import { closeSmall } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
import { createElement } from '@wordpress/element';
import { TourStepRendererProps } from '@automattic/tour-kit';
⋮----
interface Props {
	onDismiss: TourStepRendererProps[ 'onDismiss' ];
}
</file>

<file path="packages/js/components/src/tour-kit/components/step-navigation.tsx">
import { Button } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { createElement } from '@wordpress/element';
⋮----
import type { WooTourStepRendererProps } from '../types';
⋮----
type Props = Omit<
	WooTourStepRendererProps,
	'onMinimize' | 'setInitialFocusedElement'
>;
⋮----
</file>

<file path="packages/js/components/src/tour-kit/components/step.tsx">
import { withViewportMatch } from '@wordpress/viewport';
import { Card, CardBody, CardFooter, CardHeader } from '@wordpress/components';
import { createElement, useEffect, useRef } from '@wordpress/element';
⋮----
import StepNavigation from './step-navigation';
import StepControls from './step-controls';
import type { WooTourStepRendererProps } from '../types';
⋮----
const getFocusElement = (
	focusElementSelector: string | null,
	iframeSelector: string | null
) =>
⋮----
const Step = ( {
	steps,
	currentStepIndex,
	onDismiss,
	onNextStep,
	onPreviousStep,
	setInitialFocusedElement,
	onGoToStep,
	isViewportMobile,
}: WooTourStepRendererProps & {
	isViewportMobile: boolean;
} ) =>
</file>

<file path="packages/js/components/src/tour-kit/stories/tour-kit.story.tsx">
import { createElement, useState } from '@wordpress/element';
⋮----
import WooTourKit from '..';
import type { WooConfig, WooOptions } from '../types';
⋮----
<button onClick=
</file>

<file path="packages/js/components/src/tour-kit/index.tsx">
import { createElement } from '@wordpress/element';
import TourKit, { TourStepRenderer, Options } from '@automattic/tour-kit';
⋮----
import TourKitStep from './components/step';
import type { WooConfig } from './types';
⋮----
interface Props {
	config: WooConfig;
}
</file>

<file path="packages/js/components/src/tour-kit/README.md">
# tour-kit

A WooCommerce Tour Kit variant based on [@automattic/tour-kit](https://github.com/Automattic/wp-calypso/blob/trunk/packages/tour-kit/README.md) for configurable guided tours. Contains some optional effects (like spotlight and overlay) that can be enabled/disabled depending on the desired use..

Uses [Popper.js](https://popper.js.org/) underneath (also customizable via tour configuration).

## Usage

A typical expected workflow builds around:

1. Define the criteria for showing a tour.
2. Define a configuration for the tour, passing along a handler for closing.
3. Render it (or not).

### Sample

```jsx
import { TourKit } from '@woocommerce/components';

function Tour() {
	// 1. Define the criteria for showing a tour:
	const [ showTour, setShowTour ] = useState( true );

	// 2. Define a configuration for the tour, passing along a handler for closing.
	const config = {
		steps: [
			{
				referenceElements: {
					desktop: '.render-step-near-me',
				},
... (90 lines truncated)
</file>

<file path="packages/js/components/src/tour-kit/types.ts">
import {
	Step,
	Options,
	Config,
	TourStepRendererProps,
} from '@automattic/tour-kit';
⋮----
export interface WooStep extends Step {
	meta: {
		name: string | null;
		heading: string | React.ReactElement | null;
		descriptions: {
			desktop: string | React.ReactElement | null;
			mobile?: string | React.ReactElement | null;
		};
		primaryButton?: {
			text?: string;
			isDisabled?: boolean;
			isHidden?: boolean;
		};
		secondaryButton?: {
			text?: string;
		};
		skipButton?: {
			text?: string;
			isVisible?: boolean;
		};
	};
	focusElement?: {
		desktop?: string;
... (15 lines truncated)
</file>

<file path="packages/js/components/src/tree-select-control/stories/tree-select-control.story.js">
const Template = ( args ) =>
</file>

<file path="packages/js/components/src/tree-select-control/checkbox.js">
const Checkbox = (
</file>

<file path="packages/js/components/src/tree-select-control/constants.js">

</file>

<file path="packages/js/components/src/tree-select-control/control.js">
/**
		 * Handles keydown event
		 *
		 * Keys:
		 * When key down is BACKSPACE. Delete the last tag.
		 *
		 * @param {Event} event Event object
		 */
const handleKeydown = ( event ) =>
⋮----
/**
			 * ESLint Disable reason
			 * https://github.com/woocommerce/woocommerce-admin/blob/main/packages/components/src/select-control/control.js#L200
			 */
/* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
</file>

<file path="packages/js/components/src/tree-select-control/index.js">
const TreeSelectControl = ( {
	id,
	label,
	selectAllLabel = __( 'All', 'woocommerce' ),
	help,
	placeholder,
	className,
	disabled,
	options = [],
	value = [],
	maxVisibleTags,
	onChange = () => {},
	onDropdownVisibilityChange = noop,
	onInputChange = noop,
	includeParent = false,
	individuallySelectParent = false,
	alwaysShowPlaceholder = false,
	minFilterQueryLength = 3,
	clearOnSelect = true,
} ) =>
⋮----
// We will save in a REF previous search filter queries to avoid re-query the tree and save performance
⋮----
// we only trigger the filter when there are more than 3 characters in the input.
⋮----
/**
	 * Optimizes the performance for getting the tags info
	 */
⋮----
// Clear cache if options change
... (120 lines truncated)
</file>

<file path="packages/js/components/src/tree-select-control/options.js">
const Options = ( {
	options = [],
	onChange = () => {},
	onExpanderClick = noop,
	onToggleExpanded = noop,
	parent = null,
} ) =>
⋮----
const handleKeyDown = ( event, option ) =>
</file>

<file path="packages/js/components/src/tree-select-control/README.md">
# Tree Select Control

A search box which filters options while typing,
allowing a user to select multiple options from a filtered list.
The main advantage of Tree Select Controls is that it allows to distribute the options in nested groups. 

## Usage

```jsx
const options = [
       {
			value: 'EU',
			label: 'Europe',
			children: [
				{ value: 'ES', label: 'Spain' },
				{ value: 'FR', label: 'France', children: [] }, // defining children as [] is equivalent to don't have children
			],
		},
		{
			value: 'NA',
			label: 'North America',
			children: [
				{ value: 'US', label: 'United States', children: [
					{ value: 'TX', label: 'Texas' },
					{ value: 'NY', label: 'New York' },
				] },
				{ value: 'CA', label: 'Canada' },
			],
		}
     ];
... (90 lines truncated)
</file>

<file path="packages/js/components/src/tree-select-control/tags.js">
const Tags = ( {
	tags = [],
	disabled,
	maxVisibleTags = 0,
	onChange = () => {},
} ) =>
⋮----
const remove = ( key ) =>
</file>

<file path="packages/js/components/src/tree-select-control/useIsEqualRefValue.js">
const useIsEqualRefValue = ( value ) =>
</file>

<file path="packages/js/components/src/view-more-list/stories/view-more-list.story.js">
export const Basic = () => (
	<ViewMoreList
		items={ [ <i>Lorem</i>, <i>Ipsum</i>, <i>Dolor</i>, <i>Sit</i> ] }
	/>
);
</file>

<file path="packages/js/components/src/view-more-list/index.js">
const ViewMoreList = (
</file>

<file path="packages/js/components/src/view-more-list/README.md">
ViewMoreList
===

This component displays a 'X more' button that displays a list of items on a popover when clicked.



## Usage

```jsx
<ViewMoreList
    items={ [ <i>Lorem</i>, <i>Ipsum</i>, <i>Dolor</i>, <i>Sit</i> ] }
/>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`items` | Array | `[]` | `ReactNodes` to list in the popover
</file>

<file path="packages/js/components/src/web-preview/stories/web-preview.story.js">
export const Basic = () => (
	<WebPreview
		src="https://themes.woocommerce.com/?name=galleria"
		title="My Web Preview"
	/>
);
</file>

<file path="packages/js/components/src/web-preview/index.js">
class WebPreview extends Component
⋮----
componentDidMount()
⋮----
setLoaded()
⋮----
render()
</file>

<file path="packages/js/components/src/web-preview/README.md">
WebPreview
===

WebPreview component to display an iframe of another page.

## Usage

```jsx
<WebPreview
    title="My Web Preview"
    src="https://themes.woocommerce.com/?name=galleria"
/>
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`className` | String | `null` | Additional class name to style the component
`loadingContent` | ReactNode | `<Spinner />` | Content shown when iframe is still loading
`onLoad` | Function | `noop` | Function to fire when iframe content is loaded
`src` | String | `null` | (required) Iframe src to load
`title` | String | `null` | (required) Iframe title
</file>

<file path="packages/js/components/src/experimental.js">

</file>

<file path="packages/js/components/src/index.ts">

</file>

<file path="packages/js/components/src/utils.tsx">
import { isValidElement, Fragment, Children } from 'react';
import { Slot, Fill } from '@wordpress/components';
import { cloneElement, createElement } from '@wordpress/element';
⋮----
type ChildrenProps = {
	order: number;
};
⋮----
type FillProps = React.ComponentProps< typeof Fill >;
type SlotProps = React.ComponentProps< typeof Slot >;
⋮----
function getChildrenAndProps< T = FillProps, S = Record< string, unknown > >(
	children:
		| React.ReactNode
		| ( ( props: T & { order: number } ) => React.ReactNode ),
	order: number,
	props: T,
	injectProps?: S
)
⋮----
function createOrderedChildren< T = FillProps, S = Record< string, unknown > >(
	children:
		| React.ReactNode
		| ( ( props: T & { order: number } ) => React.ReactNode ),
	order: number,
	props: T,
	injectProps?: S
): React.ReactNode
⋮----
export const sortFillsByOrder: SlotProps[ 'children' ] = ( fills ) =>
... (3 lines truncated)
</file>

<file path="packages/js/components/typings/global.d.ts">
interface Window {
		wcSettings?: {
			variationTitleAttributesSeparator?: string;
			countries: Record< string, string >;
		};
	}
</file>

<file path="packages/js/components/typings/index.d.ts">

</file>

<file path="packages/js/components/typings/monorepo-enhancements.d.ts">

</file>

<file path="packages/js/components/.npmrc">
package-lock=false
</file>

<file path="packages/js/components/babel.config.js">

</file>

<file path="packages/js/components/build.mjs">

</file>

<file path="packages/js/components/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [14.1.0](https://www.npmjs.com/package/@woocommerce/components/v/14.1.0) - 2026-06-26 

-   Patch - Improve summary trend indicator contrast in Analytics. [#65784]
-   Minor - Update Timeline date rendering from browser-local formatting to localized timezone-aware formatting. [#65914]

## [14.0.0](https://www.npmjs.com/package/@woocommerce/components/v/14.0.0) - 2026-06-11 

-   Major [ **BREAKING CHANGE** ] - Replace MediaItem with native Attachment from @wordpress/media-utils throughout media-uploader and image-gallery components. [#64114]
-   Major [ **BREAKING CHANGE** ] - Update @wordpress/* dependencies to WordPress 6.8 minimum. Remove @types/wordpress__media-utils and @types/wordpress__rich-text (native types at wp-6.8). [#64114]
-   Minor - Export MediaUploadProps and MediaUploadComponentType for typed MediaUpload component props (native types are `Component<any>`). [#64114]
-   Minor - Fix tax rate search in Analytics filters by using the correct `search` query parameter instead of `code` when calling the `/wc-analytics/taxes` endpoint. [#64754]
-   Minor - Improve build time for components by using webpack filesystem cache. [#64082]
-   Patch - Add __next40pxDefaultSize prop to SelectControl components to resolve deprecated size warning on WP 7.0+. [#63847]
-   Patch - Drop the trailing colon on the Date range filter label to match WordPress 7.0 form-field labeling. [#64846]
-   Patch - Fix Analytics tag popover being too narrow. [#65414]
-   Patch - Fix date range input height increase on WP 7.0 by aligning with WordPress input styling. [#63844]
-   Patch - Fix extra padding on analytics Card and CardBody components on WordPress 7.0 by setting size to "none". [#63809]
-   Patch - Fix interval selector shifting downward on WP 7.0 by restoring margin-bottom. [#63843]
-   Patch - Fix order status text wrapping vertically when Gutenberg plugin is active by adding white-space: nowrap to prevent inherited word-break styles from affecting grid min-content sizing. [#63882]
-   Patch - Fix TypeScript error in EllipsisMenu onKeyDown handler by using native KeyboardEvent type. [#62841]
-   Patch - Monorepo: address circular dependencies surfaced by SWC TDZ. [#64797]
-   Patch - Monorepo: refresh DependencyExtractionWebpackPlugin for compatibility with filesystem cache, admin build cleanup. [#64111]
-   Patch - Move the CommonJS build to prepack so day-to-day development only builds the ESM output. [#64876]
-   Patch - Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking. [#65168]
-   Patch - Prepare table component typings for React 19 compatibility. [#65401]
-   Patch - Prevent page scroll when using arrow keys in EllipsisMenu component. [#62841]
... (352 lines truncated)
</file>

<file path="packages/js/components/composer.json">
{
	"name": "woocommerce/components",
	"description": "WooCommerce JS component library",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/components/eslint.config.mjs">
/**
 * External dependencies
 */
⋮----
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/components/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/components/package.json">
{
	"name": "@woocommerce/components",
	"version": "14.1.0",
	"description": "UI components for WooCommerce.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"keywords": [
		"wordpress",
		"woocommerce",
		"components"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/components/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
... (189 lines truncated)
</file>

<file path="packages/js/components/PREVIOUS_CHANGELOG.md">
# 10.0.0

-   Replace deprecated wp.compose.withState with wp.element.useState. #8338
-   Add missing dependencies. #8349
-   Update all js packages with minor/patch version changes. #8392
-   Add moment-timezone to package.json. #6483

## Breaking changes

-   Refactor the `onFilterChange` method in the `AdvancedFilters` component. #8459
    -   change: `onFilterChange( index, property, value, shouldResetValue = false );` to `onFilterChange( index, { property, value, shouldResetValue = false } )`;

# 9.0.0

-   Update line-height of SelectControl label to avoid truncated descenders in some typefaces and zoom levels. #8186
-   Made @woocommerce/components/Stepper a Typescript file. #8286
-   Added Typescript type declarations to build for @woocommerce/components #8282

## Breaking changes

-   Update dependencies to support react 17. #8305
-   Drop support for IE11. #8305

# 8.2.0

-   Fix usage of Wordpress DatePicker component in `DatePicker`. #7982
-   Fix select-control component label/value alignment. #8045
-   Fix clicking the error message opens the dropdown. #8094
-   Fix misaligned "Rows per page" dropdown. #8113
-   Add `labelPositionToLeft` prop to the `OrderStatus` component. #8121
... (289 lines truncated)
</file>

<file path="packages/js/components/README.md">
# Components

This packages includes a library of components that can be used to create pages in the WooCommerce dashboard and reports pages.

## Installation

Install the module

```bash
pnpm install @woocommerce/components --save
```

## Usage

```jsx
/**
 * WooCommerce dependencies
 */
import { Card } from '@woocommerce/components';

export default function MyCard() {
  return (
    <Card title="Store Performance" description="Key performance metrics">
      <p>Your stuff in a Card.</p>
    </Card>
  );
}
```

Many components include CSS to add style, you will need to add in order to appear correctly. Within WooCommerce, add the `wc-components` stylesheet as a dependency of your plugin's stylesheet. See [wp_enqueue_style documentation](https://developer.wordpress.org/reference/functions/wp_enqueue_style/#parameters) for how to specify dependencies.
... (13 lines truncated)
</file>

<file path="packages/js/components/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"noCheck": false,
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**",
		"**/stories/**"
	],
	"references": [
		{
			"path": "../csv-export"
		},
		{
			"path": "../currency"
		},
... (15 lines truncated)
</file>

<file path="packages/js/components/webpack.config.js">

</file>

<file path="packages/js/create-woo-extension/changelog/.gitkeep">

</file>

<file path="packages/js/create-woo-extension/changelog/64838-dev-esbuild-package-builds">
Significance: patch
Type: dev

Removed stray wireit devDependency.
</file>

<file path="packages/js/create-woo-extension/changelog/66078-fix-scaffold-lint-clean">
Significance: patch
Type: fix

Fix ESLint errors in the default scaffolded extension: allow the extension's own text domain, skip `no-require-imports` on CommonJS config files, declare `@wordpress/components`/`@wordpress/element`, and fix the example page's undefined `setInlineSelect` handler.
</file>

<file path="packages/js/create-woo-extension/changelog/66078-fix-scaffold-npm-install">
Significance: patch
Type: fix

Pin `i18n-calypso` to 8.1.0 in scaffolded extensions so `npm install` no longer fails on an unparseable Yarn `patch:` dependency spec.
</file>

<file path="packages/js/create-woo-extension/changelog/66078-fix-scaffold-prettier-resolution">
Significance: patch
Type: fix

Pin wp-prettier in scaffolded extensions so `prettier/prettier` stops reporting WordPress code style as errors.
</file>

<file path="packages/js/create-woo-extension/changelog/66078-update-scaffold-flat-config">
Significance: minor
Type: update

Scaffold ESLint Flat Config (`eslint.config.mjs`) instead of `.eslintrc.js`, which recent ESLint versions no longer read.
</file>

<file path="packages/js/create-woo-extension/changelog/update-php-dev-dependency-security-patches">
Significance: patch
Type: dev

Update PHP development dependencies to versions that resolve reported security advisories.
</file>

<file path="packages/js/create-woo-extension/variants/add-report/includes/Admin/Setup.php.mustache">
<?php

namespace {{slugPascalCase}}\Admin;

/**
 * {{slugPascalCase}} Setup Class
 */
class Setup {
	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts' ) );
		add_filter( 'woocommerce_analytics_report_menu_items', array( $this, 'add_report_menu_item' ) );
	}

	/**
	 * Load all necessary dependencies.
	 *
	 * @since 1.0.0
	 */
	public function register_scripts() {
		if ( ! class_exists( 'Automattic\WooCommerce\Admin\PageController' ) ||
			! \Automattic\WooCommerce\Admin\PageController::is_admin_page()
		) {
			return;
		}

... (39 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/add-report/languages/woo-plugin-setup.pot.mustache">
# Copyright (C) 2022 WooCommerce
# This file is distributed under the GNU General Public License v3.0.
msgid ""
msgstr ""
"Project-Id-Version: Woo Plugin Setup 1.0.0\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/{{slug}}\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2022-11-27T21:35:18+00:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"X-Generator: WP-CLI 2.7.1\n"
"X-Domain: {{slug}}\n"

#. Plugin Name of the plugin
msgid "Woo Plugin Setup"
msgstr ""

#. Plugin URI of the plugin
msgid "https://github.com/psealock/woo-plugin-setup"
msgstr ""

#. Description of the plugin
msgid "This is an example of an extension template to follow."
msgstr ""

#. Author of the plugin
msgid "WooCommerce"
... (16 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/add-report/src/index.js.mustache">
/**
 * External dependencies
 */

import { addFilter } from '@wordpress/hooks';
import { Fragment } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
 * WooCommerce dependencies
 */
import { ReportFilters, TableCard } from '@woocommerce/components';

const Report = ( { path, query } ) => {
	return (
		<Fragment>
			<ReportFilters
				query={ query }
				path={ path }
				filters={ [] }
				advancedFilters={ {} }
			/>
			<TableCard
				title={ __( 'Example Data', '{{textdomain}}' ) }
				headers={ [
					{ label: __( 'Type', '{{textdomain}}' ), key: 'type', isLeftAligned: true, required: true },
					{ label: __( 'Color', '{{textdomain}}' ), key: 'color' },
					{ label: __( 'Taste', '{{textdomain}}' ), key: 'taste' },
				] }
				rows={ [
... (42 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/add-report/.editorconfig.mustache">
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/

root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 4
tab_width = 4
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true

[*.txt]
trim_trailing_whitespace = false

[*.{md,json,yml}]
trim_trailing_whitespace = false
indent_style = space
indent_size = 2

[*.json]
indent_style = tab
</file>

<file path="packages/js/create-woo-extension/variants/add-report/.gitignore.mustache">
# Operating System files
.DS_Store
Thumbs.db

# IDE files
.idea
.vscode/*
project.xml
project.properties
.project
.settings*
*.sublime-project
*.sublime-workspace
.sublimelinterrc

# Sass
.sass-cache/

# Logs
logs/

# Environment files
wp-cli.local.yml
yarn-error.log
npm-debug.log
.pnpm-debug.log

# Build files
*.sql
*.swp
... (32 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/add-report/.prettierrc.json.mustache">
"@wordpress/prettier-config"
</file>

<file path="packages/js/create-woo-extension/variants/add-report/.wp-env.json.mustache">
{
	"phpVersion": null,
	"core": null,
	"plugins": [
		"https://downloads.wordpress.org/plugin/woocommerce.zip",
		"."
	],
	"config": {
		"JETPACK_AUTOLOAD_DEV": true,
		"WP_DEBUG": true,
		"SCRIPT_DEBUG": true
	}
}
</file>

<file path="packages/js/create-woo-extension/variants/add-report/$slug.php.mustache">
<?php
/**
 * Plugin Name: {{title}}
{{#description}}
 * Description: {{description}}
{{/description}}
 * Version: {{version}}
{{#author}}
 * Author: {{author}}
{{/author}}
 * Author URI: https://woocommerce.com
 * Text Domain: {{textdomain}}
 * Domain Path: /languages
 *
 * License: GNU General Public License v3.0
 * License URI: http://www.gnu.org/licenses/gpl-3.0.html
 *
 * @package {{namespace}}
 */

defined( 'ABSPATH' ) || exit;

if ( ! defined( '{{slugConstantCase}}_MAIN_PLUGIN_FILE' ) ) {
	define( '{{slugConstantCase}}_MAIN_PLUGIN_FILE', __FILE__ );
}

require_once plugin_dir_path( __FILE__ ) . '/vendor/autoload_packages.php';

use {{slugPascalCase}}\Admin\Setup;

... (97 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/add-report/composer.json.mustache">
{
	"name": "{{namespace}}/{{slug}}",
	"description": "WooCommerce plugin",
	"autoload": {
		"psr-4": {
			"{{slugPascalCase}}\\": "includes/"
		}
	},
	"require-dev": {
		"phpunit/phpunit": "^9.0",
		"automattic/jetpack-autoloader": "^2"
	},
	"config": {
		"allow-plugins": {
			"automattic/jetpack-autoloader": true
		}
	}
}
</file>

<file path="packages/js/create-woo-extension/variants/add-report/eslint.config.mjs.mustache">
import woocommerce from '@woocommerce/eslint-plugin';

export default [
	...woocommerce.configs.recommended,
	{
		rules: {
			'react/react-in-jsx-scope': 'off',
			/* The scaffolded extension ships its own text domain, not WooCommerce's. */
			'@wordpress/i18n-text-domain': [
				'error',
				{ allowedTextDomain: '{{textdomain}}' },
			],
		},
	},
	{
		/* Node config files (e.g. webpack.config.js) use CommonJS require(). */
		files: [ '**/*.config.js' ],
		rules: {
			'@typescript-eslint/no-require-imports': 'off',
		},
	},
];
</file>

<file path="packages/js/create-woo-extension/variants/add-report/README.md.mustache">
# {{title}}

{{#description}}
{{description}}
{{/description}}

This is a WooCommerce extension that adds a custom report to the Analytics section.

## Development

### Getting started

1. `npm install` to install dependencies
2. `npm start` to start the development server
3. `npm run build` to build the production version

### File Structure

- `src/index.js` - Main JavaScript file that registers the custom report
- `includes/Admin/Setup.php` - PHP class that handles script registration and menu item addition
- `{{slug}}.php` - Main plugin file

## Features

- Adds a custom report page to WooCommerce Analytics
- Demonstrates how to use the `woocommerce_admin_reports_list` filter
- Shows example usage of `ReportFilters` and `TableCard` components

## Customization

... (7 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/add-report/webpack.config.js.mustache">
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
const WooCommerceDependencyExtractionWebpackPlugin = require( '@woocommerce/dependency-extraction-webpack-plugin' );

module.exports = {
	...defaultConfig,
	plugins: [
		...defaultConfig.plugins.filter(
			( plugin ) =>
				plugin.constructor.name !== 'DependencyExtractionWebpackPlugin'
		),
		new WooCommerceDependencyExtractionWebpackPlugin(),
	],
};
</file>

<file path="packages/js/create-woo-extension/variants/add-task/includes/Admin/Setup.php.mustache">
<?php

namespace {{slugPascalCase}}\Admin;

use {{slugPascalCase}}\Task;

/**
 * {{slugPascalCase}} Setup Class
 */
class Setup {
	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts' ) );
	}

	/**
	 * Register scripts to fill the task content on the frontend.
	 *
	 * @since 1.0.0
	 */
	public function register_scripts() {
		if (
			! class_exists( 'Automattic\WooCommerce\Internal\Admin\Loader' ) ||
			! \Automattic\WooCommerce\Admin\PageController::is_admin_or_embed_page()
		) {
			return;
... (24 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/add-task/includes/Task.php.mustache">
<?php

namespace {{slugPascalCase}};

use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task as BaseTask;

/**
 * Custom task class.
 */
class Task extends BaseTask {
	/**
	 * Get the task ID.
	 *
	 * @return string
	 */
	public function get_id() {
		return '{{slugSnakeCase}}-task';
	}

	/**
	 * Title.
	 *
	 * @return string
	 */
	public function get_title() {
		return __( '{{title}}', '{{textdomain}}' );
	}

	/**
	 * Content.
... (17 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/add-task/languages/woo-plugin-setup.pot.mustache">
# Copyright (C) 2022 WooCommerce
# This file is distributed under the GNU General Public License v3.0.
msgid ""
msgstr ""
"Project-Id-Version: Woo Plugin Setup 1.0.0\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/{{slug}}\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2022-11-27T21:35:18+00:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"X-Generator: WP-CLI 2.7.1\n"
"X-Domain: {{slug}}\n"

#. Plugin Name of the plugin
msgid "Woo Plugin Setup"
msgstr ""

#. Plugin URI of the plugin
msgid "https://github.com/psealock/woo-plugin-setup"
msgstr ""

#. Description of the plugin
msgid "This is an example of an extension template to follow."
msgstr ""

#. Author of the plugin
msgid "WooCommerce"
... (16 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/add-task/src/index.js.mustache">
/* eslint-disable @wordpress/i18n-text-domain */
/**
 * External dependencies
 */
import { createElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Card, CardBody, CardFooter, Button } from '@wordpress/components';
import { onboardingStore } from '@woocommerce/data';
import { registerPlugin } from '@wordpress/plugins';
import { useDispatch } from '@wordpress/data';
import {
	WooOnboardingTask,
	WooOnboardingTaskListItem,
} from '@woocommerce/onboarding';

const TaskContent = ( { onComplete, task } ) => {
	const { actionTask } = useDispatch( onboardingStore );
	const { isActioned } = task;

	return (
		<Card className="woocommerce-task-card">
			<CardBody>
				{ __(
					"This task's completion status is dependent on being actioned. The action button below will action this task, while the complete button will optimistically complete the task in the task list and redirect back to the task list. Note that in this example, the task must be actioned for completion to persist.",
					'{{textdomain}}'
				) }{ ' ' }
				<br />
				<br />
				{ __( 'Task actioned status: ', '{{textdomain}}' ) }{ ' ' }
				{ isActioned ? 'actioned' : 'not actioned' }
... (53 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/add-task/.editorconfig.mustache">
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/

root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 4
tab_width = 4
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true

[*.txt]
trim_trailing_whitespace = false

[*.{md,json,yml}]
trim_trailing_whitespace = false
indent_style = space
indent_size = 2

[*.json]
indent_style = tab
</file>

<file path="packages/js/create-woo-extension/variants/add-task/.gitignore.mustache">
# Operating System files
.DS_Store
Thumbs.db

# IDE files
.idea
.vscode/*
project.xml
project.properties
.project
.settings*
*.sublime-project
*.sublime-workspace
.sublimelinterrc

# Sass
.sass-cache/

# Logs
logs/

# Environment files
wp-cli.local.yml
yarn-error.log
npm-debug.log
.pnpm-debug.log

# Build files
*.sql
*.swp
... (32 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/add-task/.prettierrc.json.mustache">
"@wordpress/prettier-config"
</file>

<file path="packages/js/create-woo-extension/variants/add-task/.wp-env.json.mustache">
{
	"phpVersion": null,
	"core": null,
	"plugins": [
		"https://downloads.wordpress.org/plugin/woocommerce.zip",
		"."
	],
	"config": {
		"JETPACK_AUTOLOAD_DEV": true,
		"WP_DEBUG": true,
		"SCRIPT_DEBUG": true
	}
}
</file>

<file path="packages/js/create-woo-extension/variants/add-task/$slug.php.mustache">
<?php
/**
 * Plugin Name: {{title}}
{{#description}}
 * Description: {{description}}
{{/description}}
 * Version: {{version}}
{{#author}}
 * Author: {{author}}
{{/author}}
 * Author URI: https://woocommerce.com
 * Text Domain: {{textdomain}}
 * Domain Path: /languages
 *
 * License: GNU General Public License v3.0
 * License URI: http://www.gnu.org/licenses/gpl-3.0.html
 *
 * @package {{namespace}}
 */

defined( 'ABSPATH' ) || exit;

if ( ! defined( '{{slugConstantCase}}_MAIN_PLUGIN_FILE' ) ) {
	define( '{{slugConstantCase}}_MAIN_PLUGIN_FILE', __FILE__ );
}

require_once plugin_dir_path( __FILE__ ) . '/vendor/autoload_packages.php';

use {{slugPascalCase}}\Admin\Setup;
use {{slugPascalCase}}\Task;
... (121 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/add-task/composer.json.mustache">
{
	"name": "{{namespace}}/{{slug}}",
	"description": "WooCommerce plugin",
	"autoload": {
		"psr-4": {
			"{{slugPascalCase}}\\": "includes/"
		}
	},
	"require-dev": {
		"phpunit/phpunit": "^9.0",
		"automattic/jetpack-autoloader": "^2"
	},
	"config": {
		"allow-plugins": {
			"automattic/jetpack-autoloader": true
		}
	}
}
</file>

<file path="packages/js/create-woo-extension/variants/add-task/eslint.config.mjs.mustache">
import woocommerce from '@woocommerce/eslint-plugin';

export default [
	...woocommerce.configs.recommended,
	{
		rules: {
			'react/react-in-jsx-scope': 'off',
			/* The scaffolded extension ships its own text domain, not WooCommerce's. */
			'@wordpress/i18n-text-domain': [
				'error',
				{ allowedTextDomain: '{{textdomain}}' },
			],
		},
	},
	{
		/* Node config files (e.g. webpack.config.js) use CommonJS require(). */
		files: [ '**/*.config.js' ],
		rules: {
			'@typescript-eslint/no-require-imports': 'off',
		},
	},
];
</file>

<file path="packages/js/create-woo-extension/variants/add-task/README.md.mustache">
# {{title}}

{{#description}}
{{description}}
{{/description}}

This is a WooCommerce extension that adds a custom task to the WooCommerce onboarding wizard.

## Development

### Getting started

1. `npm install` to install dependencies
2. `npm start` to start the development server
3. `npm run build` to build the production version

### File Structure

- `src/index.js` - Main JavaScript file that registers the task content and list item customization
- `includes/Admin/Setup.php` - PHP class that handles task registration and script enqueuing
- `includes/Task.php` - Custom task class extending WooCommerce's base Task class
- `{{slug}}.php` - Main plugin file

## Features

- Adds a custom task to the WooCommerce onboarding task list
- Demonstrates how to extend the `Task` base class
- Shows how to use `WooOnboardingTask` and `WooOnboardingTaskListItem` components
- Includes example of task completion and action tracking

... (13 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/add-task/webpack.config.js.mustache">
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
const WooCommerceDependencyExtractionWebpackPlugin = require( '@woocommerce/dependency-extraction-webpack-plugin' );

module.exports = {
	...defaultConfig,
	plugins: [
		...defaultConfig.plugins.filter(
			( plugin ) =>
				plugin.constructor.name !== 'DependencyExtractionWebpackPlugin'
		),
		new WooCommerceDependencyExtractionWebpackPlugin(),
	],
};
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/includes/Admin/Setup.php.mustache">
<?php

namespace {{slugPascalCase}}\Admin;

/**
 * {{slugPascalCase}} Setup Class
 */
class Setup {
	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts' ) );
	}

	/**
	 * Load all necessary dependencies.
	 *
	 * @since 1.0.0
	 */
	public function register_scripts() {
		if ( ! class_exists( 'Automattic\WooCommerce\Admin\PageController' ) ||
			! \Automattic\WooCommerce\Admin\PageController::is_admin_page()
		) {
			return;
		}

		$script_path       = '/build/index.js';
... (21 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/languages/woo-plugin-setup.pot.mustache">
# Copyright (C) 2022 WooCommerce
# This file is distributed under the GNU General Public License v3.0.
msgid ""
msgstr ""
"Project-Id-Version: Woo Plugin Setup 1.0.0\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/{{slug}}\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2022-11-27T21:35:18+00:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"X-Generator: WP-CLI 2.7.1\n"
"X-Domain: {{slug}}\n"

#. Plugin Name of the plugin
msgid "Woo Plugin Setup"
msgstr ""

#. Plugin URI of the plugin
msgid "https://github.com/psealock/woo-plugin-setup"
msgstr ""

#. Description of the plugin
msgid "This is an example of an extension template to follow."
msgstr ""

#. Author of the plugin
msgid "WooCommerce"
... (16 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/src/components/GlobalPrices.js.mustache">
/**
 * External dependencies
 */
import moment from 'moment';
import { __ } from '@wordpress/i18n';

/**
 * WooCommerce dependencies
 */
import { Card, CardHeader, CardBody } from '@wordpress/components';
import { Chart } from '@woocommerce/components';
import Currency from '@woocommerce/currency';

const storeCurrency = Currency();
const data = [];

for ( let i = 1; i <= 20; i++ ) {
	const date = moment().subtract( i, 'days' );
	data.push( {
		date: date.format( 'YYYY-MM-DDT00:00:00' ),
		primary: {
			label: __( 'Global Apple Prices, last 20 days', '{{textdomain}}' ),
			labelDate: date.format( 'YYYY-MM-DD 00:00:00' ),
			value: Math.floor( Math.random() * 100 ),
		},
	} );
}

const GlobalPrices = () => {
	const average =
... (31 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/src/components/UpcomingEvents.js.mustache">
/**
 * External dependencies
 */
import { flatten } from 'lodash';
import { __ } from '@wordpress/i18n';

/**
 * WooCommerce dependencies
 */
import { TableCard } from '@woocommerce/components';

const UpcomingEvents = ( { config } ) => {
	const rows = flatten(
		config.map( ( apple ) => {
			return apple.events.map( ( event ) => {
				return [
					{ display: apple.title, value: 'variety' },
					{ display: event.title, value: 'event' },
					{ display: event.date, value: 'date' },
				];
			} );
		} )
	);
	return (
		<TableCard
			title={ __( 'Upcoming Events', '{{textdomain}}' ) }
			headers={ [
				{ label: __( 'Variety', '{{textdomain}}' ), key: 'variety' },
				{ label: __( 'Event', '{{textdomain}}' ), key: 'event' },
				{ label: __( 'Date', '{{textdomain}}' ), key: 'date' },
... (10 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/src/index.js.mustache">
/**
 * External dependencies
 */

import { addFilter } from '@wordpress/hooks';
import { Component, Fragment } from '@wordpress/element';
import { wordpress } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';

/**
 * WooCommerce dependencies
 */
import {
	EllipsisMenu,
	MenuTitle,
	MenuItem,
	SectionHeader,
} from '@woocommerce/components';

/**
 * Internal dependencies
 */
import UpcomingEvents from './components/UpcomingEvents';
import GlobalPrices from './components/GlobalPrices';

const config = [
	{
		title: __( 'Granny Smith', '{{textdomain}}' ),
		events: [ { date: '2020-01-02', title: __( 'The Granny Apple Fair', '{{textdomain}}' ) } ],
	},
... (121 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/.editorconfig.mustache">
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/

root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 4
tab_width = 4
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true

[*.txt]
trim_trailing_whitespace = false

[*.{md,json,yml}]
trim_trailing_whitespace = false
indent_style = space
indent_size = 2

[*.json]
indent_style = tab
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/.gitignore.mustache">
# Operating System files
.DS_Store
Thumbs.db

# IDE files
.idea
.vscode/*
project.xml
project.properties
.project
.settings*
*.sublime-project
*.sublime-workspace
.sublimelinterrc

# Sass
.sass-cache/

# Logs
logs/

# Environment files
wp-cli.local.yml
yarn-error.log
npm-debug.log
.pnpm-debug.log

# Build files
*.sql
*.swp
... (32 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/.prettierrc.json.mustache">
"@wordpress/prettier-config"
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/.wp-env.json.mustache">
{
	"phpVersion": null,
	"core": null,
	"plugins": [
		"https://downloads.wordpress.org/plugin/woocommerce.zip",
		"."
	],
	"config": {
		"JETPACK_AUTOLOAD_DEV": true,
		"WP_DEBUG": true,
		"SCRIPT_DEBUG": true
	}
}
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/$slug.php.mustache">
<?php
/**
 * Plugin Name: {{title}}
{{#description}}
 * Description: {{description}}
{{/description}}
 * Version: {{version}}
{{#author}}
 * Author: {{author}}
{{/author}}
 * Author URI: https://woocommerce.com
 * Text Domain: {{textdomain}}
 * Domain Path: /languages
 *
 * License: GNU General Public License v3.0
 * License URI: http://www.gnu.org/licenses/gpl-3.0.html
 *
 * @package {{namespace}}
 */

defined( 'ABSPATH' ) || exit;

if ( ! defined( '{{slugConstantCase}}_MAIN_PLUGIN_FILE' ) ) {
	define( '{{slugConstantCase}}_MAIN_PLUGIN_FILE', __FILE__ );
}

require_once plugin_dir_path( __FILE__ ) . '/vendor/autoload_packages.php';

use {{slugPascalCase}}\Admin\Setup;

... (97 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/composer.json.mustache">
{
	"name": "{{namespace}}/{{slug}}",
	"description": "WooCommerce plugin",
	"autoload": {
		"psr-4": {
			"{{slugPascalCase}}\\": "includes/"
		}
	},
	"require-dev": {
		"phpunit/phpunit": "^9.0",
		"automattic/jetpack-autoloader": "^2"
	},
	"config": {
		"allow-plugins": {
			"automattic/jetpack-autoloader": true
		}
	}
}
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/eslint.config.mjs.mustache">
import woocommerce from '@woocommerce/eslint-plugin';

export default [
	...woocommerce.configs.recommended,
	{
		rules: {
			'react/react-in-jsx-scope': 'off',
			/* The scaffolded extension ships its own text domain, not WooCommerce's. */
			'@wordpress/i18n-text-domain': [
				'error',
				{ allowedTextDomain: '{{textdomain}}' },
			],
		},
	},
	{
		/* Node config files (e.g. webpack.config.js) use CommonJS require(). */
		files: [ '**/*.config.js' ],
		rules: {
			'@typescript-eslint/no-require-imports': 'off',
		},
	},
];
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/README.md.mustache">
# {{title}}

{{#description}}
{{description}}
{{/description}}

This is a WooCommerce extension that adds a custom section to the WooCommerce Analytics dashboard.

## Development

### Getting started

1. `npm install` to install dependencies
2. `npm start` to start the development server
3. `npm run build` to build the production version

### File Structure

- `src/index.js` - Main JavaScript file that registers the dashboard section
- `src/components/GlobalPrices.js` - Example chart component
- `src/components/UpcomingEvents.js` - Example table component
- `includes/Admin/Setup.php` - PHP class that handles script registration
- `{{slug}}.php` - Main plugin file

## Features

- Adds a custom section to the WooCommerce dashboard
- Demonstrates how to use the `woocommerce_dashboard_default_sections` filter
- Shows example usage of WooCommerce components:
  - `SectionHeader` with customizable menu
... (29 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/dashboard-section/webpack.config.js.mustache">
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
const WooCommerceDependencyExtractionWebpackPlugin = require( '@woocommerce/dependency-extraction-webpack-plugin' );

module.exports = {
	...defaultConfig,
	plugins: [
		...defaultConfig.plugins.filter(
			( plugin ) =>
				plugin.constructor.name !== 'DependencyExtractionWebpackPlugin'
		),
		new WooCommerceDependencyExtractionWebpackPlugin(),
	],
};
</file>

<file path="packages/js/create-woo-extension/variants/default/includes/Admin/Setup.php.mustache">
<?php

namespace {{slugPascalCase}}\Admin;

/**
 * {{slugPascalCase}} Setup Class
 */
class Setup {
	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts' ) );
		add_action( 'admin_menu', array( $this, 'register_page' ) );
	}

	/**
	 * Load all necessary dependencies.
	 *
	 * @since 1.0.0
	 */
	public function register_scripts() {
		if ( ! method_exists( 'Automattic\WooCommerce\Admin\PageController', 'is_admin_or_embed_page' ) ||
		! \Automattic\WooCommerce\Admin\PageController::is_admin_or_embed_page()
		) {
			return;
		}

... (52 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/default/languages/woo-plugin-setup.pot.mustache">
# Copyright (C) 2022 WooCommerce
# This file is distributed under the GNU General Public License v3.0.
msgid ""
msgstr ""
"Project-Id-Version: Woo Plugin Setup 1.0.0\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/{{slug}}\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2022-11-27T21:35:18+00:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"X-Generator: WP-CLI 2.7.1\n"
"X-Domain: {{slug}}\n"

#. Plugin Name of the plugin
msgid "Woo Plugin Setup"
msgstr ""

#. Plugin URI of the plugin
msgid "https://github.com/psealock/woo-plugin-setup"
msgstr ""

#. Description of the plugin
msgid "This is an example of an extension template to follow."
msgstr ""

#. Author of the plugin
msgid "WooCommerce"
... (16 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/default/src/index.js.mustache">
/**
 * External dependencies
 */
import { addFilter } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n';
import { Dropdown } from '@wordpress/components';
import * as Woo from '@woocommerce/components';
import { Fragment, useState } from '@wordpress/element';

/**
 * Internal dependencies
 */
import './index.scss';

const MyExamplePage = () => {
	const [ inlineSelect, setInlineSelect ] = useState( [] );

	return (
		<Fragment>
			<Woo.Section component="article">
				<Woo.SectionHeader
					title={ __( 'Search', '{{textdomain}}' ) }
				/>
				<Woo.Search
					type="products"
					placeholder="Search for something"
					selected={ inlineSelect }
					onChange={ ( items ) => setInlineSelect( items ) }
					inlineTags
				/>
... (61 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/default/src/index.scss.mustache">
h1 {
	background-color: gold;
}
</file>

<file path="packages/js/create-woo-extension/variants/default/.editorconfig.mustache">
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/

root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 4
tab_width = 4
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true

[*.txt]
trim_trailing_whitespace = false

[*.{md,json,yml}]
trim_trailing_whitespace = false
indent_style = space
indent_size = 2

[*.json]
indent_style = tab
</file>

<file path="packages/js/create-woo-extension/variants/default/.gitignore.mustache">
# Operating System files
.DS_Store
Thumbs.db

# IDE files
.idea
.vscode/*
project.xml
project.properties
.project
.settings*
*.sublime-project
*.sublime-workspace
.sublimelinterrc

# Sass
.sass-cache/

# Logs
logs/

# Environment files
wp-cli.local.yml
yarn-error.log
npm-debug.log
.pnpm-debug.log

# Build files
*.sql
*.swp
... (32 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/default/.prettierrc.json.mustache">
"@wordpress/prettier-config"
</file>

<file path="packages/js/create-woo-extension/variants/default/.wp-env.json.mustache">
{
	"phpVersion": null,
	"core": null,
	"plugins": [
		"https://downloads.wordpress.org/plugin/woocommerce.zip",
		"."
	],
	"config": {
		"JETPACK_AUTOLOAD_DEV": true,
		"WP_DEBUG": true,
		"SCRIPT_DEBUG": true
	}
}
</file>

<file path="packages/js/create-woo-extension/variants/default/$slug.php.mustache">
<?php
/**
 * Plugin Name: {{title}}
{{#description}}
 * Description: {{description}}
{{/description}}
 * Version: {{version}}
{{#author}}
 * Author: {{author}}
{{/author}}
 * Author URI: https://woocommerce.com
 * Text Domain: {{textdomain}}
 * Domain Path: /languages
 *
 * License: GNU General Public License v3.0
 * License URI: http://www.gnu.org/licenses/gpl-3.0.html
 *
 * @package {{namespace}}
 */

defined( 'ABSPATH' ) || exit;

if ( ! defined( '{{slugConstantCase}}_MAIN_PLUGIN_FILE' ) ) {
	define( '{{slugConstantCase}}_MAIN_PLUGIN_FILE', __FILE__ );
}

require_once plugin_dir_path( __FILE__ ) . '/vendor/autoload_packages.php';

use {{slugPascalCase}}\Admin\Setup;

... (97 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/default/composer.json.mustache">
{
	"name": "{{namespace}}/{{slug}}",
	"description": "WooCommerce plugin",
	"autoload": {
		"psr-4": {
			"{{slugPascalCase}}\\": "includes/"
		}
	},
	"require-dev": {
		"phpunit/phpunit": "^9.0",
		"automattic/jetpack-autoloader": "^2"
	},
	"config": {
		"allow-plugins": {
			"automattic/jetpack-autoloader": true
		}
	}
}
</file>

<file path="packages/js/create-woo-extension/variants/default/eslint.config.mjs.mustache">
import woocommerce from '@woocommerce/eslint-plugin';

export default [
	...woocommerce.configs.recommended,
	{
		rules: {
			'react/react-in-jsx-scope': 'off',
			/* The scaffolded extension ships its own text domain, not WooCommerce's. */
			'@wordpress/i18n-text-domain': [
				'error',
				{ allowedTextDomain: '{{textdomain}}' },
			],
		},
	},
	{
		/* Node config files (e.g. webpack.config.js) use CommonJS require(). */
		files: [ '**/*.config.js' ],
		rules: {
			'@typescript-eslint/no-require-imports': 'off',
		},
	},
];
</file>

<file path="packages/js/create-woo-extension/variants/default/README.md.mustache">
# {{title}}

A WooCommerce Extension inspired by [Create Woo Extension](https://github.com/woocommerce/woocommerce/blob/trunk/packages/js/create-woo-extension/README.md).

## Getting Started

### Prerequisites

-   [NPM](https://www.npmjs.com/)
-   [Composer](https://getcomposer.org/download/)
-   [wp-env](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/)

### Installation and Build

```
npm install
npm run build
wp-env start
```

Visit the added page at http://localhost:8888/wp-admin/admin.php?page=wc-admin&path=%2Fexample.
</file>

<file path="packages/js/create-woo-extension/variants/default/webpack.config.js.mustache">
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
const WooCommerceDependencyExtractionWebpackPlugin = require( '@woocommerce/dependency-extraction-webpack-plugin' );

module.exports = {
	...defaultConfig,
	plugins: [
		...defaultConfig.plugins.filter(
			( plugin ) =>
				plugin.constructor.name !== 'DependencyExtractionWebpackPlugin'
		),
		new WooCommerceDependencyExtractionWebpackPlugin(),
	],
};
</file>

<file path="packages/js/create-woo-extension/variants/sql-modification/includes/Admin/Setup.php.mustache">
<?php

namespace {{slugPascalCase}}\Admin;

/**
 * {{slugPascalCase}} Setup Class
 */
class Setup {
	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts' ) );
	}

	/**
	 * Load all necessary dependencies.
	 *
	 * @since 1.0.0
	 */
	public function register_scripts() {
		if ( ! class_exists( 'Automattic\WooCommerce\Admin\PageController' ) ||
			! \Automattic\WooCommerce\Admin\PageController::is_admin_page()
		) {
			return;
		}

		$this->add_currency_settings();
... (57 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/sql-modification/languages/woo-plugin-setup.pot.mustache">
# Copyright (C) 2022 WooCommerce
# This file is distributed under the GNU General Public License v3.0.
msgid ""
msgstr ""
"Project-Id-Version: Woo Plugin Setup 1.0.0\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/{{slug}}\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2022-11-27T21:35:18+00:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"X-Generator: WP-CLI 2.7.1\n"
"X-Domain: {{slug}}\n"

#. Plugin Name of the plugin
msgid "Woo Plugin Setup"
msgstr ""

#. Plugin URI of the plugin
msgid "https://github.com/psealock/woo-plugin-setup"
msgstr ""

#. Description of the plugin
msgid "This is an example of an extension template to follow."
msgstr ""

#. Author of the plugin
msgid "WooCommerce"
... (16 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/sql-modification/src/index.js.mustache">
/**
 * External dependencies
 */

import { addFilter } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n';

/**
 * Add a currency dropdown filter to reports.
 *
 * @param {Array} filters - Set of filters in a report.
 * @return {Array} Amended set of filters.
 */
const addCurrencyFilters = ( filters ) => {
	return [
		{
			label: __( 'Currency', '{{textdomain}}' ),
			staticParams: [],
			param: 'currency',
			showFilters: () => true,
			defaultValue: 'USD',
			filters: [ ...( wcSettings.multiCurrency || [] ) ],
		},
		...filters,
	];
};

// Add currency filter to all relevant reports.
addFilter(
	'woocommerce_admin_revenue_report_filters',
... (145 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/sql-modification/src/index.scss.mustache">
h1 {
	background-color: gold;
}
</file>

<file path="packages/js/create-woo-extension/variants/sql-modification/.editorconfig.mustache">
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/

root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 4
tab_width = 4
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true

[*.txt]
trim_trailing_whitespace = false

[*.{md,json,yml}]
trim_trailing_whitespace = false
indent_style = space
indent_size = 2

[*.json]
indent_style = tab
</file>

<file path="packages/js/create-woo-extension/variants/sql-modification/.gitignore.mustache">
# Operating System files
.DS_Store
Thumbs.db

# IDE files
.idea
.vscode/*
project.xml
project.properties
.project
.settings*
*.sublime-project
*.sublime-workspace
.sublimelinterrc

# Sass
.sass-cache/

# Logs
logs/

# Environment files
wp-cli.local.yml
yarn-error.log
npm-debug.log
.pnpm-debug.log

# Build files
*.sql
*.swp
... (32 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/sql-modification/.prettierrc.json.mustache">
"@wordpress/prettier-config"
</file>

<file path="packages/js/create-woo-extension/variants/sql-modification/.wp-env.json.mustache">
{
	"phpVersion": null,
	"core": null,
	"plugins": [
		"https://downloads.wordpress.org/plugin/woocommerce.zip",
		"."
	],
	"config": {
		"JETPACK_AUTOLOAD_DEV": true,
		"WP_DEBUG": true,
		"SCRIPT_DEBUG": true
	}
}
</file>

<file path="packages/js/create-woo-extension/variants/sql-modification/$slug.php.mustache">
<?php
/**
 * Plugin Name: {{title}}
{{#description}}
 * Description: {{description}}
{{/description}}
 * Version: {{version}}
{{#author}}
 * Author: {{author}}
{{/author}}
 * Author URI: https://woocommerce.com
 * Text Domain: {{textdomain}}
 * Domain Path: /languages
 *
 * License: GNU General Public License v3.0
 * License URI: http://www.gnu.org/licenses/gpl-3.0.html
 *
 * @package {{namespace}}
 */

defined( 'ABSPATH' ) || exit;

if ( ! defined( '{{slugConstantCase}}_MAIN_PLUGIN_FILE' ) ) {
	define( '{{slugConstantCase}}_MAIN_PLUGIN_FILE', __FILE__ );
}

require_once plugin_dir_path( __FILE__ ) . '/vendor/autoload_packages.php';

use {{slugPascalCase}}\Admin\Setup;

... (275 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/sql-modification/composer.json.mustache">
{
	"name": "{{namespace}}/{{slug}}",
	"description": "WooCommerce plugin",
	"autoload": {
		"psr-4": {
			"{{slugPascalCase}}\\": "includes/"
		}
	},
	"require-dev": {
		"phpunit/phpunit": "^9.0",
		"automattic/jetpack-autoloader": "^2"
	},
	"config": {
		"allow-plugins": {
			"automattic/jetpack-autoloader": true
		}
	}
}
</file>

<file path="packages/js/create-woo-extension/variants/sql-modification/eslint.config.mjs.mustache">
import woocommerce from '@woocommerce/eslint-plugin';

export default [
	...woocommerce.configs.recommended,
	{
		rules: {
			'react/react-in-jsx-scope': 'off',
			/* The scaffolded extension ships its own text domain, not WooCommerce's. */
			'@wordpress/i18n-text-domain': [
				'error',
				{ allowedTextDomain: '{{textdomain}}' },
			],
		},
	},
	{
		/* Node config files (e.g. webpack.config.js) use CommonJS require(). */
		files: [ '**/*.config.js' ],
		rules: {
			'@typescript-eslint/no-require-imports': 'off',
		},
	},
];
</file>

<file path="packages/js/create-woo-extension/variants/sql-modification/README.md.mustache">
# {{title}}

{{#description}}
{{description}}
{{/description}}

This is a WooCommerce extension that demonstrates how to modify SQL queries for WooCommerce Analytics reports. It adds multi-currency filtering support to reports.

## Development

### Getting started

1. `npm install` to install dependencies
2. `npm start` to start the development server
3. `npm run build` to build the production version

### File Structure

- `src/index.js` - JavaScript filters for UI (dropdowns, table columns, currency formatting)
- `includes/Admin/Setup.php` - PHP class for script registration and currency settings
- `{{slug}}.php` - Main plugin file with SQL modification hooks

## Features

This extension demonstrates:

- **Query Argument Filters** - Add custom parameters for caching
- **JOIN Clause Filters** - Join additional tables to reports
- **WHERE Clause Filters** - Filter report data by custom criteria
- **SELECT Clause Filters** - Add custom columns to report data
... (67 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/sql-modification/webpack.config.js.mustache">
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
const WooCommerceDependencyExtractionWebpackPlugin = require( '@woocommerce/dependency-extraction-webpack-plugin' );

module.exports = {
	...defaultConfig,
	plugins: [
		...defaultConfig.plugins.filter(
			( plugin ) =>
				plugin.constructor.name !== 'DependencyExtractionWebpackPlugin'
		),
		new WooCommerceDependencyExtractionWebpackPlugin(),
	],
};
</file>

<file path="packages/js/create-woo-extension/variants/table-column/includes/Admin/Setup.php.mustache">
<?php

namespace {{slugPascalCase}}\Admin;

/**
 * {{slugPascalCase}} Setup Class
 */
class Setup {
	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts' ) );
		add_filter( 'woocommerce_rest_report_products_schema', array( $this, 'add_product_extended_attributes_schema' ) );
		add_filter( 'woocommerce_rest_reports_products_extended_attributes', array( $this, 'add_product_extended_attributes' ) );
	}

	/**
	 * Load all necessary dependencies.
	 *
	 * @since 1.0.0
	 */
	public function register_scripts() {
		if ( ! class_exists( 'Automattic\WooCommerce\Admin\PageController' ) ||
			! \Automattic\WooCommerce\Admin\PageController::is_admin_page()
		) {
			return;
		}
... (55 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/table-column/languages/woo-plugin-setup.pot.mustache">
# Copyright (C) 2022 WooCommerce
# This file is distributed under the GNU General Public License v3.0.
msgid ""
msgstr ""
"Project-Id-Version: Woo Plugin Setup 1.0.0\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/{{slug}}\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2022-11-27T21:35:18+00:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"X-Generator: WP-CLI 2.7.1\n"
"X-Domain: {{slug}}\n"

#. Plugin Name of the plugin
msgid "Woo Plugin Setup"
msgstr ""

#. Plugin URI of the plugin
msgid "https://github.com/psealock/woo-plugin-setup"
msgstr ""

#. Description of the plugin
msgid "This is an example of an extension template to follow."
msgstr ""

#. Author of the plugin
msgid "WooCommerce"
... (16 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/table-column/src/index.js.mustache">
/**
 * External dependencies
 */

import { addFilter } from '@wordpress/hooks';
import { Rating } from '@woocommerce/components';

addFilter(
	'woocommerce_admin_report_table',
	'{{textdomain}}',
	( reportTableData ) => {
		if ( reportTableData.endpoint !== 'products' ) {
			return reportTableData;
		}

		reportTableData.headers = [
			...reportTableData.headers,
			{
				label: 'ID',
				key: 'product_id',
			},
			{
				label: 'Rating',
				key: 'product_rating',
			},
		];

		if (
			! reportTableData.items ||
			! reportTableData.items.data ||
... (36 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/table-column/.editorconfig.mustache">
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/

root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 4
tab_width = 4
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true

[*.txt]
trim_trailing_whitespace = false

[*.{md,json,yml}]
trim_trailing_whitespace = false
indent_style = space
indent_size = 2

[*.json]
indent_style = tab
</file>

<file path="packages/js/create-woo-extension/variants/table-column/.gitignore.mustache">
# Operating System files
.DS_Store
Thumbs.db

# IDE files
.idea
.vscode/*
project.xml
project.properties
.project
.settings*
*.sublime-project
*.sublime-workspace
.sublimelinterrc

# Sass
.sass-cache/

# Logs
logs/

# Environment files
wp-cli.local.yml
yarn-error.log
npm-debug.log
.pnpm-debug.log

# Build files
*.sql
*.swp
... (32 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/table-column/.prettierrc.json.mustache">
"@wordpress/prettier-config"
</file>

<file path="packages/js/create-woo-extension/variants/table-column/.wp-env.json.mustache">
{
	"phpVersion": null,
	"core": null,
	"plugins": [
		"https://downloads.wordpress.org/plugin/woocommerce.zip",
		"."
	],
	"config": {
		"JETPACK_AUTOLOAD_DEV": true,
		"WP_DEBUG": true,
		"SCRIPT_DEBUG": true
	}
}
</file>

<file path="packages/js/create-woo-extension/variants/table-column/$slug.php.mustache">
<?php
/**
 * Plugin Name: {{title}}
{{#description}}
 * Description: {{description}}
{{/description}}
 * Version: {{version}}
{{#author}}
 * Author: {{author}}
{{/author}}
 * Author URI: https://woocommerce.com
 * Text Domain: {{textdomain}}
 * Domain Path: /languages
 *
 * License: GNU General Public License v3.0
 * License URI: http://www.gnu.org/licenses/gpl-3.0.html
 *
 * @package {{namespace}}
 */

defined( 'ABSPATH' ) || exit;

if ( ! defined( '{{slugConstantCase}}_MAIN_PLUGIN_FILE' ) ) {
	define( '{{slugConstantCase}}_MAIN_PLUGIN_FILE', __FILE__ );
}

require_once plugin_dir_path( __FILE__ ) . '/vendor/autoload_packages.php';

use {{slugPascalCase}}\Admin\Setup;

... (97 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/table-column/composer.json.mustache">
{
	"name": "{{namespace}}/{{slug}}",
	"description": "WooCommerce plugin",
	"autoload": {
		"psr-4": {
			"{{slugPascalCase}}\\": "includes/"
		}
	},
	"require-dev": {
		"phpunit/phpunit": "^9.0",
		"automattic/jetpack-autoloader": "^2"
	},
	"config": {
		"allow-plugins": {
			"automattic/jetpack-autoloader": true
		}
	}
}
</file>

<file path="packages/js/create-woo-extension/variants/table-column/eslint.config.mjs.mustache">
import woocommerce from '@woocommerce/eslint-plugin';

export default [
	...woocommerce.configs.recommended,
	{
		rules: {
			'react/react-in-jsx-scope': 'off',
			/* The scaffolded extension ships its own text domain, not WooCommerce's. */
			'@wordpress/i18n-text-domain': [
				'error',
				{ allowedTextDomain: '{{textdomain}}' },
			],
		},
	},
	{
		/* Node config files (e.g. webpack.config.js) use CommonJS require(). */
		files: [ '**/*.config.js' ],
		rules: {
			'@typescript-eslint/no-require-imports': 'off',
		},
	},
];
</file>

<file path="packages/js/create-woo-extension/variants/table-column/README.md.mustache">
# {{title}}

{{#description}}
{{description}}
{{/description}}

This is a WooCommerce extension that adds custom columns to WooCommerce Analytics report tables.

## Development

### Getting started

1. `npm install` to install dependencies
2. `npm start` to start the development server
3. `npm run build` to build the production version

### File Structure

- `src/index.js` - Main JavaScript file that filters the report table data
- `includes/Admin/Setup.php` - PHP class that handles script registration and REST API schema modifications
- `{{slug}}.php` - Main plugin file

## Features

- Adds custom columns to the Products report table
- Demonstrates how to extend the REST API schema for reports
- Shows how to add extended product attributes
- Example of using the `woocommerce_admin_report_table` filter

## How It Works
... (21 lines truncated)
</file>

<file path="packages/js/create-woo-extension/variants/table-column/webpack.config.js.mustache">
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
const WooCommerceDependencyExtractionWebpackPlugin = require( '@woocommerce/dependency-extraction-webpack-plugin' );

module.exports = {
	...defaultConfig,
	plugins: [
		...defaultConfig.plugins.filter(
			( plugin ) =>
				plugin.constructor.name !== 'DependencyExtractionWebpackPlugin'
		),
		new WooCommerceDependencyExtractionWebpackPlugin(),
	],
};
</file>

<file path="packages/js/create-woo-extension/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.0.1](https://www.npmjs.com/package/@woocommerce/create-woo-extension/v/2.0.1) - 2025-12-12 

-   Patch - Replace deprecated "templatesPath" with "blockTemplatesPath" and "pluginTemplatesPath" properties. [#62417]

## [2.0.0](https://www.npmjs.com/package/@woocommerce/create-woo-extension/v/2.0.0) - 2025-12-10 

-   Patch - Correcting directory and filename casing to address bug with PHP autoloader. [#48992]
-   Patch - Update Woo.com references to WooCommerce.com. [#46259]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - CI: liverage composer packages cache in lint monorepo job [#52054]
-   Patch - Fix pnpm version to 9.1.3 to avoid dependency installation issues. [#50828]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Update pnpm to 9.1.0 [#47385]
-   Patch - Update wireit to 0.14.10 [#54996]
-   Patch - Fix a small typo in package.json homepage url. [#45811]
-   Minor - Bump node version. [#45148]
-   Minor - Monorepo: bump pnpm version to 9.15.0 [#54189]
-   Minor - Fix typos in README.md files [#48569]
-   **Breaking Change:**  Adds variants for multiple extension scaffolds, templatesPath moved to variants/default subdirectory, new variants API structure introduced, postinstall script modified, and @wordpress/scripts version unpinned [#62297]

## [1.1.0](https://www.npmjs.com/package/@woocommerce/create-woo-extension/v/1.1.0) - 2024-01-31 

-   Patch - bump php version in packages/js/*/composer.json [#42020]
-   Patch - update references to woocommerce.com to now reference woo.com [#41241]
-   Patch - Update WooCommerce version to latest [#44107]
-   Minor - Update pnpm monorepo-wide to 8.6.5 [#38990]
... (19 lines truncated)
</file>

<file path="packages/js/create-woo-extension/composer.json">
{
	"name": "woocommerce/extend-cart-checkout-block",
	"description": "A template to be used with `@wordpress/create-block` to create a WooCommerce extension.",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"prefer-stable": true,
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
... (4 lines truncated)
</file>

<file path="packages/js/create-woo-extension/index.js">
transformer: ( view ) =>
</file>

<file path="packages/js/create-woo-extension/package.json">
{
	"name": "@woocommerce/create-woo-extension",
	"version": "2.0.1",
	"description": "A template to be used with `@wordpress/create-block` to create a WooCommerce extension.",
	"main": "index.js",
	"engines": {
		"node": "^24.15.0"
	},
	"repository": {
		"type": "git",
		"url": "git+https://github.com/woocommerce/woocommerce.git"
	},
	"keywords": [],
	"author": "",
	"license": "GPL-2.0-or-later",
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"scripts": {
		"changelog": "XDEBUG_MODE=off composer install --quiet && composer exec -- changelogger"
	},
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/create-woo-extension#readme"
}
</file>

<file path="packages/js/create-woo-extension/README.md">
# @woocommerce/create-woo-extension

Create Woo Extension scaffolds a fully functional modern development environment for integrating with WooCommerce. Use it to build extensions leveraging the power of WooCommerce.

## Configuration Free

With build tooling already configured, getting started developing modern Javascript screens requires no effort. Create Woo Extension adds a React page integrating with WooCommerce Admin. Also included are PHP and Javascript unit testing, linting, and Prettier IDE configuration for WooCommerce and WordPress.

Add a project inside of your favorite environment setup or use the built in [wp-env](https://github.com/WordPress/gutenberg/tree/trunk/packages/env) for easily setting up a local WordPress environment for building and testing plugins and themes. `wp-env` is configured to load the latest WooCommerce to easily start developing with a single command.

## Usage

```bash
npx @wordpress/create-block -t @woocommerce/create-woo-extension my-extension-name
```

Navigate to the newly created folder and get started.

```bash
cd my-extension-name
npm run start # Watch the javascript for changes

# Local development with wp-env (optional)
npm -g i @wordpress/env # If you don't already have wp-env
wp-env start # Start WordPress environment
```

See the new plugin activated from the WordPress plugins page and navigate to `wp-admin/admin.php?page=wc-admin&path=%2Fmy-extension-name` to check it out.

## Variants
... (32 lines truncated)
</file>

<file path="packages/js/csv-export/changelog/.gitkeep">

</file>

<file path="packages/js/csv-export/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/csv-export/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/csv-export/src/index.ts">
import { saveAs } from 'browser-filesaver';
⋮----
export type Header = {
	label: string;
	key: string;
};
⋮----
export type RowItem = {
	display: string;
	value: string | number;
};
⋮----
export type Rows = Array< RowItem[] >;
⋮----
function escapeCSVValue( value: string | number )
⋮----
function getCSVHeaders( headers: Header[] )
⋮----
function getCSVRows( rows: Rows )
⋮----
export function generateCSVDataFromTable( headers: Header[], rows: Rows )
⋮----
function todayDateStr()
⋮----
export function generateCSVFileName(
	name = '',
	params: Record< string, string > = {}
)
⋮----
export function downloadCSVFile( fileName: string, content: BlobPart )
... (1 lines truncated)
</file>

<file path="packages/js/csv-export/typings/index.d.ts">
declare function FileSaver(data: Blob, filename: string, disableAutoBOM?: boolean): void;
</file>

<file path="packages/js/csv-export/.npmrc">
package-lock=false
</file>

<file path="packages/js/csv-export/.prettierrc.js">

</file>

<file path="packages/js/csv-export/babel.config.js">

</file>

<file path="packages/js/csv-export/build.mjs">

</file>

<file path="packages/js/csv-export/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.11.0](https://www.npmjs.com/package/@woocommerce/csv-export/v/1.11.0) - 2026-06-10 

-   Minor - Bump jest package dependency to 29.5.x. [#60324]
-   Minor - Monorepo: bump pnpm version to 9.15.0. [#54189]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - Clean up CI job config options; remove unused cascading keys. [#55863]
-   Patch - Monorepo: build RAM usage optimization. [#58781]
-   Patch - Monorepo: consolidate @babel/* dependencies versions across the monorepo. [#56575]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Monorepo: drop the unused `concurrently` package from dependencies. [#58765]
-   Patch - Monorepo: refresh wireit dependencyOutputs configuration synchronization when installing dependencies. [#55095]
-   Patch - Move the CommonJS build to prepack so day-to-day development only builds the ESM output. [#64876]
-   Patch - Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking. [#65168]
-   Patch - Replaced patched `@wordpress/data` types with opt-in internal package types. [#63483]
-   Patch - Replaced wireit + tsc package build pipeline with a per-package esbuild script. [#65210]
-   Patch - Update wireit to 0.14.10. [#54996]

## [1.10.0](https://www.npmjs.com/package/@woocommerce/csv-export/v/1.10.0) - 2024-12-19 

-   Patch - Improved CSV export usability by allowing negative numeric values to be unescaped while continuing to escape potentially risky strings to prevent CSV Injection (client-side CSV exporting). [#52727]
-   Patch - CI: liverage composer packages cache in lint monorepo job [#52054]
-   Patch - Fix pnpm version to 9.1.3 to avoid dependency installation issues. [#50828]
-   Patch - Monorepo: consolidate syncpack config around React 17/18 usage. [#52022]
-   Patch - Monorepo: consolidate TypeScript config files and JS test directories naming. [#52191]
-   Minor - Upgraded Typescript in the monorepo to 5.7.2 [#53165]

... (36 lines truncated)
</file>

<file path="packages/js/csv-export/composer.json">
{
	"name": "woocommerce/csv-export",
	"description": "WooCommerce CSV export package",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/csv-export/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/csv-export/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/csv-export/package.json">
{
	"name": "@woocommerce/csv-export",
	"version": "1.11.0",
	"description": "WooCommerce utility library to convert data to CSV files.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"keywords": [
		"wordpress",
		"woocommerce",
		"csv"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/csv-export/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
... (92 lines truncated)
</file>

<file path="packages/js/csv-export/PREVIOUS_CHANGELOG.md">
# 1.5.0

-   Update all js packages with minor/patch version changes. #8392

# 1.4.0

-   Fix commonjs module build, allow package to be built in isolation. #7286

# 1.3.2

-   Use tab char for the CSV injection prevention.

# 1.3.1

-   Update dependencies.

# 1.3.0

-   Update to @wordpress/eslint coding standards.

# 1.2.0

-   Properly escape values with double quotes.
-   Prevent CSV injection.

# 1.1.2

-   Update dependencies.

# 1.1.1
... (18 lines truncated)
</file>

<file path="packages/js/csv-export/README.md">
# CSV Export

A set of functions to convert data into CSV values, and enable a browser download of the CSV data.

## Installation

Install the module

```bash
pnpm install @woocommerce/csv-export --save
```

## Usage

```js
onClick = () => {
	// Create a file name based on a title and optional query. Will return a timestamped
	// name, for example: revenue-2018-11-01-interval-month.csv
	const name = generateCSVFileName( 'revenue', { interval: 'month' } );

	// Create a string of CSV data, `headers` is an array of row headers, put at the top
	// of the file. `rows` is a 2 dimensional array. Each array is a line in the file,
	// separated by newlines. The second-level arrays are the data points in each row.
	const data = generateCSVDataFromTable( headers, rows );

	// Triggers a browser UI to save a file, named the first argument, with the contents of
	// the second argument.
	downloadCSVFile( name, data );
}
```
... (33 lines truncated)
</file>

<file path="packages/js/csv-export/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": []
}
</file>

<file path="packages/js/currency/changelog/.gitkeep">

</file>

<file path="packages/js/currency/changelog/consolidate-eslint-core-modules">
Significance: patch
Type: dev
Comment: Consolidate the shared `import/core-modules` list into `@woocommerce/eslint-config`. Tooling only; no runtime change.
</file>

<file path="packages/js/currency/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/currency/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/currency/src/currency-context.js">
export const getFilteredCurrencyInstance = ( query ) =>
</file>

<file path="packages/js/currency/src/index.ts">
import { CurrencyFactory } from './utils';
</file>

<file path="packages/js/currency/src/utils.tsx">
import { createElement } from '@wordpress/element';
import { decodeEntities } from '@wordpress/html-entities';
import { sprintf } from '@wordpress/i18n';
import { NumberConfig, numberFormat, parseNumber } from '@woocommerce/number';
import deprecated from '@wordpress/deprecated';
⋮----
export type SymbolPosition = 'left' | 'right' | 'left_space' | 'right_space';
⋮----
export type CurrencyProps = {
	code: string;
	symbol: string;
	symbolPosition: SymbolPosition;
	priceFormat?: string;
};
⋮----
export type CurrencyConfig = Partial< NumberConfig & CurrencyProps >;
⋮----
export type Currency = {
	code: string;
	symbol: string;
	symbolPosition: string;
	decimalSeparator: string;
	priceFormat: string;
	thousandSeparator: string;
	precision: number;
};
⋮----
export type CountryInfo = {
	currency_code: string;
	currency_pos: SymbolPosition;
... (72 lines truncated)
</file>

<file path="packages/js/currency/.npmrc">
package-lock=false
</file>

<file path="packages/js/currency/babel.config.js">

</file>

<file path="packages/js/currency/build.mjs">

</file>

<file path="packages/js/currency/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [6.0.0](https://www.npmjs.com/package/@woocommerce/currency/v/6.0.0) - 2026-06-10 

-   Major - Update @wordpress/* dependencies to WordPress 6.8 minimum. [#64114]
-   Patch - Move the CommonJS build to prepack so day-to-day development only builds the ESM output. [#64876]
-   Patch - Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking. [#65168]
-   Patch - Replaced patched `@wordpress/data` types with opt-in internal package types. [#63483]
-   Patch - Replaced wireit + tsc package build pipeline with a per-package esbuild script. [#65210]

## [5.0.0](https://www.npmjs.com/package/@woocommerce/currency/v/5.0.0) - 2025-10-27 

-   Patch - Adding dependency to avoid invalid types reference in external plugins. [#52969]
-   Patch - Unformat Shipping Method numeric values before persisting data to the server. [#54181]
-   Patch - Add an explicit note to `CurrencyProps.currency` JSDoc that HTML markup is not supported. [#50726]
-   Patch - Add localiseMonetaryValue function to format a number input for display. [#54181]
-   Minor - Bump jest package dependency to 29.5.x [#60324]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - CI: liverage composer packages cache in lint monorepo job [#52054]
-   Patch - dev: clean-up ci-job config options - remove unused cascading keys [#55863]
-   Patch - Fix pnpm version to 9.1.3 to avoid dependency installation issues. [#50828]
-   Patch - Monorepo: build RAM usage optimization. [#58781]
-   Minor - Monorepo: bump pnpm version to 9.15.0 [#54189]
-   Patch - Monorepo: consolidate @babel/* dependencies versions across the monorepo. [#56575]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Monorepo: consolidate syncpack config around React 17/18 usage. [#52022]
-   Patch - Monorepo: consolidate TypeScript config files and JS test directories naming. [#52191]
-   Patch - Monorepo: drop the unused `concurrently` package from dependencies. [#58765]
... (40 lines truncated)
</file>

<file path="packages/js/currency/composer.json">
{
	"name": "woocommerce/currency",
	"description": "WooCommerce JS currency utils",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/currency/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/currency/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/currency/package.json">
{
	"name": "@woocommerce/currency",
	"version": "6.0.0",
	"description": "WooCommerce currency utilities.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"keywords": [
		"wordpress",
		"woocommerce",
		"currency"
	],
	"engines": {
		"node": "^24.15.0"
	},
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/currency/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
... (97 lines truncated)
</file>

<file path="packages/js/currency/PREVIOUS_CHANGELOG.md">
# 4.0.1

-   Update all js packages with minor/patch version changes. #8392

# 4.0.0

## Breaking changes

-   Update dependencies to support react 17. #8305
-   Drop support for IE11. #8305

# 3.2.1

-   Tweak - Added `useCode` parameter to `formatAmount`, to render currency code instead of symbol. #7575

# 3.2.0

-   Fix commonjs module build, allow package to be built in isolation. #7286

# 3.1.0

-   Return countryInfo as an empty object if not in locale info #6188
-   Localize regional currency information for use during onboarding setup #5969
-   Update dependencies

# 3.0.0

## Breaking changes

-   Currency is now a factory function instead of a class.
... (38 lines truncated)
</file>

<file path="packages/js/currency/README.md">
# Currency

A collection of utilities to display and work with currency values.

## Installation

Install the module

```bash
pnpm install @woocommerce/currency --save
```

_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for ES2015+ such as lower versions of IE then using [core-js](https://github.com/zloirock/core-js) or [@babel/polyfill](https://babeljs.io/docs/en/next/babel-polyfill) will add support for these methods. Learn more about it in [Babel docs](https://babeljs.io/docs/en/next/caveats)._

## Usage

```JS
import CurrencyFactory from '@woocommerce/currency';

const storeCurrency = CurrencyFactory(); // pass store settings into constructor.

// Formats money with a given currency symbol. Uses site's currency settings for formatting,
// from the settings api. Defaults to symbol=`$`, precision=2, decimalSeparator=`.`, thousandSeparator=`,`
const total = storeCurrency.formatAmount( 20.923 ); // '$20.92'

// Get the rounded decimal value of a number at the precision used for the current currency,
// from the settings api. Defaults to 2.
const total = storeCurrency.formatDecimal( '6.2892' ); // 6.29

// Get the string representation of a floating point number to the precision used by the current
... (4 lines truncated)
</file>

<file path="packages/js/currency/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": [
		{
			"path": "../number"
		}
	]
}
</file>

<file path="packages/js/customer-effort-score/changelog/.gitkeep">

</file>

<file path="packages/js/customer-effort-score/changelog/66078-dehoist-react">
Significance: patch
Type: dev
Comment: Declare react/react-dom as devDependencies alongside the existing peerDependencies. Tooling only; no runtime change.
</file>

<file path="packages/js/customer-effort-score/changelog/consolidate-eslint-core-modules">
Significance: patch
Type: dev
Comment: Consolidate the shared `import/core-modules` list into `@woocommerce/eslint-config`. Tooling only; no runtime change.
</file>

<file path="packages/js/customer-effort-score/changelog/dev-eslint-no-floating-promises">
Significance: patch
Type: dev

Add void to intentionally-unawaited promises for the new no-floating-promises lint rule
</file>

<file path="packages/js/customer-effort-score/changelog/fix-39052-normalize-submit-label">
Significance: patch
Type: fix

Normalize customer effort score submit labels while preserving legacy action and queue aliases.
</file>

<file path="packages/js/customer-effort-score/changelog/fix-wooairr-204-ces-container-createelement-import">
Significance: patch
Type: fix

Restore the createElement/Fragment import in CustomerEffortScoreTracksContainer so the published esbuild artifact no longer references unbound identifiers.
</file>

<file path="packages/js/customer-effort-score/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/customer-effort-score/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/customer-effort-score/src/components/customer-effort-score/index.tsx">
import { createElement, useState, useEffect } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { useDispatch } from '@wordpress/data';
⋮----
import { CustomerFeedbackModal } from '../customer-feedback-modal';
⋮----
const noop = () =>
⋮----
export type CustomerEffortScoreProps = {
	recordScoreCallback: (
		score: number,
		secondScore: number,
		comments: string
	) => void;
	title?: string;
	description?: string;
	showDescription?: boolean;
	noticeLabel?: string;
	firstQuestion: string;
	secondQuestion?: string;
	onNoticeShownCallback?: () => void;
	onNoticeDismissedCallback?: () => void;
	onModalShownCallback?: () => void;
	onModalDismissedCallback?: () => void;
	icon?: React.ReactElement | null;
	shouldShowComments?: (
		firstQuestionScore: number,
		secondQuestionScore: number
	) => boolean;
	getExtraFieldsToBeShown?: (
... (24 lines truncated)
</file>

<file path="packages/js/customer-effort-score/src/components/customer-effort-score-modal-container/index.tsx">
import { __ } from '@wordpress/i18n';
import { useDispatch, useSelect } from '@wordpress/data';
import { optionsStore } from '@woocommerce/data';
import { createElement } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { CustomerFeedbackModal } from '../customer-feedback-modal';
import { getStoreAgeInWeeks } from '../../utils';
import { ADMIN_INSTALL_TIMESTAMP_OPTION_NAME } from '../../constants';
import store from '../../store';
⋮----
export const CustomerEffortScoreModalContainer = () =>
⋮----
const recordScore = (
		score: number,
		secondScore: number,
		comments: string,
		extraFieldsValues: { [ key: string ]: string } = {}
) =>
</file>

<file path="packages/js/customer-effort-score/src/components/customer-effort-score-tracks/index.js">
function _CustomerEffortScoreTracks( {
	action,
	trackProps,
	title,
	description,
	noticeLabel,
	firstQuestion,
	secondQuestion,
	icon,
	onSubmitLabel = __( 'Thank you for your feedback!', 'woocommerce' ),
	cesShownForActions,
	allowTracking,
	resolving,
	storeAgeInWeeks,
	createNotice,
} )
⋮----
const onNoticeShown = () =>
⋮----
const onNoticeDismissed = () =>
⋮----
const onModalDismissed = () =>
⋮----
const onModalShown = () =>
⋮----
const recordScore = ( score, secondScore, comments ) =>
</file>

<file path="packages/js/customer-effort-score/src/components/customer-effort-score-tracks-container/index.js">
function _CustomerEffortScoreTracksContainer( {
	queue,
	resolving,
	clearQueue,
} )
⋮----
clearQueue: () =>
</file>

<file path="packages/js/customer-effort-score/src/components/customer-feedback-modal/index.tsx">
import { createElement, useState } from '@wordpress/element';
import {
	Button,
	Modal,
	RadioControl,
	TextareaControl,
} from '@wordpress/components';
import { Text } from '@woocommerce/experimental';
import { __ } from '@wordpress/i18n';
⋮----
export type CustomerFeedbackModalProps = {
	recordScoreCallback: (
		score: number,
		secondScore: number,
		comments: string,
		extraFieldsValues: { [ key: string ]: string }
	) => void;
	title?: string;
	description?: string;
	showDescription?: boolean;
	firstQuestion: string;
	secondQuestion?: string;
	defaultScore?: number;
	onCloseModal?: () => void;
	customOptions?: { label: string; value: string }[];
	shouldShowComments?: (
		firstQuestionScore: number,
		secondQuestionScore: number
	) => boolean;
	getExtraFieldsToBeShown?: (
... (22 lines truncated)
</file>

<file path="packages/js/customer-effort-score/src/components/customer-feedback-simple/customer-feedback-simple.tsx">
import { createElement } from '@wordpress/element';
import { Button, Tooltip } from '@wordpress/components';
import { Text } from '@woocommerce/experimental';
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
⋮----
export type CustomerFeedbackSimpleProps = {
	onSelect: ( score: number ) => void;
	label: string;
	selectedValue?: number | null;
};
⋮----
export function CustomerFeedbackSimple( {
	onSelect,
	label,
	selectedValue,
}: CustomerFeedbackSimpleProps )
</file>

<file path="packages/js/customer-effort-score/src/components/customer-feedback-simple/index.ts">

</file>

<file path="packages/js/customer-effort-score/src/components/feedback-modal/feedback-modal.tsx">
import { createElement, useState } from '@wordpress/element';
import { Button, Modal } from '@wordpress/components';
import { Text } from '@woocommerce/experimental';
import clsx from 'clsx';
⋮----
export type FeedbackModalProps = {
	onSubmit: () => void;
	title: string;
	description?: string;
	onModalClose?: () => void;
	onCancel?: () => void;
	children?: JSX.Element;
	isSubmitButtonDisabled?: boolean;
	submitButtonLabel?: string;
	cancelButtonLabel?: string;
	className?: string;
};
⋮----
const closeModal = () =>
⋮----
className=
</file>

<file path="packages/js/customer-effort-score/src/components/feedback-modal/index.ts">

</file>

<file path="packages/js/customer-effort-score/src/components/index.ts">

</file>

<file path="packages/js/customer-effort-score/src/hooks/use-customer-effort-score-exit-page-tracker/index.ts">
import { useEffect, useRef } from '@wordpress/element';
⋮----
import {
	addCustomerEffortScoreExitPageListener,
	addExitPage,
	removeCustomerEffortScoreExitPageListener,
} from '../../utils/customer-effort-score-exit-page';
⋮----
export const useCustomerEffortScoreExitPageTracker = (
	pageId: string,
	hasUnsavedChanges: boolean
) =>
</file>

<file path="packages/js/customer-effort-score/src/hooks/use-customer-effort-score-modal/index.ts">
import { resolveSelect, useDispatch, useSelect } from '@wordpress/data';
import { optionsStore } from '@woocommerce/data';
⋮----
import { SHOWN_FOR_ACTIONS_OPTION_NAME } from '../../constants';
import { STORE_KEY } from '../../store';
⋮----
export const useCustomerEffortScoreModal = () =>
⋮----
const wasPreviouslyShown = ( action: string ) =>
⋮----
const markCesAsShown = async ( action: string ) =>
⋮----
const showCesModal = (
		surveyProps = {},
		props = {},
		onSubmitNoticeProps = {},
		tracksProps = {}
) =>
</file>

<file path="packages/js/customer-effort-score/src/hooks/index.ts">

</file>

<file path="packages/js/customer-effort-score/src/store/action-types.js">

</file>

<file path="packages/js/customer-effort-score/src/store/actions.js">
export function setCesSurveyQueue( queue )
⋮----
export function addCesSurvey( {
	action,
	title,
	description,
	noticeLabel,
	firstQuestion,
	secondQuestion,
	icon,
	pageNow = window.pagenow,
	adminPage = window.adminpage,
	onSubmitLabel,
	onsubmitLabel,
	onsubmit_label,
	props = {},
} )
⋮----
export function showCesModal(
	surveyProps = {},
	props = {},
	onSubmitNoticeProps = {},
	tracksProps = {}
)
⋮----
/**
 * Hide CES Modal.
 */
export function hideCesModal()
⋮----
... (11 lines truncated)
</file>

<file path="packages/js/customer-effort-score/src/store/constants.js">

</file>

<file path="packages/js/customer-effort-score/src/store/get-on-submit-label.js">
export const getOnSubmitLabel = ( value =
</file>

<file path="packages/js/customer-effort-score/src/store/index.js">

</file>

<file path="packages/js/customer-effort-score/src/store/reducer.js">
const reducer = ( state = DEFAULT_STATE, action ) =>
</file>

<file path="packages/js/customer-effort-score/src/store/resolvers.js">
export function* getCesSurveyQueue()
</file>

<file path="packages/js/customer-effort-score/src/store/selectors.js">
export function getCesSurveyQueue( state )
⋮----
export function getVisibleCESModalData( state )
⋮----
export function isProductMVPFeedbackModalVisible( state )
</file>

<file path="packages/js/customer-effort-score/src/utils/customer-effort-score-exit-page.ts">
import { __ } from '@wordpress/i18n';
import { optionsStore } from '@woocommerce/data';
import { dispatch, resolveSelect } from '@wordpress/data';
import { getQuery } from '@woocommerce/navigation';
⋮----
import { ALLOW_TRACKING_OPTION_NAME } from '../constants';
import store from '../store';
⋮----
interface AdminWindow extends Window {
	pagenow?: string;
	adminpage?: string;
}
⋮----
export const getExitPageData = () =>
⋮----
const isTrackingAllowed = async () =>
⋮----
export const addExitPage = async ( pageId: string ) =>
⋮----
export const removeExitPage = ( pageId: string ) =>
⋮----
export const addCustomerEffortScoreExitPageListener = (
	pageId: string,
	hasUnsavedChanges: () => boolean
) =>
⋮----
export const removeCustomerEffortScoreExitPageListener = ( pageId: string ) =>
⋮----
function getExitPageCESCopy( pageId: string )
⋮----
... (4 lines truncated)
</file>

<file path="packages/js/customer-effort-score/src/utils/get-store-age-in-weeks.ts">
import { WEEK } from '@woocommerce/data';
⋮----
export function getStoreAgeInWeeks( adminInstallTimestamp: number )
</file>

<file path="packages/js/customer-effort-score/src/utils/index.ts">

</file>

<file path="packages/js/customer-effort-score/src/constants.js">

</file>

<file path="packages/js/customer-effort-score/src/index.ts">

</file>

<file path="packages/js/customer-effort-score/typings/index.d.ts">

</file>

<file path="packages/js/customer-effort-score/typings/monorepo-enhancements.d.ts">

</file>

<file path="packages/js/customer-effort-score/.npmrc">
package-lock=false
</file>

<file path="packages/js/customer-effort-score/babel.config.js">

</file>

<file path="packages/js/customer-effort-score/build.mjs">

</file>

<file path="packages/js/customer-effort-score/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [4.0.0](https://www.npmjs.com/package/@woocommerce/customer-effort-score/v/4.0.0) - 2026-06-11 

-   Major - Update @wordpress/* dependencies to WordPress 6.8 minimum. [#64114]
-   Major - Updated declared dependencies to React 18 and WordPress 6.6. [#53531]
-   Minor - Bump jest package dependency to 29.5.x. [#60324]
-   Minor - Fix typos in inline documentation. [#48640]
-   Minor - Fix: Responsiveness of CES feedback form. [#52938]
-   Minor - Improve build time for customer-effort-score by using webpack filesystem cache. [#64082]
-   Minor - Monorepo: bump pnpm version to 9.15.0. [#54189]
-   Minor - Update store registration to use createReduxStore and fix type errors. [#55584]
-   Minor - Upgraded TypeScript in the monorepo to 5.7.2. [#53165]
-   Patch - A fix a bug where users need to click Give feedback twice. [#52556]
-   Patch - Added `__nextHasNoMarginBottom` prop to various WordPress components and updated styling to support WordPress 6.7+ margin style changes. [#56257]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - CI: leverage composer packages cache in lint monorepo job. [#52054]
-   Patch - Clean up CI job config options; remove unused cascading keys. [#55863]
-   Patch - Drop the default pencil icon from CES snackbars so they render without cross-platform glyph rendering issues and alignment quirks; callers can still pass an explicit icon when needed. [#64357]
-   Patch - Fix "description" prop ignored in CustomerEffortScoreModalContainer. [#55747]
-   Patch - Fix broken CES style for WP 6.7. [#52499]
-   Patch - Fix CES options being on two rows when scrollbar is visible. [#55923]
-   Patch - Fix pnpm version to 9.1.3 to avoid dependency installation issues. [#50828]
-   Patch - Fix unstable `useSelect()` return value in feedback button. [#63554]
-   Patch - Migrate from React RC types to direct React Props types with jscodeshift codemod. [#56594]
-   Patch - Monorepo: address circular dependencies surfaced by SWC TDZ. [#64797]
-   Patch - Monorepo: build RAM usage optimization. [#58861]
-   Patch - Monorepo: complete migration from `classnames` package to `clsx`. [#58699]
... (81 lines truncated)
</file>

<file path="packages/js/customer-effort-score/composer.json">
{
	"name": "woocommerce/customer-effort-score",
	"description": "WooCommerce utility to measure user effort.",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/customer-effort-score/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/customer-effort-score/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/customer-effort-score/package.json">
{
	"name": "@woocommerce/customer-effort-score",
	"version": "4.0.0",
	"description": "WooCommerce utility to measure user effort.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"keywords": [
		"wordpress",
		"woocommerce"
	],
	"engines": {
		"node": "^24.15.0"
	},
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/customer-effort-score/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
	"main": "build/index.js",
... (122 lines truncated)
</file>

<file path="packages/js/customer-effort-score/PREVIOUS_CHANGELOG.md">
# 2.0.1

-   Update all js packages with minor/patch version changes. #8392

# 2.0.0

-   Update dependencies to support react 17 #8305

# 1.1.0

-   Fix commonjs module build, allow package to be built in isolation. #7286

# 1.0.0

-   Initial release.
</file>

<file path="packages/js/customer-effort-score/README.md">
# Customer Effort Score

WooCommerce utility to measuring user satisfaction.

## Installation

Install the module

```bash
pnpm install @woocommerce/customer-effort-score --save
```

_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for ES2015+ such as lower versions of IE then using [core-js](https://github.com/zloirock/core-js) or [@babel/polyfill](https://babeljs.io/docs/en/next/babel-polyfill) will add support for these methods. Learn more about it in [Babel docs](https://babeljs.io/docs/en/next/caveats)._

## Usage

### CustomerEffortScore component

`CustomerEffortScore` is a React component that can be used to implement your
own effort score survey, providing your own logging infrastructure.

This creates a wrapper component around `CustomerEffortScore` which simply logs
responses to the console:

```js
import CustomerEffortScore from '@woocommerce/customer-effort-score';

export function CustomerEffortScoreConsole( { label } ) {
    const onNoticeShown = () => console.log( 'onNoticeShown' );
    const onModalShown = () => console.log( 'onModalShown' );
... (44 lines truncated)
</file>

<file path="packages/js/customer-effort-score/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": [
		{
			"path": "../experimental"
		}
	]
}
</file>

<file path="packages/js/customer-effort-score/webpack.config.js">

</file>

<file path="packages/js/data/changelog/.gitkeep">

</file>

<file path="packages/js/data/changelog/33593-isolate-leaderboard-queries">
Significance: patch
Type: fix

Prevent stale leaderboard responses from overwriting results for another query.
</file>

<file path="packages/js/data/changelog/50786-add-server-side-search-opt-out">
Significance: minor
Type: add

Add the `woocommerce_admin_report_server_side_search_item_types` filter, so an integration that overrides a report route with a handler that does not read `search` can opt out and keep receiving resolved item IDs.
</file>

<file path="packages/js/data/changelog/50786-fix-analytics-products-search-limit">
Significance: minor
Type: add

Add usesServerSideSearch() and pass the search term straight to report endpoints that resolve it themselves, instead of limiting them to a hydrated list of matching IDs.
</file>

<file path="packages/js/data/changelog/63697-analytics-taxes-taxable-amount">
Significance: minor
Type: add

Add the taxable_amount field to the TaxesReport type.
</file>

<file path="packages/js/data/changelog/65662-dev-65627-postrelease-cleanup">
Significance: major
Type: dev

Update @wordpress/core-data peer dependency to ^7.19.0 to align with WordPress 6.8 minimum.
</file>

<file path="packages/js/data/changelog/66078-dehoist-react">
Significance: patch
Type: dev
Comment: Declare react/react-dom as devDependencies alongside the existing peerDependencies. Tooling only; no runtime change.
</file>

<file path="packages/js/data/changelog/add-60393-activity-panel-store">
Significance: minor
Type: add

Add activityPanelStore with a getActivityPanelCounts selector, backed by a single combined REST request.
</file>

<file path="packages/js/data/changelog/add-onboarding-task-image-metadata">
Significance: minor
Type: add

Add optional imageUrl and imageAlt fields to the onboarding TaskType.
</file>

<file path="packages/js/data/changelog/consolidate-eslint-core-modules">
Significance: patch
Type: dev
Comment: Consolidate the shared `import/core-modules` list into `@woocommerce/eslint-config`. Tooling only; no runtime change.
</file>

<file path="packages/js/data/changelog/dev-eslint-no-floating-promises">
Significance: patch
Type: dev

Add void to intentionally-unawaited promises for the new no-floating-promises lint rule
</file>

<file path="packages/js/data/changelog/fix-68084-plugin-install-error-message">
Significance: patch
Type: fix

Plugin install/activate error messages now read as one sentence instead of splicing the server error onto the frame with a comma.
</file>

<file path="packages/js/data/changelog/fix-analytics-settings-report-cache">
Significance: patch
Type: fix

Return refreshed report data and safely handle errors for unloaded settings groups.
</file>

<file path="packages/js/data/changelog/fix-dismiss-task-list-scope">
Significance: patch
Type: fix

Scope onboarding task dismissal to the supplied task list so a task ID that exists in more than one list is only dismissed or restored in the list it was actioned from.
</file>

<file path="packages/js/data/changelog/fix-wooairr-102-settings-stale-error">
Significance: patch
Type: fix

Keep unsaved settings retryable after a failed save and clear the stored error once a save succeeds.
</file>

<file path="packages/js/data/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/data/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/data/changelog/wooplug-929-settings-alias-docs">
Significance: patch
Type: dev
Comment: Note in the README that wc-store-data is registered in wp-admin only.
</file>

<file path="packages/js/data/src/activity-panel/action-types.ts">
enum TYPES {
	GET_ACTIVITY_PANEL_COUNTS_SUCCESS = 'GET_ACTIVITY_PANEL_COUNTS_SUCCESS',
	GET_ACTIVITY_PANEL_COUNTS_ERROR = 'GET_ACTIVITY_PANEL_COUNTS_ERROR',
}
</file>

<file path="packages/js/data/src/activity-panel/actions.ts">
import TYPES from './action-types';
import { ActivityPanelCounts } from './types';
⋮----
export function getActivityPanelCountsSuccess( counts: ActivityPanelCounts )
⋮----
export function getActivityPanelCountsError( error: unknown )
⋮----
export type Actions = ReturnType<
	typeof getActivityPanelCountsSuccess | typeof getActivityPanelCountsError
>;
</file>

<file path="packages/js/data/src/activity-panel/constants.ts">

</file>

<file path="packages/js/data/src/activity-panel/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
⋮----
import { STORE_NAME } from './constants';
⋮----
import reducer, { type State } from './reducer';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/activity-panel/reducer.ts">
import { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { Actions } from './actions';
import { ActivityPanelState } from './types';
⋮----
const reducer: Reducer< ActivityPanelState, Actions > = (
	state = {},
	payload
) =>
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="packages/js/data/src/activity-panel/resolvers.ts">
import { apiFetch } from '@wordpress/data-controls';
⋮----
import { NAMESPACE } from '../constants';
import {
	getActivityPanelCountsSuccess,
	getActivityPanelCountsError,
} from './actions';
import { ActivityPanelCounts } from './types';
</file>

<file path="packages/js/data/src/activity-panel/selectors.ts">
import { ActivityPanelState } from './types';
⋮----
export const getActivityPanelCounts = ( state: ActivityPanelState ) =>
⋮----
export const getActivityPanelCountsError = ( state: ActivityPanelState ) =>
</file>

<file path="packages/js/data/src/activity-panel/types.ts">
import { WPDataSelector, WPDataSelectors } from '../types';
import {
	getActivityPanelCounts,
	getActivityPanelCountsError,
} from './selectors';
⋮----
export type ActivityPanelCounts = {
	orders_to_fulfill_count: number | null;
	reviews_to_moderate_count: number | null;
	products_low_in_stock_count: number | null;
};
⋮----
export type ActivityPanelState = {
	counts?: ActivityPanelCounts;
	error?: unknown;
};
⋮----
export type ActivityPanelSelectors = {
	getActivityPanelCounts: WPDataSelector< typeof getActivityPanelCounts >;
	getActivityPanelCountsError: WPDataSelector<
		typeof getActivityPanelCountsError
	>;
} & WPDataSelectors;
</file>

<file path="packages/js/data/src/countries/action-types.ts">
export enum TYPES {
	GET_LOCALES_ERROR = 'GET_LOCALES_ERROR',
	GET_LOCALES_SUCCESS = 'GET_LOCALES_SUCCESS',
	GET_COUNTRIES_ERROR = 'GET_COUNTRIES_ERROR',
	GET_COUNTRIES_SUCCESS = 'GET_COUNTRIES_SUCCESS',
	GEOLOCATION_SUCCESS = 'GEOLOCATION_SUCCESS',
	GEOLOCATION_ERROR = 'GEOLOCATION_ERROR',
}
</file>

<file path="packages/js/data/src/countries/actions.ts">
import TYPES from './action-types';
import { Locales, Country, GeolocationResponse } from './types';
⋮----
export function getLocalesSuccess( locales: Locales )
⋮----
export function getLocalesError( error: unknown )
⋮----
export function getCountriesSuccess( countries: Country[] )
⋮----
export function getCountriesError( error: unknown )
⋮----
export function geolocationSuccess( geolocation: GeolocationResponse )
⋮----
export function geolocationError( error: unknown )
⋮----
export type Action = ReturnType<
	| typeof getLocalesSuccess
	| typeof getLocalesError
	| typeof getCountriesSuccess
	| typeof getCountriesError
	| typeof geolocationSuccess
	| typeof geolocationError
>;
</file>

<file path="packages/js/data/src/countries/constants.ts">

</file>

<file path="packages/js/data/src/countries/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
⋮----
import { STORE_NAME } from './constants';
⋮----
import reducer, { type State } from './reducer';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/countries/reducer.ts">
import type { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { Action } from './actions';
import { CountriesState } from './types';
⋮----
const reducer: Reducer< CountriesState, Action > = (
	state = {
		errors: {},
		locales: {},
		countries: [],
		geolocation: undefined,
	},
	action
) =>
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="packages/js/data/src/countries/resolvers.ts">
import { apiFetch, select } from '@wordpress/data-controls';
import { controls } from '@wordpress/data';
⋮----
import {
	getLocalesSuccess,
	getLocalesError,
	getCountriesSuccess,
	getCountriesError,
} from './actions';
import { DispatchFromMap } from '../types';
import { NAMESPACE } from '../constants';
import { Locales, Country, GeolocationResponse } from './types';
import { STORE_NAME } from './constants';
⋮----
export const geolocate =
()
</file>

<file path="packages/js/data/src/countries/selectors.ts">
import { CountriesState } from './types';
⋮----
export const getLocales = ( state: CountriesState ) =>
⋮----
export const getLocale = ( state: CountriesState, id: string ) =>
⋮----
export const getCountries = ( state: CountriesState ) =>
⋮----
export const getCountry = ( state: CountriesState, code: string ) =>
⋮----
export const geolocate = ( state: CountriesState ) =>
</file>

<file path="packages/js/data/src/countries/types.ts">
export type SettingProperties = {
	label?: string;
	label_class?: string[];
	placeholder?: string;
	class?: string[];
	autocomplete?: string;
	priority?: number;
	required?: boolean;
	type?: string;
	hidden?: boolean;
};
⋮----
export type Locale = {
	address_1?: SettingProperties;
	address_2?: SettingProperties;
	city?: SettingProperties;
	company?: SettingProperties;
	first_name?: SettingProperties;
	last_name?: SettingProperties;
	postcode?: SettingProperties;
	state?: SettingProperties;
};
⋮----
export type Country = {
	code: string;
	name: string;
	states: Array< {
		code: string;
		name: string;
	} >;
... (24 lines truncated)
</file>

<file path="packages/js/data/src/crud/action-types.ts">
export enum TYPES {
	CREATE_ITEM_ERROR = 'CREATE_ITEM_ERROR',
	CREATE_ITEM_REQUEST = 'CREATE_ITEM_REQUEST',
	CREATE_ITEM_SUCCESS = 'CREATE_ITEM_SUCCESS',
	DELETE_ITEM_ERROR = 'DELETE_ITEM_ERROR',
	DELETE_ITEM_REQUEST = 'DELETE_ITEM_REQUEST',
	DELETE_ITEM_SUCCESS = 'DELETE_ITEM_SUCCESS',
	GET_ITEM_ERROR = 'GET_ITEM_ERROR',
	GET_ITEM_SUCCESS = 'GET_ITEM_SUCCESS',
	GET_ITEMS_ERROR = 'GET_ITEMS_ERROR',
	GET_ITEMS_SUCCESS = 'GET_ITEMS_SUCCESS',
	UPDATE_ITEM_ERROR = 'UPDATE_ITEM_ERROR',
	UPDATE_ITEM_REQUEST = 'UPDATE_ITEM_REQUEST',
	UPDATE_ITEM_SUCCESS = 'UPDATE_ITEM_SUCCESS',
	GET_ITEMS_TOTAL_COUNT_SUCCESS = 'GET_ITEMS_TOTAL_COUNT_SUCCESS',
	GET_ITEMS_TOTAL_COUNT_ERROR = 'GET_ITEMS_TOTAL_COUNT_ERROR',
}
</file>

<file path="packages/js/data/src/crud/actions.ts">
import { apiFetch } from '@wordpress/data-controls';
⋮----
import { cleanQuery, getUrlParameters, getRestPath, parseId } from './utils';
import CRUD_ACTIONS from './crud-actions';
import TYPES from './action-types';
import { IdType, IdQuery, Item, ItemQuery, CrudActionOptions } from './types';
⋮----
type ResolverOptions< ResourceName extends string > = {
	resourceName: ResourceName;
	namespace: string;
};
⋮----
export function createItemError( query: Partial< ItemQuery >, error: unknown )
⋮----
export function createItemRequest( query: Partial< ItemQuery > )
⋮----
export function createItemSuccess(
	key: IdType,
	item: Item,
	query: Partial< ItemQuery >,
	options?: CrudActionOptions
)
⋮----
export function deleteItemError( key: IdType, error: unknown, force: boolean )
⋮----
export function deleteItemRequest( key: IdType, force: boolean )
⋮----
export function deleteItemSuccess( key: IdQuery, force: boolean, item: Item )
⋮----
export function getItemError( key: IdType, error: unknown )
... (64 lines truncated)
</file>

<file path="packages/js/data/src/crud/crud-actions.ts">
export enum CRUD_ACTIONS {
	CREATE_ITEM = 'CREATE_ITEM',
	DELETE_ITEM = 'DELETE_ITEM',
	GET_ITEM = 'GET_ITEM',
	GET_ITEMS = 'GET_ITEMS',
	GET_ITEMS_TOTAL_COUNT = 'GET_ITEMS_TOTAL_COUNT',
	UPDATE_ITEM = 'UPDATE_ITEM',
}
</file>

<file path="packages/js/data/src/crud/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { AnyAction } from 'redux';
⋮----
import { createSelectors } from './selectors';
import { createDispatchActions } from './actions';
import defaultControls from '../controls';
import { createResolvers } from './resolvers';
import { createReducer, ResourceState } from './reducer';
⋮----
type AnyArguments = any[];
⋮----
interface CrudStoreParams<
	Actions extends Record< string, ( ...args: AnyArguments ) => unknown >,
	Selectors,
	Resolvers = Record< string, ( ...args: AnyArguments ) => unknown >,
	Controls = Record< string, ( ...args: AnyArguments ) => unknown >,
	Reducer extends (
		state: ResourceState | undefined,
		action: AnyAction
	) => ResourceState = (
		state: ResourceState | undefined,
		action: AnyAction
	) => ResourceState,
> {
	storeName: string;
	resourceName: string;
	namespace: string;
	pluralResourceName: string;
	storeConfig?: {
		reducer?: Reducer;
... (21 lines truncated)
</file>

<file path="packages/js/data/src/crud/README.md">
# CRUD Data Stores

The CRUD data store is a set of utilities to allow faster and less error prone creation of data stores that have create, read, update, and delete capabilities.

## Usage

The CRUD data store methods can be used in one of a couple ways.

### Default data store

If the default CRUD actions work well for your use case, you can use the quicker, more opinionated setup.

```js
import { createCrudDataStore } from '../crud';

createCrudDataStore( {
	storeName: 'my/custom/store',
	resourceName: 'MyThing',
	pluralResourceName: 'MyThings',
	namespace: '/my/rest/namespace',
    storeConfig: {
        actions: additionalActions,
        selectors: additionalSelectors,
        resolvers: additionalResolvers,
        controls: additionalControls,
    }
} );
```

#### TypeScript
... (211 lines truncated)
</file>

<file path="packages/js/data/src/crud/reducer.ts">
import { Reducer } from 'redux';
⋮----
import { Actions } from './actions';
import CRUD_ACTIONS from './crud-actions';
import {
	filterDataByKeys,
	getRequestIdentifier,
	organizeItemsById,
} from './utils';
import { getTotalCountResourceName } from '../utils';
import { TYPES } from './action-types';
import type { IdType, Item, ItemQuery } from './types';
⋮----
export type Data = Record< IdType, Item >;
export type ResourceState = {
	items: Record<
		string,
		{
			data: IdType[];
		}
	>;
	data: Data;
	itemsCount: Record< string, number >;
	errors: Record< string, unknown >;
	requesting: Record< string, boolean >;
};
⋮----
export const createReducer = (
	additionalReducer?: Reducer< ResourceState >
) =>
... (14 lines truncated)
</file>

<file path="packages/js/data/src/crud/resolvers.ts">
import { apiFetch } from '@wordpress/data-controls';
import { controls } from '@wordpress/data';
⋮----
import { cleanQuery, getUrlParameters, getRestPath, parseId } from './utils';
import {
	getItemError,
	getItemSuccess,
	getItemsError,
	getItemsSuccess,
	getItemsTotalCountSuccess,
	getItemsTotalCountError,
} from './actions';
import { IdQuery, Item, ItemQuery } from './types';
import { request } from '../utils';
⋮----
type ResolverOptions = {
	storeName: string;
	resourceName: string;
	pluralResourceName: string;
	namespace: string;
};
⋮----
export const createResolvers = ( {
	storeName,
	resourceName,
	pluralResourceName,
	namespace,
}: ResolverOptions ) =>
</file>

<file path="packages/js/data/src/crud/selectors.ts">
import createSelector from 'rememo';
⋮----
import {
	applyNamespace,
	getGenericActionName,
	getRequestIdentifier,
	getUrlParameters,
	maybeReplaceIdQuery,
	parseId,
} from './utils';
import { getTotalCountResourceName } from '../utils';
import { IdQuery, IdType, Item, ItemQuery } from './types';
import { ResourceState } from './reducer';
import CRUD_ACTIONS from './crud-actions';
⋮----
export const getItemCreateError = (
	state: ResourceState,
	query: ItemQuery
) =>
⋮----
export const getItemDeleteError = (
	state: ResourceState,
	idQuery: IdQuery,
	namespace: string
) =>
⋮----
export const getItem = (
	state: ResourceState,
	idQuery: IdQuery,
	namespace: string
... (44 lines truncated)
</file>

<file path="packages/js/data/src/crud/types.ts">
import { BaseQueryParams, WPDataSelector, WPDataSelectors } from '../types';
import {
	getItem,
	getItemError,
	getItems,
	getItemsTotalCount,
	getItemsError,
	getItemCreateError,
	getItemDeleteError,
	getItemUpdateError,
} from './selectors';
⋮----
export type IdType = number | string;
⋮----
export type IdQuery =
	| IdType
	| {
			id: IdType;
			key: IdType;
	  }
	| {
			[ key: string ]: IdType;
	  };
⋮----
export type Item = {
	id: IdType;
	[ key: string ]: unknown;
};
⋮----
export type ItemQuery = BaseQueryParams & {
... (124 lines truncated)
</file>

<file path="packages/js/data/src/crud/utils.ts">
import { addQueryArgs } from '@wordpress/url';
⋮----
import CRUD_ACTIONS from './crud-actions';
import { getResourceName } from '../utils';
import type { IdQuery, IdType, Item, ItemQuery } from './types';
⋮----
export const getRestPath = (
	templatePath: string,
	query: Partial< ItemQuery >,
	parameters: IdType[]
) =>
⋮----
export const getKey = ( query: IdQuery, urlParameters: IdType[] = [] ) =>
⋮----
type organizeItemsByIdReturn = {
	objItems: Record< string, Item >;
	ids: IdType[];
};
⋮----
export const organizeItemsById = (
	items: Item[],
	urlParameters: IdType[] = [],
	currentState: Record< string, Item > = {}
): organizeItemsByIdReturn =>
⋮----
export function filterDataByKeys(
	data: Record< string, unknown >,
	keys: IdType[]
): Record< string, unknown >
⋮----
... (29 lines truncated)
</file>

<file path="packages/js/data/src/export/action-types.ts">

</file>

<file path="packages/js/data/src/export/actions.ts">
import { fetchWithHeaders, FetchWithHeadersResponse } from '../controls';
import TYPES from './action-types';
import { NAMESPACE } from '../constants';
import { SelectorArgs, ExportArgs } from './types';
⋮----
export function setExportId(
	exportType: string,
	exportArgs: ExportArgs,
	exportId: string
)
⋮----
export function setIsRequesting(
	selector: string,
	selectorArgs: SelectorArgs,
	isRequesting: boolean
)
⋮----
export function setError(
	selector: string,
	selectorArgs: SelectorArgs,
	error: unknown
)
⋮----
export type Action = ReturnType<
	typeof setExportId | typeof setError | typeof setIsRequesting
>;
</file>

<file path="packages/js/data/src/export/constants.ts">

</file>

<file path="packages/js/data/src/export/index.ts">
import { registerStore } from '@wordpress/data';
import { Reducer, AnyAction } from 'redux';
⋮----
import { STORE_NAME } from './constants';
⋮----
import reducer, { type State } from './reducer';
import { DispatchFromMap, SelectFromMap, WPDataSelectors } from '../types';
import controls from '../controls';
import { PromiseifySelectors } from '../types/promiseify-selectors';
⋮----
function dispatch(
		key: typeof STORE_NAME
	): DispatchFromMap< typeof actions >;
function select(
		key: typeof STORE_NAME
	): SelectFromMap< typeof selectors > & WPDataSelectors;
function resolveSelect(
		key: typeof STORE_NAME
	): PromiseifySelectors< SelectFromMap< typeof selectors > >;
</file>

<file path="packages/js/data/src/export/reducer.ts">
import type { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { Action } from './actions';
import { hashExportArgs } from './utils';
import { ExportState } from './types';
⋮----
const reducer: Reducer< ExportState, Action > = (
	state = {
		errors: {},
		requesting: {},
		exportMeta: {},
		exportIds: {},
	},
	action
) =>
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="packages/js/data/src/export/selectors.ts">
import { hashExportArgs } from './utils';
import { ExportState, SelectorArgs, ExportArgs } from './types';
⋮----
export const isExportRequesting = (
	state: ExportState,
	selector: string,
	selectorArgs: SelectorArgs
) =>
⋮----
export const getExportId = (
	state: ExportState,
	exportType: string,
	exportArgs: ExportArgs
) =>
⋮----
export const getError = (
	state: ExportState,
	selector: string,
	selectorArgs: SelectorArgs
) =>
</file>

<file path="packages/js/data/src/export/types.ts">
export type ExportArgs = {
	[ key: string ]: unknown;
};
⋮----
export type SelectorArgs = {
	type: string;
	args: ExportArgs;
};
⋮----
export type ExportState = {
	errors: {
		[ selector: string ]: {
			[ hashExportArgs: string ]: unknown;
		};
	};
	requesting: {
		[ selector: string ]: {
			[ hashExportArgs: string ]: boolean;
		};
	};
	exportMeta: {
		[ exportId: string ]: {
			exportType: string;
			exportArgs: ExportArgs;
		};
	};
	exportIds: {
		[ exportType: string ]: {
			[ hashExportArgs: string ]: string;
		};
... (3 lines truncated)
</file>

<file path="packages/js/data/src/export/utils.ts">
import md5 from 'md5';
⋮----
import { getResourceName } from '../utils';
import { ExportArgs } from './types';
⋮----
export const hashExportArgs = ( args: ExportArgs ) =>
</file>

<file path="packages/js/data/src/import/action-types.ts">

</file>

<file path="packages/js/data/src/import/actions.ts">
import { apiFetch } from '@wordpress/data-controls';
⋮----
import TYPES from './action-types';
import {
	ImportStatusQuery,
	ImportStatus,
	ImportTotals,
	ImportTotalsQuery,
} from './types';
⋮----
export function setImportStarted( activeImport: boolean )
⋮----
export function setImportPeriod( date: string, dateModified: boolean )
⋮----
export function setSkipPrevious( skipPrevious: boolean )
⋮----
export function setImportStatus(
	query: ImportStatusQuery,
	importStatus: ImportStatus
)
⋮----
export function setImportTotals(
	query: ImportTotalsQuery,
	importTotals: ImportTotals
)
⋮----
export function setImportError(
	queryOrPath: ImportStatusQuery | ImportTotalsQuery | string,
	error: unknown
)
... (10 lines truncated)
</file>

<file path="packages/js/data/src/import/constants.ts">

</file>

<file path="packages/js/data/src/import/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
import { Reducer, AnyAction } from 'redux';
⋮----
import { STORE_NAME } from './constants';
⋮----
import reducer, { type State } from './reducer';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/import/reducer.ts">
import { __ } from '@wordpress/i18n';
import moment from 'moment';
import type { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { ImportState } from './types';
import { Action } from './actions';
⋮----
const reducer: Reducer< ImportState, Action > = (
	state = {
		activeImport: false,
		importStatus: {},
		importTotals: {},
		errors: {},
		lastImportStartTimestamp: 0,
		period: {
			date: moment().format( __( 'MM/DD/YYYY', 'woocommerce' ) ),
			label: 'all',
		},
		skipPrevious: true,
	},
	action
) =>
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="packages/js/data/src/import/resolvers.ts">
import { addQueryArgs } from '@wordpress/url';
import { apiFetch } from '@wordpress/data-controls';
import { omit } from 'lodash';
⋮----
import { NAMESPACE } from '../constants';
import { setImportError, setImportStatus, setImportTotals } from './actions';
import {
	ImportStatusQuery,
	ImportTotalsQuery,
	ImportStatus,
	ImportTotals,
} from './types';
</file>

<file path="packages/js/data/src/import/selectors.ts">
import { ImportState, ImportStatusQuery, ImportTotalsQuery } from './types';
⋮----
export const getImportStarted = ( state: ImportState ) =>
⋮----
export const getFormSettings = ( state: ImportState ) =>
⋮----
export const getImportStatus = (
	state: ImportState,
	query: ImportStatusQuery
) =>
⋮----
export const getImportTotals = (
	state: ImportState,
	query: ImportTotalsQuery
) =>
⋮----
export const getImportError = (
	state: ImportState,
	query: ImportTotalsQuery | ImportStatusQuery | string
) =>
</file>

<file path="packages/js/data/src/import/types.ts">
type SchedulerName = 'orders' | 'customers';
⋮----
type isImporting = {
	is_importing: boolean;
};
⋮----
type SchedulerImportStatus = {
	[ schedulerName in SchedulerName ]: {
		imported: number;
		totals: number;
	};
} & {
	imported_from?: string | number;
};
⋮----
export type ImportStatus =
	| isImporting
	| ( isImporting & SchedulerImportStatus );
⋮----
export type ImportStatusQuery = number;
⋮----
export type ImportTotals = {
	[ schedulerName in SchedulerName ]: number;
};
⋮----
export type ImportTotalsQuery = {
	skip_existing: boolean;
	days: number;
};
⋮----
... (23 lines truncated)
</file>

<file path="packages/js/data/src/items/action-types.ts">

</file>

<file path="packages/js/data/src/items/actions.ts">
import { apiFetch } from '@wordpress/data-controls';
import { addQueryArgs } from '@wordpress/url';
⋮----
import TYPES from './action-types';
import { NAMESPACE, WC_ADMIN_NAMESPACE } from '../constants';
import { ItemType, Item, ProductItem, Query, ItemID } from './types';
⋮----
export function setItem( itemType: ItemType, id: ItemID, item: Item )
⋮----
export function setItems(
	itemType: ItemType,
	query: Query,
	items: Item[],
	totalCount?: number
)
⋮----
export function setItemsTotalCount(
	itemType: ItemType,
	query: Query,
	totalCount: number
)
⋮----
export function setError(
	itemType: ItemType | 'createProductFromTemplate',
	query: Record< string, unknown >,
	error: unknown
)
⋮----
export type Action = ReturnType<
	| typeof setItem
... (5 lines truncated)
</file>

<file path="packages/js/data/src/items/constants.ts">

</file>

<file path="packages/js/data/src/items/index.ts">
import { createReduxStore, register } from '@wordpress/data';
⋮----
import { STORE_NAME } from './constants';
⋮----
import reducer, { type State } from './reducer';
import controls from '../controls';
import { SelectFromMap, WPDataSelectors } from '../types';
import { getItemsType } from './selectors';
import { PromiseifySelectors } from '../types/promiseify-selectors';
⋮----
export type ItemsSelector = Omit<
	SelectFromMap< typeof selectors >,
	'getItems'
> & {
	getItems: getItemsType;
} & WPDataSelectors;
⋮----
function select( key: typeof STORE_NAME | typeof store ): ItemsSelector;
function resolveSelect(
		key: typeof STORE_NAME | typeof store
	): PromiseifySelectors< ItemsSelector >;
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/items/reducer.ts">
import type { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { getResourceName } from '../utils';
import { getTotalCountResourceName } from './utils';
import { Action } from './actions';
import { ItemsState, Item, ItemID } from './types';
⋮----
const reducer: Reducer< ItemsState, Action > = (
	state = initialState,
	action
) =>
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="packages/js/data/src/items/resolvers.ts">
import { NAMESPACE } from '../constants';
import { setError, setItems, setItemsTotalCount } from './actions';
import { request } from '../utils';
import { ItemType, Query } from './types';
</file>

<file path="packages/js/data/src/items/selectors.ts">
import createSelector from 'rememo';
⋮----
import { getResourceName } from '../utils';
import { getTotalCountResourceName } from './utils';
⋮----
import { ItemType, ItemsState, Query, ItemIDOf, ItemInfer } from './types';
⋮----
export type getItemsType = < T extends ItemType >(
	itemType: T,
	query: Query,
	defaultValue?: Map< ItemIDOf< T >, ItemInfer< T > | undefined >
) => Map< ItemIDOf< T >, ItemInfer< T > | undefined >;
⋮----
type getItemsSelectorType = < T extends ItemType >(
	state: ItemsState,
	itemType: T,
	query: Query,
	defaultValue?: Map< ItemIDOf< T >, ItemInfer< T > | undefined >
) => Map< ItemIDOf< T >, ItemInfer< T > | undefined >;
⋮----
export const getItemsTotalCount = (
	state: ItemsState,
	itemType: ItemType,
	query: Query,
	defaultValue = 0
) =>
⋮----
export const getItemsError = (
	state: ItemsState,
	itemType: ItemType,
... (3 lines truncated)
</file>

<file path="packages/js/data/src/items/store-aware-utils.ts">
import { appendTimestamp, getCurrentDates } from '@woocommerce/date';
import { select as wpSelect } from '@wordpress/data';
⋮----
import { LeaderboardItem, Query } from './types';
import { store as itemsStore } from './';
⋮----
type Options = {
	id: LeaderboardItem[ 'id' ];
	per_page: number;
	persisted_query: Query;
	filterQuery: Query;
	query: { [ key: string ]: string | undefined };
	select: typeof wpSelect;
	defaultDateRange: string;
};
⋮----
export function getLeaderboard( options: Options )
</file>

<file path="packages/js/data/src/items/types.ts">
import { BaseQueryParams } from '../types/query-params';
⋮----
type Link = {
	href: string;
};
⋮----
export type ItemType = 'categories' | 'products' | 'customers' | 'leaderboards';
⋮----
export type ItemIDOf< T extends ItemType > = T extends 'leaderboards'
	? LeaderboardItem[ 'id' ]
	: number;
⋮----
export type ItemID = ItemIDOf< ItemType >;
⋮----
export type ItemImage = {
	id: number;
	date_created: string;
	date_created_gmt: string;
	date_modified: string;
	date_modified_gmt: string;
	src: string;
	name: string;
	alt: string;
};
⋮----
export type CategoryItem = {
	id: number;
	name: string;
	slug: string;
	parent: number;
... (193 lines truncated)
</file>

<file path="packages/js/data/src/items/utils.ts">
import { getResourceName } from '../utils';
import { ItemIDOf, ItemInfer, ItemType, Query } from './types';
import { ItemsSelector } from './';
⋮----
export function searchItemsByString< T extends ItemType >(
	selector: ItemsSelector,
	endpoint: T,
	search: string[],
	options: Query = {}
)
⋮----
export function getTotalCountResourceName( itemType: string, query: Query )
</file>

<file path="packages/js/data/src/navigation/action-types.ts">

</file>

<file path="packages/js/data/src/navigation/actions.ts">
import apiFetch from '@wordpress/api-fetch';
import { getPersistedQuery } from '@woocommerce/navigation';
⋮----
import TYPES from './action-types';
import { WC_ADMIN_NAMESPACE } from '../constants';
import { MenuItem } from './types';
⋮----
export function setMenuItems( menuItems: MenuItem[] )
⋮----
export function addMenuItems( menuItems: MenuItem[] )
⋮----
export function getFavoritesFailure( error: unknown )
⋮----
export function getFavoritesRequest( favorites?: string[] )
⋮----
export function getFavoritesSuccess( favorites: string[] )
⋮----
export function addFavoriteRequest( favorite: string )
⋮----
export function addFavoriteFailure( favorite: string, error: unknown )
⋮----
export function addFavoriteSuccess( favorite: string )
⋮----
export function removeFavoriteRequest( favorite: string )
⋮----
export function removeFavoriteFailure( favorite: string, error: unknown )
⋮----
export function removeFavoriteSuccess( favorite: string )
⋮----
export type Action = ReturnType<
... (17 lines truncated)
</file>

<file path="packages/js/data/src/navigation/constants.ts">

</file>

<file path="packages/js/data/src/navigation/dispatchers.ts">
import { dispatch } from '@wordpress/data';
import { addHistoryListener } from '@woocommerce/navigation';
⋮----
import { STORE_NAME } from './constants';
</file>

<file path="packages/js/data/src/navigation/index.ts">
import { controls } from '@wordpress/data-controls';
import { createReduxStore, register } from '@wordpress/data';
import deprecated from '@wordpress/deprecated';
⋮----
import { STORE_NAME } from './constants';
⋮----
import reducer, { type State } from './reducer';
⋮----
import initDispatchers, { INTERNAL_CALL } from './dispatchers';
import {
	DispatchFromMap,
	SelectFromMap,
	WPDataActions,
	WPDataSelectors,
} from '../types';
import { PromiseifySelectors } from '../types/promiseify-selectors';
⋮----
function wrapWithDeprecate< T extends Record< string, unknown > >( obj: T ): T
⋮----
function dispatch(
		key: typeof STORE_NAME
	): DispatchFromMap< typeof actions & WPDataActions >;
function select(
		key: typeof STORE_NAME
	): SelectFromMap< typeof selectors > & WPDataSelectors;
function resolveSelect(
		key: typeof STORE_NAME
	): PromiseifySelectors< SelectFromMap< typeof selectors > >;
⋮----
interface StoreRegistry {
... (3 lines truncated)
</file>

<file path="packages/js/data/src/navigation/reducer.ts">
import type { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { Action } from './actions';
import { NavigationState } from './types';
⋮----
const reducer: Reducer< NavigationState, Action > = (
	state = {
		error: null,
		menuItems: [],
		favorites: [],
		requesting: {},
		persistedQuery: {},
	},
	action
) =>
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="packages/js/data/src/navigation/resolvers.ts">
import { apiFetch } from '@wordpress/data-controls';
⋮----
import {
	getFavoritesFailure,
	getFavoritesRequest,
	getFavoritesSuccess,
} from './actions';
import { WC_ADMIN_NAMESPACE } from '../constants';
</file>

<file path="packages/js/data/src/navigation/selectors.ts">
import { applyFilters } from '@wordpress/hooks';
⋮----
import { NavigationState } from './types';
⋮----
export const getMenuItems = ( state: NavigationState ) =>
⋮----
export const getFavorites = ( state: NavigationState ) =>
⋮----
export const isNavigationRequesting = (
	state: NavigationState,
	selector: string
) =>
⋮----
export const getPersistedQuery = ( state: NavigationState ) =>
</file>

<file path="packages/js/data/src/navigation/types.ts">
import { getPersistedQuery } from '@woocommerce/navigation';
⋮----
export type MenuItem = {
	id: string;
	title: string;
	url: string;
	order: number;
	migrate: boolean;
	menuId: string;
	isCategory?: boolean;
	badge?: number;
	backButtonLabel?: string;
	parent?: string;
	capability?: string;
	matchExpression?: string;
};
⋮----
export type NavigationState = {
	error: null | unknown;
	menuItems: MenuItem[];
	favorites: string[];
	requesting: {
		[ key: string ]: boolean | unknown;
	};
	persistedQuery: ReturnType< typeof getPersistedQuery >;
};
</file>

<file path="packages/js/data/src/navigation/with-navigation-hydration.tsx">
import { createHigherOrderComponent } from '@wordpress/compose';
import { useSelect, useDispatch } from '@wordpress/data';
import { createElement, useEffect } from '@wordpress/element';
import type { ComponentType } from 'react';
import deprecated from '@wordpress/deprecated';
⋮----
import { STORE_NAME } from './constants';
import { MenuItem } from './types';
⋮----
export const withNavigationHydration = ( data:
</file>

<file path="packages/js/data/src/notes/action-types.ts">

</file>

<file path="packages/js/data/src/notes/actions.ts">
import { apiFetch } from '@wordpress/data-controls';
import { addQueryArgs } from '@wordpress/url';
⋮----
import { DispatchFromMap } from '../types';
import { NAMESPACE } from '../constants';
import TYPES from './action-types';
import { Note, NoteQuery } from './types';
⋮----
export function setNote( noteId: number, noteFields: Note )
⋮----
export function setNoteIsUpdating( noteId: number, isUpdating: boolean )
⋮----
export function setNotes( notes: Note[] )
⋮----
export function setNotesQuery( query: NoteQuery, noteIds: number[] )
⋮----
export function setError( selector: string, error: unknown )
⋮----
export function setIsRequesting( selector: string, isRequesting: boolean )
⋮----
export type Action = ReturnType<
	| typeof setNote
	| typeof setNoteIsUpdating
	| typeof setNotes
	| typeof setNotesQuery
	| typeof setError
	| typeof setIsRequesting
>;
⋮----
export type ActionDispatchers = DispatchFromMap< {
... (7 lines truncated)
</file>

<file path="packages/js/data/src/notes/constants.ts">

</file>

<file path="packages/js/data/src/notes/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { Reducer, AnyAction } from 'redux';
import { controls } from '@wordpress/data-controls';
⋮----
import { STORE_NAME } from './constants';
⋮----
import reducer, { type State } from './reducer';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/notes/reducer.ts">
import type { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { Action } from './actions';
import { NoteState, Note } from './types';
⋮----
const reducer: Reducer< NoteState, Action > = (
	state = {
		errors: {},
		noteQueries: {},
		notes: {},
		requesting: {},
	},
	action
) =>
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="packages/js/data/src/notes/resolvers.ts">
import { addQueryArgs } from '@wordpress/url';
import { apiFetch } from '@wordpress/data-controls';
⋮----
import { NAMESPACE } from '../constants';
import { setNotes, setNotesQuery, setError } from './actions';
import { NoteQuery, Note } from './types';
import { checkUserCapability } from '../utils';
</file>

<file path="packages/js/data/src/notes/selectors.ts">
import createSelector from 'rememo';
⋮----
import { NoteState, NoteQuery } from './types';
⋮----
export const getNotesError = ( state: NoteState, selector: string ) =>
⋮----
export const isNotesRequesting = ( state: NoteState, selector: string ) =>
</file>

<file path="packages/js/data/src/notes/types.ts">
export type NoteAction = {
	id: number;
	name: string;
	label: string;
	query: string;
	status: string;
	actioned_text: string;
	nonce_action: string | null;
	nonce_name: string | null;
	url: string;
};
⋮----
export type NoteStatus =
	| 'pending'
	| 'unactioned'
	| 'actioned'
	| 'snoozed'
	| 'sent';
⋮----
export type NoteType =
	| 'error'
	| 'warning'
	| 'update'
	| 'info'
	| 'marketing'
	| 'survey'
	| 'email';
⋮----
export type Note = {
	id: number;
... (48 lines truncated)
</file>

<file path="packages/js/data/src/onboarding/action-types.ts">

</file>

<file path="packages/js/data/src/onboarding/actions.ts">
import { apiFetch } from '@wordpress/data-controls';
import { controls, dispatch } from '@wordpress/data';
import { addQueryArgs } from '@wordpress/url';
⋮----
import TYPES from './action-types';
import { WC_ADMIN_NAMESPACE } from '../constants';
import { store } from './';
⋮----
import { DeprecatedTasks } from './deprecated-tasks';
import { STORE_NAME as OPTIONS_STORE_NAME } from '../options/constants';
import {
	ExtensionList,
	ProfileItems,
	TaskListType,
	TaskType,
	OnboardingProductTypes,
	InstallAndActivatePluginsAsyncResponse,
	GetJetpackAuthUrlResponse,
	CoreProfilerStep,
	CoreProfilerCompletedSteps,
} from './types';
import { Plugin, PluginNames } from '../plugins/types';
import { store as optionsStore } from '../options';
⋮----
export function getFreeExtensionsError( error: unknown )
⋮----
export function getFreeExtensionsSuccess( freeExtensions: ExtensionList[] )
⋮----
export function setError( selector: string, error: unknown )
⋮----
... (140 lines truncated)
</file>

<file path="packages/js/data/src/onboarding/constants.ts">

</file>

<file path="packages/js/data/src/onboarding/deprecated-tasks.ts">
import { applyFilters } from '@wordpress/hooks';
import { parse } from 'qs';
import deprecated from '@wordpress/deprecated';
⋮----
import { TaskListType, TaskType, DeprecatedTaskType } from './types';
⋮----
function getQuery()
⋮----
export class DeprecatedTasks
⋮----
constructor()
⋮----
hasDeprecatedTasks()
⋮----
getPostData()
⋮----
mergeDeprecatedCallbackFunctions( taskLists: TaskListType[] )
⋮----
static possiblyPruneTaskData( task: TaskType, keys: ( keyof TaskType )[] )
</file>

<file path="packages/js/data/src/onboarding/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
⋮----
import { STORE_NAME } from './constants';
⋮----
import reducer, { type State } from './reducer';
import { SelectFromMap, WPDataSelectors } from '../types';
⋮----
export type OnboardingSelector = SelectFromMap< typeof selectors > &
	WPDataSelectors;
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/onboarding/reducer.ts">
import type { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { Action } from './actions';
import { OnboardingState, TaskListType, TaskType } from './types';
⋮----
const getUpdatedTaskLists = (
	taskLists: Record< string, TaskListType >,
	args: Partial< TaskType >,
	scopedTaskListId?: string
) =>
⋮----
const reducer: Reducer< OnboardingState, Action > = (
	state = defaultState,
	action
) =>
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="packages/js/data/src/onboarding/resolvers.ts">
import { apiFetch, select } from '@wordpress/data-controls';
import { controls } from '@wordpress/data';
⋮----
import { STORE_NAME } from './constants';
import { WC_ADMIN_NAMESPACE } from '../constants';
import {
	getFreeExtensionsError,
	getFreeExtensionsSuccess,
	getTaskListsError,
	getTaskListsSuccess,
	setProfileItems,
	setError,
	setPaymentMethods,
	setEmailPrefill,
	getProductTypesSuccess,
	getProductTypesError,
	setJetpackAuthUrl,
	setProfileProgress,
} from './actions';
import { DeprecatedTasks } from './deprecated-tasks';
import {
	CoreProfilerCompletedSteps,
	ExtensionList,
	GetJetpackAuthUrlResponse,
	OnboardingProductTypes,
	ProfileItems,
	TaskListType,
} from './types';
import { Plugin } from '../plugins/types';
import { checkUserCapability } from '../utils';
... (1 lines truncated)
</file>

<file path="packages/js/data/src/onboarding/selectors.ts">
import createSelector from 'rememo';
⋮----
import {
	TaskType,
	TaskListType,
	OnboardingState,
	ExtensionList,
	ProfileItems,
	GetJetpackAuthUrlResponse,
	CoreProfilerCompletedSteps,
} from './types';
import { WPDataSelectors } from '../types';
import { Plugin } from '../plugins/types';
⋮----
export const getFreeExtensions = (
	state: OnboardingState
): ExtensionList[] =>
⋮----
export const getProfileItems = (
	state: OnboardingState
): ProfileItems | Record< string, never > =>
⋮----
export const getProfileProgress = (
	state: OnboardingState
): Partial< CoreProfilerCompletedSteps > =>
⋮----
export const getTaskList = (
	state: OnboardingState,
	selector: string
): TaskListType | undefined =>
... (55 lines truncated)
</file>

<file path="packages/js/data/src/onboarding/types.ts">
import { Plugin } from '../plugins/types';
⋮----
export type TaskType = {
	actionLabel?: string;
	actionUrl?: string;
	imageUrl?: string;
	imageAlt?: string;
	content: string;
	id: string;
	parentId: string;
	isComplete: boolean;
	isDismissable: boolean;
	isDismissed: boolean;
	isSnoozed: boolean;
	isInProgress: boolean;
	inProgressLabel: string;
	isVisible: boolean;
	isSnoozeable: boolean;
	isDisabled: boolean;
	snoozedUntil: number;
	time: string;
	title: string;
	isVisited: boolean;
	additionalInfo: string;
	canView: boolean;
	isActioned: boolean;
	eventPrefix: string;
	level: 1 | 2 | 3;
	recordViewEvent: boolean;
	badge?: string;
... (219 lines truncated)
</file>

<file path="packages/js/data/src/onboarding/utils.ts">
import { TaskType } from './types';
⋮----
export const getVisibleTasks = ( tasks: TaskType[] )
</file>

<file path="packages/js/data/src/onboarding/with-onboarding-hydration.tsx">
import { createHigherOrderComponent } from '@wordpress/compose';
import { useDispatch, useSelect } from '@wordpress/data';
import { createElement, useEffect, useRef } from '@wordpress/element';
import type { ComponentType } from 'react';
⋮----
import { store } from './';
import { ProfileItems } from './types';
⋮----
export const withOnboardingHydration = ( data: {
	profileItems: ProfileItems;
} ) =>
</file>

<file path="packages/js/data/src/options/action-types.ts">

</file>

<file path="packages/js/data/src/options/actions.ts">
import { apiFetch } from '@wordpress/data-controls';
⋮----
import TYPES from './action-types';
import { WC_ADMIN_NAMESPACE } from '../constants';
import { Options } from './types';
⋮----
export function receiveOptions( options: Options )
⋮----
export function setRequestingError( error: unknown, name: string )
⋮----
export function setUpdatingError( error: unknown )
⋮----
export function setIsUpdating( isUpdating: boolean )
⋮----
export type Action = ReturnType<
	| typeof receiveOptions
	| typeof setRequestingError
	| typeof setUpdatingError
	| typeof setIsUpdating
>;
</file>

<file path="packages/js/data/src/options/constants.ts">

</file>

<file path="packages/js/data/src/options/controls.ts">
import { controls as dataControls } from '@wordpress/data-controls';
import apiFetch from '@wordpress/api-fetch';
⋮----
import { WC_ADMIN_NAMESPACE } from '../constants';
import { debounce } from './utils';
⋮----
export const batchFetch = ( optionName: string ) =>
⋮----
const debouncedFetch = async ( optionName: string ) =>
⋮----
async BATCH_FETCH(
</file>

<file path="packages/js/data/src/options/index.ts">
import { createReduxStore, register } from '@wordpress/data';
⋮----
import { STORE_NAME } from './constants';
⋮----
import reducer, { type State } from './reducer';
import { controls } from './controls';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/options/reducer.ts">
import type { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { Action } from './actions';
import { OptionsState } from './types';
⋮----
const optionsReducer: Reducer< OptionsState, Action > = (
	state = { isUpdating: false, requestingErrors: {} },
	action
) =>
⋮----
export type State = ReturnType< typeof optionsReducer >;
</file>

<file path="packages/js/data/src/options/resolvers.ts">
import { receiveOptions, setRequestingError } from './actions';
import { batchFetch } from './controls';
import { Options } from './types';
</file>

<file path="packages/js/data/src/options/selectors.ts">
import { OptionsState } from './types';
⋮----
export const getOption = ( state: OptionsState, name: string ) =>
⋮----
export const getOptionsRequestingError = (
	state: OptionsState,
	name: string
) =>
⋮----
export const isOptionsUpdating = ( state: OptionsState ) =>
⋮----
export const getOptionsUpdatingError = ( state: OptionsState ) =>
</file>

<file path="packages/js/data/src/options/types.ts">
import { WPDataSelector, WPDataSelectors } from '../types';
import {
	getOptionsRequestingError,
	isOptionsUpdating,
	getOptionsUpdatingError,
} from './selectors';
⋮----
export type OptionsSelectors = {
	getOption: < T = string >( option: string ) => T;
	getOptionsRequestingError: WPDataSelector<
		typeof getOptionsRequestingError
	>;
	isOptionsUpdating: WPDataSelector< typeof isOptionsUpdating >;
	getOptionsUpdatingError: WPDataSelector< typeof getOptionsUpdatingError >;
} & WPDataSelectors;
⋮----
export type Options = {
	[ key: string ]: unknown;
};
⋮----
export type OptionsState = {
	isUpdating: boolean;
	requestingErrors:
		| {
				[ name: string ]: unknown;
		  }
		| Record< string, never >;
	error?: unknown;
	updatingError?: unknown;
} & Options;
... (1 lines truncated)
</file>

<file path="packages/js/data/src/options/utils.ts">
export type DebouncedFunction< T extends ( ...args: any[] ) => any > = ( (
	...args: Parameters< T >
) => void ) & { flush: () => void };
⋮----
export const debounce = < T extends ( ...args: any[] ) => any >(
	func: T,
	wait: number,
	immediate?: boolean
): DebouncedFunction< T > =>
</file>

<file path="packages/js/data/src/options/with-options-hydration.tsx">
import { createHigherOrderComponent } from '@wordpress/compose';
import { useSelect, useDispatch } from '@wordpress/data';
import { createElement, useEffect } from '@wordpress/element';
import type { ComponentType } from 'react';
⋮----
import { store } from './';
import { Options } from './types';
⋮----
export const useOptionsHydration = ( data: Options ) =>
⋮----
export const withOptionsHydration = ( data: Options )
</file>

<file path="packages/js/data/src/orders/action-types.ts">
export enum TYPES {
	GET_ORDER_SUCCESS = 'GET_ORDER_SUCCESS',
	GET_ORDER_ERROR = 'GET_ORDER_ERROR',
	GET_ORDERS_SUCCESS = 'GET_ORDERS_SUCCESS',
	GET_ORDERS_ERROR = 'GET_ORDERS_ERROR',
	GET_ORDERS_TOTAL_COUNT_SUCCESS = 'GET_ORDERS_TOTAL_COUNT_SUCCESS',
	GET_ORDERS_TOTAL_COUNT_ERROR = 'GET_ORDERS_TOTAL_COUNT_ERROR',
}
</file>

<file path="packages/js/data/src/orders/actions.ts">
import TYPES from './action-types';
import { PartialOrder, OrdersQuery } from './types';
⋮----
export function getOrderSuccess( id: number, order: PartialOrder )
⋮----
export function getOrderError( query: Partial< OrdersQuery >, error: unknown )
⋮----
export function getOrdersSuccess(
	query: Partial< OrdersQuery >,
	orders: PartialOrder[],
	totalCount: number
)
⋮----
export function getOrdersError(
	query: Partial< OrdersQuery >,
	error: unknown
)
⋮----
export function getOrdersTotalCountSuccess(
	query: Partial< OrdersQuery >,
	totalCount: number
)
⋮----
export function getOrdersTotalCountError(
	query: Partial< OrdersQuery >,
	error: unknown
)
⋮----
export type Actions = ReturnType<
	| typeof getOrderSuccess
... (7 lines truncated)
</file>

<file path="packages/js/data/src/orders/constants.ts">

</file>

<file path="packages/js/data/src/orders/index.ts">
import { createReduxStore, register } from '@wordpress/data';
⋮----
import { STORE_NAME } from './constants';
⋮----
import controls from '../controls';
import reducer, { type State } from './reducer';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/orders/reducer.ts">
import { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { Actions } from './actions';
import { PartialOrder } from './types';
import { getOrderResourceName, getTotalOrderCountResourceName } from './utils';
⋮----
export type OrdersState = {
	orders: Record<
		string,
		{
			data: number[];
		}
	>;
	ordersCount: Record< string, number >;
	errors: Record< string, unknown >;
	data: Record< number, PartialOrder >;
};
⋮----
const reducer: Reducer< OrdersState, Actions > = (
	state = {
		orders: {},
		ordersCount: {},
		errors: {},
		data: {},
	},
	payload
) =>
⋮----
export type State = ReturnType< typeof reducer >;
... (1 lines truncated)
</file>

<file path="packages/js/data/src/orders/resolvers.ts">
import { WC_ORDERS_NAMESPACE } from './constants';
import { Order, OrdersQuery } from './types';
import {
	getOrdersError,
	getOrdersSuccess,
	getOrdersTotalCountError,
	getOrdersTotalCountSuccess,
} from './actions';
import { request } from '../utils';
</file>

<file path="packages/js/data/src/orders/selectors.ts">
import createSelector from 'rememo';
⋮----
import { getOrderResourceName, getTotalOrderCountResourceName } from './utils';
import { OrdersState } from './reducer';
import { OrdersQuery, PartialOrder } from './types';
import { WPDataSelector, WPDataSelectors } from '../types';
⋮----
export const getOrdersTotalCount = (
	state: OrdersState,
	query: OrdersQuery,
	defaultValue = undefined
) =>
⋮----
export const getOrdersError = ( state: OrdersState, query: OrdersQuery ) =>
⋮----
export type OrdersSelectors = {
	getOrders: WPDataSelector< typeof getOrders >;
	getOrdersTotalCount: WPDataSelector< typeof getOrdersTotalCount >;
	getOrdersError: WPDataSelector< typeof getOrdersError >;
} & WPDataSelectors;
</file>

<file path="packages/js/data/src/orders/types.ts">
import { Post } from '@wordpress/core-data';
⋮----
import { BaseQueryParams } from '../types';
⋮----
export type Address = {
	first_name: string;
	last_name: string;
	company: string;
	address_1: string;
	address_2: string;
	city: string;
	state: string;
	postcode: string;
	country: string;
	email: string;
	phone: string;
};
⋮----
export type OrderTax = {
	id: number;
	total: string;
	subtotal: string;
};
⋮----
export type OrderTaxLine = {
	id: number;
	rate_code: string;
	rate_id: string;
	label: string;
	compound: boolean;
... (127 lines truncated)
</file>

<file path="packages/js/data/src/orders/utils.ts">
import { getResourceName } from '../utils';
import { OrdersQuery } from './types';
⋮----
export function getOrderResourceName( query: Partial< OrdersQuery > )
⋮----
export function getTotalOrderCountResourceName(
	query: Partial< OrdersQuery >
)
</file>

<file path="packages/js/data/src/payment-gateways/action-types.ts">
export enum ACTION_TYPES {
	GET_PAYMENT_GATEWAYS_REQUEST = 'GET_PAYMENT_GATEWAYS_REQUEST',
	GET_PAYMENT_GATEWAYS_SUCCESS = 'GET_PAYMENT_GATEWAYS_SUCCESS',
	GET_PAYMENT_GATEWAYS_ERROR = 'GET_PAYMENT_GATEWAYS_ERROR',
	UPDATE_PAYMENT_GATEWAY_REQUEST = 'UPDATE_PAYMENT_GATEWAY_REQUEST',
	UPDATE_PAYMENT_GATEWAY_SUCCESS = 'UPDATE_PAYMENT_GATEWAY_SUCCESS',
	UPDATE_PAYMENT_GATEWAY_ERROR = 'UPDATE_PAYMENT_GATEWAY_ERROR',
	GET_PAYMENT_GATEWAY_REQUEST = 'GET_PAYMENT_GATEWAY_REQUEST',
	GET_PAYMENT_GATEWAY_SUCCESS = 'GET_PAYMENT_GATEWAY_SUCCESS',
	GET_PAYMENT_GATEWAY_ERROR = 'GET_PAYMENT_GATEWAY_ERROR',
}
</file>

<file path="packages/js/data/src/payment-gateways/actions.ts">
import { apiFetch } from '@wordpress/data-controls';
⋮----
import { ACTION_TYPES } from './action-types';
import { API_NAMESPACE } from './constants';
import { PaymentGateway, PaymentGatewayUpdatePayload } from './types';
⋮----
export function getPaymentGatewaysRequest():
⋮----
export function getPaymentGatewaysSuccess(
	paymentGateways: PaymentGateway[]
):
⋮----
export function getPaymentGatewaysError( error: unknown ):
⋮----
export function getPaymentGatewayRequest():
⋮----
export function getPaymentGatewayError( error: unknown ):
⋮----
export function getPaymentGatewaySuccess( paymentGateway: PaymentGateway ):
⋮----
export function updatePaymentGatewaySuccess( paymentGateway: PaymentGateway ):
export function updatePaymentGatewayRequest():
⋮----
export function updatePaymentGatewayError( error: unknown ):
⋮----
type DeepPartial< T > = {
	[ P in keyof T ]?: DeepPartial< T[ P ] >;
};
⋮----
export type Actions =
... (12 lines truncated)
</file>

<file path="packages/js/data/src/payment-gateways/constants.ts">

</file>

<file path="packages/js/data/src/payment-gateways/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
⋮----
import reducer from './reducer';
import { STORE_KEY } from './constants';
⋮----
interface StoreRegistry {
		[ STORE_KEY ]: typeof store;
	}
</file>

<file path="packages/js/data/src/payment-gateways/reducer.ts">
import { ACTION_TYPES } from './action-types';
import { PluginsState, PaymentGateway } from './types';
import { Actions } from './actions';
⋮----
function updatePaymentGatewayList(
	state: PluginsState,
	paymentGateway: PaymentGateway
): PluginsState
⋮----
const reducer = (
	state: PluginsState = {
		paymentGateways: [],
		isUpdating: false,
		errors: {},
	},
	payload?: Actions
): PluginsState =>
</file>

<file path="packages/js/data/src/payment-gateways/resolvers.ts">
import {
	apiFetch,
	dispatch as depreciatedDispatch,
} from '@wordpress/data-controls';
import { controls } from '@wordpress/data';
⋮----
import {
	getPaymentGatewaysSuccess,
	getPaymentGatewaySuccess,
	getPaymentGatewaysError,
	getPaymentGatewayError,
	getPaymentGatewayRequest,
	getPaymentGatewaysRequest,
} from './actions';
⋮----
import { API_NAMESPACE, STORE_KEY } from './constants';
import { PaymentGateway } from './types';
</file>

<file path="packages/js/data/src/payment-gateways/selectors.ts">
import { PaymentGateway, PluginsState } from './types';
import { WPDataSelector, WPDataSelectors } from '../types';
⋮----
export function getPaymentGateway(
	state: PluginsState,
	id: string
): PaymentGateway | undefined
⋮----
export function getPaymentGateways(
	state: PluginsState
): Array< PaymentGateway >
⋮----
export function getPaymentGatewayError(
	state: PluginsState,
	selector: string
): unknown | null
⋮----
export function isPaymentGatewayUpdating( state: PluginsState ): boolean
⋮----
export type PaymentSelectors = {
	getPaymentGateway: WPDataSelector< typeof getPaymentGateway >;
	getPaymentGateways: WPDataSelector< typeof getPaymentGateways >;
	isPaymentGatewayUpdating: WPDataSelector< typeof isPaymentGatewayUpdating >;
} & WPDataSelectors;
</file>

<file path="packages/js/data/src/payment-gateways/types.ts">
export type SettingDefinition = {
	default: string;
	description: string;
	id: string;
	label: string;
	options?: Record< string, Record< string, string > >;
	placeholder: string;
	tip: string;
	type: string;
	value: string | string[];
	is_dismissed: string;
};
⋮----
export type PaymentGateway< TSettings = Record< string, SettingDefinition > > =
	{
		id: string;
		title: string;
		description: string;
		order: number | '';
		enabled: boolean;
		method_title: string;
		method_description: string;
		method_supports: string[];
		settings: TSettings;
		settings_url: string;
		needs_setup?: boolean;
	};
⋮----
export type PaymentGatewayUpdatePayload = PaymentGateway<
	Record< string, string | string[] >
... (8 lines truncated)
</file>

<file path="packages/js/data/src/payment-settings/action-types.ts">
export enum ACTION_TYPES {
	GET_PAYMENT_PROVIDERS_REQUEST = 'GET_PAYMENT_PROVIDERS_REQUEST',
	GET_PAYMENT_PROVIDERS_SUCCESS = 'GET_PAYMENT_PROVIDERS_SUCCESS',
	GET_PAYMENT_PROVIDERS_ERROR = 'GET_PAYMENT_PROVIDERS_ERROR',
	UPDATE_PROVIDER_ORDERING = 'UPDATE_PROVIDER_ORDERING',
	SET_IS_ELIGIBLE = 'SET_IS_ELIGIBLE',
}
</file>

<file path="packages/js/data/src/payment-settings/actions.ts">
import apiFetch from '@wordpress/api-fetch';
⋮----
import { ACTION_TYPES } from './action-types';
import {
	PaymentsProvider,
	OfflinePaymentMethodProvider,
	OrderMap,
	SuggestedPaymentsExtension,
	SuggestedPaymentsExtensionCategory,
	EnableGatewayResponse,
} from './types';
import { WC_ADMIN_NAMESPACE } from '../constants';
⋮----
export function getPaymentProvidersRequest():
⋮----
export function getPaymentProvidersSuccess(
	providers: PaymentsProvider[],
	offlinePaymentGateways: OfflinePaymentMethodProvider[],
	suggestions: SuggestedPaymentsExtension[],
	suggestionCategories: SuggestedPaymentsExtensionCategory[]
):
⋮----
export function getPaymentProvidersError( error: unknown ):
⋮----
export function updateProviderOrdering( orderMap: OrderMap ):
⋮----
export function setIsWooPayEligible( isEligible: boolean ):
⋮----
export type Actions =
	| ReturnType< typeof getPaymentProvidersRequest >
... (8 lines truncated)
</file>

<file path="packages/js/data/src/payment-settings/constants.ts">

</file>

<file path="packages/js/data/src/payment-settings/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
⋮----
import reducer from './reducer';
import { STORE_KEY } from './constants';
⋮----
interface StoreRegistry {
		[ STORE_KEY ]: typeof store;
	}
</file>

<file path="packages/js/data/src/payment-settings/reducer.ts">
import { ACTION_TYPES } from './action-types';
import { PaymentsSettingsState } from './types';
import { Actions } from './actions';
⋮----
const reducer = (
	state: PaymentsSettingsState = {
		providers: [],
		offlinePaymentGateways: [],
		suggestions: [],
		suggestionCategories: [],
		isFetching: false,
		isWooPayEligible: false,
		errors: {},
	},
	payload?: Actions
): PaymentsSettingsState =>
</file>

<file path="packages/js/data/src/payment-settings/resolvers.ts">
import { apiFetch, select } from '@wordpress/data-controls';
import { controls } from '@wordpress/data';
⋮----
import {
	getPaymentProvidersSuccess,
	getPaymentProvidersError,
	getPaymentProvidersRequest,
	setIsWooPayEligible,
} from './actions';
import { PaymentProvidersResponse, WooPayEligibilityResponse } from './types';
import { WC_ADMIN_NAMESPACE } from '../constants';
import { STORE_KEY } from './constants';
</file>

<file path="packages/js/data/src/payment-settings/selectors.ts">
import {
	PaymentsProvider,
	OfflinePaymentMethodProvider,
	PaymentsSettingsState,
	SuggestedPaymentsExtension,
	SuggestedPaymentsExtensionCategory,
} from './types';
import { WPDataSelector, WPDataSelectors } from '../types';
⋮----
export function getPaymentProviders(
	state: PaymentsSettingsState,
	businessCountry?: string | null
): Array< PaymentsProvider >
⋮----
export function getOfflinePaymentGateways(
	state: PaymentsSettingsState,
	businessCountry?: string | null
): Array< OfflinePaymentMethodProvider >
⋮----
export function getSuggestions(
	state: PaymentsSettingsState,
	businessCountry?: string | null
): Array< SuggestedPaymentsExtension >
⋮----
export function getSuggestionCategories(
	state: PaymentsSettingsState,
	businessCountry?: string | null
): Array< SuggestedPaymentsExtensionCategory >
⋮----
export function isFetching( state: PaymentsSettingsState ): boolean
... (14 lines truncated)
</file>

<file path="packages/js/data/src/payment-settings/types.ts">
export interface PaymentsProviderLink {
	_type: string;
	url: string;
}
⋮----
export interface PluginData {
	_type?: string;
	slug: string;
	file: string;
	status: 'installed' | 'active' | 'not_installed';
}
⋮----
export interface PaymentsProviderState {
	enabled: boolean;
	account_connected: boolean;
	needs_setup: boolean;
	test_mode: boolean;
	dev_mode: boolean;
}
⋮----
export interface LinkData {
	href: string;
}
⋮----
export interface ManagementData {
	_links: {
		settings: LinkData;
	};
}
⋮----
... (198 lines truncated)
</file>

<file path="packages/js/data/src/payment-settings/utils.ts">
export const parseOrdering = < T extends { id: string | number } >(
	items: T[]
) =>
</file>

<file path="packages/js/data/src/plugins/action-types.ts">
export enum ACTION_TYPES {
	UPDATE_ACTIVE_PLUGINS = 'UPDATE_ACTIVE_PLUGINS',
	UPDATE_INSTALLED_PLUGINS = 'UPDATE_INSTALLED_PLUGINS',
	SET_IS_REQUESTING = 'SET_IS_REQUESTING',
	SET_ERROR = 'SET_ERROR',
	UPDATE_JETPACK_CONNECTION = 'UPDATE_JETPACK_CONNECTION',
	UPDATE_JETPACK_CONNECT_URL = 'UPDATE_JETPACK_CONNECT_URL',
	UPDATE_JETPACK_CONNECTION_DATA = 'UPDATE_JETPACK_CONNECTION_DATA',
	SET_PAYPAL_ONBOARDING_STATUS = 'SET_PAYPAL_ONBOARDING_STATUS',
	SET_RECOMMENDED_PLUGINS = 'SET_RECOMMENDED_PLUGINS',
}
</file>

<file path="packages/js/data/src/plugins/actions.ts">
import { apiFetch } from '@wordpress/data-controls';
import { __, _n, sprintf } from '@wordpress/i18n';
import { controls } from '@wordpress/data';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { DispatchFromMap, isRestApiError } from '../types';
import { STORE_NAME } from './constants';
import { ACTION_TYPES as TYPES } from './action-types';
import { WC_ADMIN_NAMESPACE } from '../constants';
import {
	PaypalOnboardingStatus,
	SelectorKeysWithActions,
	RecommendedTypes,
	InstallPluginsResponse,
	ActivatePluginsResponse,
	PluginsResponse,
	PluginNames,
	JetpackConnectionDataResponse,
	Plugin,
} from './types';
⋮----
class PluginError extends Error
⋮----
constructor(
		message: string,
		public data: unknown,
		public actionType: 'install' | 'activate',
		public reason: string
)
⋮----
... (75 lines truncated)
</file>

<file path="packages/js/data/src/plugins/constants.ts">
import { __ } from '@wordpress/i18n';
</file>

<file path="packages/js/data/src/plugins/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
⋮----
import { STORE_NAME } from './constants';
⋮----
import reducer, { type State } from './reducer';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/plugins/reducer.ts">
import { concat } from 'lodash';
import { Reducer } from 'redux';
⋮----
import { ACTION_TYPES as TYPES } from './action-types';
import { Actions } from './actions';
import { PluginsState } from './types';
⋮----
const reducer: Reducer< PluginsState, Actions > = (
	state = {
		active: [],
		installed: [],
		requesting: {},
		errors: {},
		jetpackConnectUrls: {},
		recommended: {},
	},
	payload
) =>
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="packages/js/data/src/plugins/resolvers.ts">
import { apiFetch, select } from '@wordpress/data-controls';
import { controls } from '@wordpress/data';
import { addQueryArgs } from '@wordpress/url';
⋮----
import { WC_ADMIN_NAMESPACE, JETPACK_NAMESPACE } from '../constants';
import { OPTIONS_STORE_NAME } from '../options';
import { PAYPAL_NAMESPACE } from './constants';
import {
	setIsRequesting,
	updateActivePlugins,
	setError,
	updateInstalledPlugins,
	updateIsJetpackConnected,
	updateJetpackConnectUrl,
	updateJetpackConnectionData,
	setPaypalOnboardingStatus,
	setRecommendedPlugins,
} from './actions';
import {
	PaypalOnboardingStatus,
	RecommendedTypes,
	JetpackConnectionDataResponse,
	Plugin,
} from './types';
import { checkUserCapability } from '../utils';
import { store } from './';
⋮----
type PluginGetResponse = {
	plugins: string[];
} & Response;
... (23 lines truncated)
</file>

<file path="packages/js/data/src/plugins/selectors.ts">
import { WPDataSelector, WPDataSelectors } from '../types';
import {
	PluginsState,
	RecommendedTypes,
	SelectorKeysWithActions,
} from './types';
⋮----
export const getActivePlugins = ( state: PluginsState ) =>
⋮----
export const getInstalledPlugins = ( state: PluginsState ) =>
⋮----
export const isPluginsRequesting = (
	state: PluginsState,
	selector: SelectorKeysWithActions
) =>
⋮----
export const getPluginsError = (
	state: PluginsState,
	selector: SelectorKeysWithActions
) =>
⋮----
export const isJetpackConnected = ( state: PluginsState )
⋮----
export const getJetpackConnectionData = ( state: PluginsState )
⋮----
export const getJetpackConnectUrl = (
	state: PluginsState,
	query: { redirect_url: string }
) =>
⋮----
... (22 lines truncated)
</file>

<file path="packages/js/data/src/plugins/types.ts">
import { pluginNames } from './constants';
import { WPError } from '../types';
⋮----
export type RecommendedTypes = 'payments';
⋮----
export type PluginNames = keyof typeof pluginNames;
⋮----
export type SelectorKeysWithActions =
	| 'getActivePlugins'
	| 'getInstalledPlugins'
	| 'getRecommendedPlugins'
	| 'installPlugins'
	| 'activatePlugins'
	| 'isJetpackConnected'
	| 'getJetpackConnectionData'
	| 'getJetpackConnectUrl'
	| 'getPaypalOnboardingStatus';
⋮----
export type PluginsState = {
	active: string[];
	installed: string[];
	requesting: Partial< Record< SelectorKeysWithActions, boolean > >;
	jetpackConnectUrls: Record< string, unknown >;
	jetpackConnection?: boolean;
	jetpackConnectionData?: JetpackConnectionDataResponse;
	recommended: Partial< Record< RecommendedTypes, Plugin[] > >;
	paypalOnboardingStatus?: Partial< PaypalOnboardingStatus >;
	errors: Record< string, unknown >;
};
⋮----
... (94 lines truncated)
</file>

<file path="packages/js/data/src/plugins/with-plugins-hydration.tsx">
import { createHigherOrderComponent } from '@wordpress/compose';
⋮----
import { useSelect, useDispatch } from '@wordpress/data';
import { createElement, useEffect } from '@wordpress/element';
⋮----
import { STORE_NAME } from './constants';
⋮----
type PluginHydrationData = {
	installedPlugins: string[];
	activePlugins: string[];
	jetpackStatus?: { isActive: boolean };
};
export const withPluginsHydration = ( data: PluginHydrationData )
</file>

<file path="packages/js/data/src/product-attribute-terms/constants.ts">

</file>

<file path="packages/js/data/src/product-attribute-terms/index.ts">
import { STORE_NAME, WC_PRODUCT_ATTRIBUTE_TERMS_NAMESPACE } from './constants';
import { createCrudDataStore } from '../crud';
import {
	ProductAttributeTermActions,
	ProductAttributeTermsSelectors,
} from './types';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/product-attribute-terms/types.ts">
import { CrudActions, CrudSelectors } from '../crud/types';
import { DispatchFromMap } from '../types';
⋮----
export type ProductAttributeTermQuery = {
	attribute_id?: number;
	exclude?: number[];
	include?: number[];
	offset?: number;
	order?: string;
};
⋮----
export type ProductAttributeTerm = {
	id: number;
	slug: string;
	name: string;
	description: string;
	menu_order: number;
	count: number;
	attribute_id?: number;
};
⋮----
type Query = {
	context: string;
	page: number;
	per_page: number;
	search: string;
	exclude: number[];
	include: number[];
	offset: number;
	order: string;
... (29 lines truncated)
</file>

<file path="packages/js/data/src/product-attributes/constants.ts">

</file>

<file path="packages/js/data/src/product-attributes/index.ts">
import { STORE_NAME, WC_PRODUCT_ATTRIBUTES_NAMESPACE } from './constants';
import { createCrudDataStore } from '../crud';
import { ProductAttributeSelectors, ProductAttributeActions } from './types';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/product-attributes/types.ts">
import { CrudActions, CrudSelectors } from '../crud/types';
import { DispatchFromMap } from '../types';
⋮----
export type ProductAttribute = {
	id: number;
	slug: string;
	name: string;
	type: string;
	order_by: string;
	has_archives: boolean;
};
⋮----
export type QueryProductAttribute = {
	slug: string;
	name: string;
	type: 'select' | string;
	order_by: string;
	has_archives: boolean;
	generate_slug: boolean;
	attribute_id: number;
};
⋮----
type Query = {
	context?: string;
	order_by?: string;
};
⋮----
type ReadOnlyProperties = 'id';
⋮----
type MutableProperties = Partial<
... (19 lines truncated)
</file>

<file path="packages/js/data/src/product-categories/constants.ts">

</file>

<file path="packages/js/data/src/product-categories/index.ts">
import { STORE_NAME, WC_PRODUCT_CATEGORIES_NAMESPACE } from './constants';
import { createCrudDataStore } from '../crud';
import { ProductCategoryActions, ProductCategorySelectors } from './types';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/product-categories/README.md">
# Product Categories Data Store

This data store provides functions to interact with the [Product Category REST endpoints](https://developer.woocommerce.com/docs/apis/rest-api/v3/product-categories/).
Under the hood this data store makes use of the [CRUD data store](../crud/README.md).

**Note: This data store is listed as experimental still as it is still in active development.**

## Usage

This data store can be accessed under the `experimental/wc/admin/products/categories` name. It is recommended you make use of the export constant `EXPERIMENTAL_PRODUCT_CATEGORIES_STORE_NAME`.

Example:

```js
import { EXPERIMENTAL_PRODUCT_CATEGORIES_STORE_NAME } from '@woocommerce/data';
import { useDispatch } from '@wordpress/data';

function Component() {
	const actions = useDispatch(
		EXPERIMENTAL_PRODUCT_CATEGORIES_STORE_NAME
	);
	actions.createProductCategory( { name: 'test' } );
}
```

## Selections and actions

| Selector                                  | Description                                                                                                        |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `getProductCategory( id: number )`        | Gets a Product Category by ID                                                                                      |
... (14 lines truncated)
</file>

<file path="packages/js/data/src/product-categories/types.ts">
import { CrudActions, CrudSelectors } from '../crud/types';
import { BaseQueryParams, DispatchFromMap } from '../types';
⋮----
export type ProductCategoryImage = {
	id: number;
	date_created: string;
	date_created_gmt: string;
	date_modified: string;
	date_modified_gmt: string;
	src: string;
	name: string;
	alt: string;
};
⋮----
export type ProductCategory = {
	id: number;
	name: string;
	slug: string;
	parent: number;
	description: string;
	display: string;
	image: ProductCategoryImage;
	menu_order: number;
	count: number;
};
⋮----
type Query = Partial< BaseQueryParams< keyof ProductCategory > > & {
	hide_empty?: boolean;
	slug?: string;
	product?: number;
... (23 lines truncated)
</file>

<file path="packages/js/data/src/product-form/action-types.ts">
export enum TYPES {
	GET_FIELDS_ERROR = 'GET_FIELDS_ERROR',
	GET_FIELDS_SUCCESS = 'GET_FIELDS_SUCCESS',
	GET_PRODUCT_FORM_ERROR = 'GET_PRODUCT_FORM_ERROR',
	GET_PRODUCT_FORM_SUCCESS = 'GET_PRODUCT_FORM_SUCCESS',
}
</file>

<file path="packages/js/data/src/product-form/actions.ts">
import TYPES from './action-types';
import { ProductFormField, ProductForm } from './types';
⋮----
export function getFieldsSuccess( fields: ProductFormField[] )
⋮----
export function getFieldsError( error: unknown )
⋮----
export function getProductFormSuccess( productForm: ProductForm )
⋮----
export function getProductFormError( error: unknown )
⋮----
export type Action = ReturnType<
	| typeof getFieldsSuccess
	| typeof getFieldsError
	| typeof getProductFormSuccess
	| typeof getProductFormError
>;
</file>

<file path="packages/js/data/src/product-form/constants.ts">

</file>

<file path="packages/js/data/src/product-form/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
⋮----
import { STORE_NAME } from './constants';
⋮----
import reducer, { type State } from './reducer';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/product-form/reducer.ts">
import type { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { Action } from './actions';
import { ProductFormState } from './types';
⋮----
const reducer: Reducer< ProductFormState, Action > = (
	state = {
		errors: {},
		fields: [],
		sections: [],
		subsections: [],
		tabs: [],
	},
	action
) =>
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="packages/js/data/src/product-form/resolvers.ts">
import { apiFetch } from '@wordpress/data-controls';
⋮----
import {
	getFieldsSuccess,
	getFieldsError,
	getProductFormSuccess,
	getProductFormError,
} from './actions';
import { WC_ADMIN_NAMESPACE } from '../constants';
import { ProductFormField, ProductForm } from './types';
</file>

<file path="packages/js/data/src/product-form/selectors.ts">
import { WPDataSelector, WPDataSelectors } from '../types';
import { ProductFormState } from './types';
⋮----
export const getFields = ( state: ProductFormState ) =>
⋮----
export const getField = ( state: ProductFormState, id: string ) =>
⋮----
export const getProductForm = ( state: ProductFormState ) =>
⋮----
export type ProductFormSelectors = {
	getFields: WPDataSelector< typeof getFields >;
	getField: WPDataSelector< typeof getField >;
	getProductForm: WPDataSelector< typeof getProductForm >;
} & WPDataSelectors;
</file>

<file path="packages/js/data/src/product-form/types.ts">
type BaseComponent = {
	id: string;
	plugin_id: string;
	order: number;
};
⋮----
type FieldProperties = {
	name: string;
	label: string;
};
⋮----
export type ProductFormField = BaseComponent & {
	type: string;
	section: string;
	properties: FieldProperties;
};
⋮----
export type ProductFormSection = BaseComponent & {
	title: string;
	description: string;
	location: string;
};
⋮----
export type Subsection = BaseComponent;
⋮----
export type Tabs = BaseComponent & {
	name: string;
	title: string;
};
⋮----
... (13 lines truncated)
</file>

<file path="packages/js/data/src/product-shipping-classes/constants.ts">

</file>

<file path="packages/js/data/src/product-shipping-classes/index.ts">
import { STORE_NAME, WC_PRODUCT_SHIPPING_CLASSES_NAMESPACE } from './constants';
import { createCrudDataStore } from '../crud';
import {
	ProductShippingClassActions,
	ProductShippingClassSelectors,
} from './types';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/product-shipping-classes/README.md">
# Product Shipping Classes Data Store

This data store provides functions to interact with the [Product Shipping Class REST endpoints](https://developer.woocommerce.com/docs/apis/rest-api/v3/product-shipping-classes/).
Under the hood this data store makes use of the [CRUD data store](../crud/README.md).

**Note: This data store is listed as experimental still as it is still in active development.**

## Usage

This data store can be accessed under the `experimental/wc/admin/products/shipping-classes` name. It is recommended you make use of the export constant `EXPERIMENTAL_PRODUCT_SHIPPING_CLASSES_STORE_NAME`.

Example:

```js
import { EXPERIMENTAL_PRODUCT_SHIPPING_CLASSES_STORE_NAME } from '@woocommerce/data';
import { useDispatch } from '@wordpress/data';

function Component() {
	const actions = useDispatch(
		EXPERIMENTAL_PRODUCT_SHIPPING_CLASSES_STORE_NAME
	);
	actions.createProductShippingClass( { name: 'test' } );
}
```

## Selections and actions

| Selector                                       | Description                                                                                                   |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `getProductShippingClass( id: number )`        | Gets a Product Shipping Class by ID                                                                           |
... (14 lines truncated)
</file>

<file path="packages/js/data/src/product-shipping-classes/types.ts">
import { CrudActions, CrudSelectors } from '../crud/types';
import { BaseQueryParams, DispatchFromMap } from '../types';
⋮----
export type ProductShippingClass = {
	id: number;
	slug: string;
	name: string;
	description: string;
	count: number;
};
⋮----
type Query = BaseQueryParams< keyof ProductShippingClass > & {
	context?: string;
	hide_empty?: boolean;
	slug?: string;
	product?: number;
};
⋮----
type ReadOnlyProperties = 'id';
⋮----
type MutableProperties = Omit< ProductShippingClass, ReadOnlyProperties >;
⋮----
export type ProductShippingClassActions = CrudActions<
	'ProductShippingClass',
	ProductShippingClass,
	MutableProperties
>;
⋮----
export type ProductShippingClassSelectors = CrudSelectors<
	'ProductShippingClass',
... (8 lines truncated)
</file>

<file path="packages/js/data/src/product-tags/constants.ts">

</file>

<file path="packages/js/data/src/product-tags/index.ts">
import { STORE_NAME, WC_PRODUCT_TAGS_NAMESPACE } from './constants';
import { createCrudDataStore } from '../crud';
import { ProductTagActions, ProductTagSelectors } from './types';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/product-tags/types.ts">
import { CrudActions, CrudSelectors } from '../crud/types';
import { DispatchFromMap } from '../types';
⋮----
export type ProductTag = {
	id: number;
	slug: string;
	name: string;
	type: string;
	description: string;
	count: number;
};
⋮----
export type Query = {
	context?: string;
	page: number;
	per_page: number;
	search: string;
	exclude: number[];
	include: number[];
	offset: number;
	order: string;
	orderby: string;
	hide_empty: boolean;
	product: number;
	slug: string;
};
⋮----
type ReadOnlyProperties = 'id' | 'count';
⋮----
type MutableProperties = Partial< Omit< ProductTag, ReadOnlyProperties > >;
... (18 lines truncated)
</file>

<file path="packages/js/data/src/product-variations/action-types.ts">
export enum TYPES {
	GENERATE_VARIATIONS_REQUEST = 'GENERATE_VARIATIONS_REQUEST',
	GENERATE_VARIATIONS_SUCCESS = 'GENERATE_VARIATIONS_SUCCESS',
	GENERATE_VARIATIONS_ERROR = 'GENERATE_VARIATIONS_ERROR',
	BATCH_UPDATE_VARIATIONS_ERROR = 'BATCH_UPDATE_VARIATIONS_ERROR',
}
</file>

<file path="packages/js/data/src/product-variations/actions.ts">
import { apiFetch } from '@wordpress/data-controls';
import { controls } from '@wordpress/data';
⋮----
import { getUrlParameters, getRestPath, parseId } from '../crud/utils';
import TYPES from './action-types';
import { IdQuery, IdType, Item } from '../crud/types';
import { WC_PRODUCT_VARIATIONS_NAMESPACE } from './constants';
import type {
	BatchUpdateRequest,
	BatchUpdateResponse,
	GenerateRequest,
} from './types';
import CRUD_ACTIONS from './crud-actions';
import {
	Product,
	ProductProductAttribute,
	ProductDefaultAttribute,
} from '../products/types';
⋮----
export function generateProductVariationsError( key: IdType, error: unknown )
⋮----
export function generateProductVariationsRequest( key: IdType )
⋮----
export function generateProductVariationsSuccess( key: IdType )
⋮----
export function batchUpdateProductVariationsError(
	key: IdType,
	error: unknown
)
⋮----
... (16 lines truncated)
</file>

<file path="packages/js/data/src/product-variations/constants.ts">

</file>

<file path="packages/js/data/src/product-variations/crud-actions.ts">
export enum CRUD_ACTIONS {
	GENERATE_VARIATIONS = 'GENERATE_VARIATIONS',
}
</file>

<file path="packages/js/data/src/product-variations/index.ts">
import { Reducer } from 'redux';
⋮----
import { STORE_NAME, WC_PRODUCT_VARIATIONS_NAMESPACE } from './constants';
import { createCrudDataStore } from '../crud';
⋮----
import { reducer } from './reducer';
import { ProductVariationActions, ProductVariationSelectors } from './types';
import { ResourceState } from '../crud/reducer';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/product-variations/reducer.ts">
import { Reducer } from 'redux';
⋮----
import { Actions } from './actions';
import { TYPES } from './action-types';
import { ResourceState } from '../crud/reducer';
import { getRequestIdentifier } from '../crud/utils';
import CRUD_ACTIONS from './crud-actions';
⋮----
const reducer: Reducer< ResourceState, Actions > = (
	state = {
		items: {},
		data: {},
		itemsCount: {},
		errors: {},
		requesting: {},
	},
	payload
) =>
</file>

<file path="packages/js/data/src/product-variations/selectors.ts">
import { ResourceState } from '../crud/reducer';
import { IdQuery } from '../crud/types';
import { getRequestIdentifier, getUrlParameters, parseId } from '../crud/utils';
import { WC_PRODUCT_VARIATIONS_NAMESPACE } from './constants';
import CRUD_ACTIONS from './crud-actions';
⋮----
export const isGeneratingVariations = (
	state: ResourceState,
	idQuery: IdQuery
) =>
export const generateProductVariationsError = (
	state: ResourceState,
	idQuery: IdQuery
) =>
⋮----
export type CustomSelectors = {
	isGeneratingVariations: typeof isGeneratingVariations;
	generateProductVariationsError: typeof generateProductVariationsError;
};
</file>

<file path="packages/js/data/src/product-variations/types.ts">
import { CrudActions, CrudSelectors } from '../crud/types';
import { Product, ProductQuery, ReadOnlyProperties } from '../products/types';
import { DispatchFromMap } from '../types';
import { CustomActions } from './actions';
import { CustomSelectors } from './selectors';
⋮----
export type ProductVariationAttribute = {
	id: number;
	name: string;
	slug: string;
	option: string;
};
⋮----
export interface ProductVariationImage {
	id: number;
	readonly date_created?: string;
	readonly date_created_gmt?: string;
	readonly date_modified?: string;
	readonly date_modified_gmt?: string;
	src: string;
	name: string;
	alt: string;
}
⋮----
export type ProductVariation = Omit<
	Product,
	'slug' | 'attributes' | 'images' | 'manage_stock'
> &
	Pick< Product, 'id' > & {
		attributes: ProductVariationAttribute[];
... (57 lines truncated)
</file>

<file path="packages/js/data/src/products/action-types.ts">
export enum TYPES {
	CREATE_PRODUCT_START = 'CREATE_PRODUCT_START',
	CREATE_PRODUCT_ERROR = 'CREATE_PRODUCT_ERROR',
	CREATE_PRODUCT_SUCCESS = 'CREATE_PRODUCT_SUCCESS',
	GET_PRODUCT_SUCCESS = 'GET_PRODUCT_SUCCESS',
	GET_PRODUCT_ERROR = 'GET_PRODUCT_ERROR',
	GET_PRODUCTS_SUCCESS = 'GET_PRODUCTS_SUCCESS',
	GET_PRODUCTS_ERROR = 'GET_PRODUCTS_ERROR',
	GET_PRODUCTS_TOTAL_COUNT_SUCCESS = 'GET_PRODUCTS_TOTAL_COUNT_SUCCESS',
	GET_PRODUCTS_TOTAL_COUNT_ERROR = 'GET_PRODUCTS_TOTAL_COUNT_ERROR',
	UPDATE_PRODUCT_START = 'UPDATE_PRODUCT_START',
	UPDATE_PRODUCT_ERROR = 'UPDATE_PRODUCT_ERROR',
	UPDATE_PRODUCT_SUCCESS = 'UPDATE_PRODUCT_SUCCESS',
	DELETE_PRODUCT_START = 'DELETE_PRODUCT_START',
	DELETE_PRODUCT_ERROR = 'DELETE_PRODUCT_ERROR',
	DELETE_PRODUCT_SUCCESS = 'DELETE_PRODUCT_SUCCESS',
	DUPLICATE_PRODUCT_START = 'DUPLICATE_PRODUCT_START',
	DUPLICATE_PRODUCT_ERROR = 'DUPLICATE_PRODUCT_ERROR',
	DUPLICATE_PRODUCT_SUCCESS = 'DUPLICATE_PRODUCT_SUCCESS',
	SET_SUGGESTED_PRODUCTS = 'SET_SUGGESTED_PRODUCTS',
}
</file>

<file path="packages/js/data/src/products/actions.ts">
import { apiFetch } from '@wordpress/data-controls';
⋮----
import { DispatchFromMap } from '../types';
import TYPES from './action-types';
import {
	ReadOnlyProperties,
	PartialProduct,
	Product,
	ProductQuery,
} from './types';
import { WC_PRODUCT_NAMESPACE } from './constants';
⋮----
export function getProductSuccess( id: number, product: PartialProduct )
⋮----
export function getProductError( productId: number, error: unknown )
⋮----
function createProductStart()
⋮----
function createProductSuccess( id: number, product: Partial< Product > )
⋮----
export function createProductError(
	query: Partial< Product >,
	error: unknown
)
⋮----
function duplicateProductStart( id: number )
⋮----
function duplicateProductSuccess( id: number, product: Partial< Product > )
⋮----
export function duplicateProductError( id: number, error: unknown )
... (69 lines truncated)
</file>

<file path="packages/js/data/src/products/constants.ts">

</file>

<file path="packages/js/data/src/products/index.ts">
import { createReduxStore, register } from '@wordpress/data';
⋮----
import { STORE_NAME } from './constants';
⋮----
import reducer from './reducer';
import controls from '../controls';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/products/reducer.ts">
import { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { Actions } from './actions';
import type {
	PartialProduct,
	Product,
	SuggestedProductOptionsKey,
} from './types';
import {
	getProductResourceName,
	getTotalProductCountResourceName,
} from './utils';
⋮----
export type ProductState = {
	products: Record<
		string,
		{
			data: number[];
		}
	>;
	productsCount: Record< string, number >;
	errors: Record< string, unknown >;
	data: Record< number, PartialProduct >;
	pending: {
		createProduct?: boolean;
		updateProduct?: Record< number, boolean >;
		duplicateProduct?: Record< number, boolean >;
		deleteProduct?: Record< number, boolean >;
	};
... (21 lines truncated)
</file>

<file path="packages/js/data/src/products/resolvers.ts">
import { addQueryArgs } from '@wordpress/url';
import apiFetch from '@wordpress/api-fetch';
⋮----
import {
	apiFetch as controlsApiFetch,
	dispatch as deprecatedDispatch,
	select,
} from '@wordpress/data-controls';
import { controls } from '@wordpress/data';
⋮----
import {
	STORE_NAME,
	WC_PRODUCT_NAMESPACE,
	WC_V3_ENDPOINT_SUGGESTED_PRODUCTS,
} from './constants';
import { GetSuggestedProductsOptions, Product, ProductQuery } from './types';
import {
	getProductError,
	getProductsError,
	getProductsSuccess,
	getProductsTotalCountError,
	getProductsTotalCountSuccess,
	getProductSuccess,
} from './actions';
import { request } from '../utils';
import { createIdFromOptions } from './utils';
⋮----
export const getSuggestedProducts =
( options: GetSuggestedProductsOptions )
</file>

<file path="packages/js/data/src/products/selectors.ts">
import createSelector from 'rememo';
⋮----
import {
	createIdFromOptions,
	getProductResourceName,
	getTotalProductCountResourceName,
} from './utils';
import { WPDataSelector, WPDataSelectors } from '../types';
import { ProductState } from './reducer';
import {
	GetSuggestedProductsOptions,
	PartialProduct,
	ProductQuery,
} from './types';
import { ActionDispatchers } from './actions';
import { PERMALINK_PRODUCT_REGEX } from './constants';
⋮----
export const getProduct = (
	state: ProductState,
	productId: number,
	defaultValue = undefined
) =>
⋮----
export const getProductsTotalCount = (
	state: ProductState,
	query: ProductQuery,
	defaultValue = undefined
) =>
⋮----
export const getProductsError = (
... (40 lines truncated)
</file>

<file path="packages/js/data/src/products/types.ts">
import { Context, Post } from '@wordpress/core-data';
⋮----
import { ProductCategory } from '../product-categories/types';
import { ProductTag } from '../product-tags/types';
import { BaseQueryParams } from '../types';
⋮----
interface PerPackageEntityRecords< C extends Context > {
		woocommerce: Product;
	}
⋮----
export type ProductType =
	| 'simple'
	| 'grouped'
	| 'external'
	| 'variable'
	| 'variation';
export type ProductStatus =
	| 'auto-draft'
	| 'deleted'
	| 'draft'
	| 'pending'
	| 'private'
	| 'publish'
	| 'any'
	| 'trash'
	| 'future';
⋮----
export type ProductDownload = {
	id: string;
	name: string;
... (148 lines truncated)
</file>

<file path="packages/js/data/src/products/utils.ts">
import { getResourceName } from '../utils';
import type { GetSuggestedProductsOptions, ProductQuery } from './types';
⋮----
export function getProductResourceName( query: Partial< ProductQuery > )
⋮----
export function getTotalProductCountResourceName(
	query: Partial< ProductQuery >
)
⋮----
export function createIdFromOptions(
	options: GetSuggestedProductsOptions = {}
): string
</file>

<file path="packages/js/data/src/reviews/action-types.ts">

</file>

<file path="packages/js/data/src/reviews/actions.ts">
import { apiFetch } from '@wordpress/data-controls';
import { addQueryArgs } from '@wordpress/url';
⋮----
import TYPES from './action-types';
import { NAMESPACE } from '../constants';
import { ReviewObject, ReviewObjectUpdate, ReviewsQueryParams } from './types';
⋮----
export function setReviewIsUpdating( reviewId: number, isUpdating: boolean )
⋮----
export function setReview( reviewId: number, reviewData: ReviewObject )
⋮----
export function setError( query: string, error: unknown )
⋮----
export function updateReviews(
	query: ReviewsQueryParams,
	reviews: Array< ReviewObjectUpdate >,
	totalCount: number
)
⋮----
export type Action = ReturnType<
	| typeof updateReviews
	| typeof setReviewIsUpdating
	| typeof setReview
	| typeof setError
>;
</file>

<file path="packages/js/data/src/reviews/constants.ts">

</file>

<file path="packages/js/data/src/reviews/index.ts">
import { createReduxStore, register } from '@wordpress/data';
⋮----
import { STORE_NAME } from './constants';
⋮----
import controls from '../controls';
import reducer, { type State } from './reducer';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/reviews/reducer.ts">
import type { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { Action } from './actions';
import { ReviewObject, ReviewsState } from './types';
⋮----
const reducer: Reducer< ReviewsState, Action > = (
	state = initialState,
	action
) =>
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="packages/js/data/src/reviews/resolvers.ts">
import { addQueryArgs } from '@wordpress/url';
⋮----
import { NAMESPACE } from '../constants';
import { setError, setReview, updateReviews } from './actions';
import { fetchWithHeaders } from '../controls';
import { ReviewObject, ReviewsQueryParams } from './types';
</file>

<file path="packages/js/data/src/reviews/selectors.ts">
import { ReviewsQueryParams, ReviewsState } from './types';
⋮----
export const getReviews = (
	state: ReviewsState,
	query: ReviewsQueryParams
) =>
⋮----
export const getReview = ( state: ReviewsState, id: number ) =>
⋮----
export const getReviewsTotalCount = (
	state: ReviewsState,
	query: ReviewsQueryParams
) =>
⋮----
export const getReviewsError = (
	state: ReviewsState,
	query: ReviewsQueryParams
) =>
⋮----
export const getReviewError = ( state: ReviewsState, id: number ) =>
</file>

<file path="packages/js/data/src/reviews/types.ts">
export interface ReviewObject {
	id: number;
	date_created: string;
	date_created_gmt: string;
	product_id: number;
	product_name: string;
	product_permalink: string;
	status: 'approved' | 'hold' | 'spam' | 'unspam' | 'trash' | 'untrash';
	reviewer: string;
	reviewer_email: string;
	review: string;
	rating: number;
	verified: boolean;
	reviewer_avatar_urls: {
		'24': string;
		'48': string;
		'96': string;
	};
	_embedded?: {
		up?: Array< {
			id: number;
			name?: string;
			slug?: string;
			permalink?: string;
			description?: string;
			short_description?: string;
			images?: Array< {
				id: number;
				date_created?: string;
				date_created_gmt?: string;
... (50 lines truncated)
</file>

<file path="packages/js/data/src/setting-options/action-types.ts">

</file>

<file path="packages/js/data/src/setting-options/actions.ts">
import apiFetch from '@wordpress/api-fetch';
import type { createRegistry } from '@wordpress/data';
import { store as coreDataStore } from '@wordpress/core-data';
⋮----
import { TYPES } from './action-types';
import type {
	Setting,
	SettingValue,
	SettingsGroup,
	APIError,
	BatchSettingsError,
	SettingEdit,
	SettingsEditObject,
	SettingsState,
} from './types';
import { NAMESPACE } from '../constants';
import { STORE_NAME } from './';
⋮----
type WPDataRegistry = ReturnType< typeof createRegistry >;
type Selectors = typeof import('./selectors');
⋮----
type CurriedState< F > = F extends (
	state: SettingsState,
	...args: infer P
) => infer R
	? ( ...args: P ) => R
	: F;
⋮----
type CurriedSelectors< T > = {
	[ K in keyof T ]: CurriedState< T[ K ] >;
... (128 lines truncated)
</file>

<file path="packages/js/data/src/setting-options/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
⋮----
import reducer from './reducer';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/setting-options/README.md">
# Experimental Setting Options Data Store

The setting options data store provides a centralized way to manage WooCommerce settings options, including groups and individual settings. It handles the state management for settings values, unsaved changes, and error states.

## Usage

```js
import { useSelect } from '@wordpress/data';
import { experimentalSettingOptionsStore as settingOptionsStore } from '@woocommerce/data';

function MySettingsComponent() {
	const settings = useSelect( ( select ) => {
		const { getSettings } = select( settingOptionsStore );

		// Get settings without edits
		const originalSettings = getSettings( 'general' );

		// Get settings with edits
		const editedSettings = getSettings( 'general', { includeEdits: true } );

		return { originalSettings, editedSettings };
	}, [] );

	return <div>{ /* Use your settings here */ }</div>;
}
```

## Actions

### `receiveGroups( groups: SettingsGroup[] )`
... (96 lines truncated)
</file>

<file path="packages/js/data/src/setting-options/reducer.ts">
import { TYPES } from './action-types';
import type { Actions } from './actions';
import type { SettingsState, Setting, SettingValue } from './types';
⋮----
const ensureGroupExists = < T >(
	obj: { [ groupId: string ]: T | undefined },
	groupId: string
): T =>
⋮----
const cleanupEmptyGroups = (
	obj: { [ groupId: string ]: { [ key: string ]: unknown } | undefined },
	groupId: string
) =>
⋮----
const reducer = (
	state: SettingsState = DEFAULT_STATE,
	action: Actions
): SettingsState =>
</file>

<file path="packages/js/data/src/setting-options/resolvers.ts">
import apiFetch from '@wordpress/api-fetch';
⋮----
import { receiveGroups, receiveSettings, setError } from './actions';
import type { Setting, SettingsGroup } from './types';
import type { ThunkArgs } from './actions';
import { NAMESPACE } from '../constants';
import { STORE_NAME } from './';
⋮----
export const getGroups =
()
⋮----
export const getSettings =
( groupId: string )
⋮----
export const getSetting =
( groupId: string, settingId: string )
⋮----
export const getSettingValue =
( groupId: string, settingId: string ) => async ( args: ThunkArgs ) =>
</file>

<file path="packages/js/data/src/setting-options/selectors.ts">
import createSelector from 'rememo';
⋮----
import type {
	SettingsState,
	SettingsGroup,
	Setting,
	SettingValue,
} from './types';
⋮----
type SelectorOptions = {
	includeEdits?: boolean;
};
⋮----
export const getGroups = ( state: SettingsState ): SettingsGroup[]
⋮----
export const getGroup = (
	state: SettingsState,
	groupId: string
): SettingsGroup | undefined
⋮----
export const getSettingValue = (
	state: SettingsState,
	groupId: string,
	settingId: string,
	options: SelectorOptions = { includeEdits: false }
): SettingValue | undefined =>
⋮----
export const isSettingEdited = (
	state: SettingsState,
	groupId: string,
... (30 lines truncated)
</file>

<file path="packages/js/data/src/setting-options/types.ts">
export type SettingValue = unknown;
⋮----
export type SettingType =
	| 'text'
	| 'password'
	| 'title'
	| 'multi_select_countries'
	| 'color'
	| 'datetime'
	| 'datetime-local'
	| 'date'
	| 'month'
	| 'time'
	| 'week'
	| 'number'
	| 'email'
	| 'url'
	| 'tel'
	| 'select'
	| 'radio'
	| 'multiselect'
	| 'checkbox'
	| 'relative_date_selector'
	| 'textarea'
	| 'sectionend'
	| 'single_select_page'
	| 'single_select_page_with_search'
	| 'single_select_country'
	| 'slotfill_placeholder';
⋮----
... (82 lines truncated)
</file>

<file path="packages/js/data/src/settings/action-types.ts">

</file>

<file path="packages/js/data/src/settings/actions.ts">
import { __ } from '@wordpress/i18n';
import { apiFetch, select } from '@wordpress/data-controls';
import { controls } from '@wordpress/data';
import { concat } from 'lodash';
⋮----
import { DispatchFromMap } from '../types';
import { NAMESPACE } from '../constants';
import { STORE_NAME } from './constants';
import TYPES from './action-types';
import { Settings } from './types';
⋮----
export function updateSettingsForGroup(
	group: string,
	data: Settings,
	time = new Date()
)
⋮----
export function updateErrorForGroup(
	group: string,
	data: Settings | null,
	error: unknown,
	time = new Date()
)
⋮----
export function setIsRequesting( group: string, isRequesting: boolean )
⋮----
export function clearErrorForGroup( group: string )
⋮----
export function clearIsDirty( group: string )
⋮----
... (16 lines truncated)
</file>

<file path="packages/js/data/src/settings/constants.ts">

</file>

<file path="packages/js/data/src/settings/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
import type { Reducer } from 'redux';
⋮----
import { STORE_NAME } from './constants';
⋮----
import reducer, { type State } from './reducer';
import { SettingsState } from './types';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/settings/reducer.ts">
import { union } from 'lodash';
import { Reducer } from 'redux';
⋮----
import TYPES from './action-types';
import { getResourceName } from '../utils';
import { Actions } from './actions';
import { Settings, SettingsState } from './types';
⋮----
const updateGroupDataInNewState = (
	newState: SettingsState,
	{
		group,
		groupIds,
		data,
		time,
		error,
	}: {
		group: string;
		groupIds: string[];
		data: Settings;
		time: Date;
		error: unknown;
	}
) =>
⋮----
const reducer: Reducer< SettingsState, Actions > = ( state =
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="packages/js/data/src/settings/resolvers.ts">
import {
	apiFetch,
	dispatch as depreciatedDispatch,
} from '@wordpress/data-controls';
import { controls } from '@wordpress/data';
⋮----
import { NAMESPACE } from '../constants';
import { STORE_NAME } from './constants';
import { updateSettingsForGroup, updateErrorForGroup } from './actions';
import { isRestApiError } from '../types';
⋮----
type RawSetting = {
	id: string;
	group_id: string;
	label: string;
	description: string;
	tip?: string;
	type:
		| 'text'
		| 'email'
		| 'number'
		| 'color'
		| 'password'
		| 'textarea'
		| 'select'
		| 'multiselect'
		| 'radio'
		| 'image_width'
		| 'checkbox';
	default: unknown;
... (9 lines truncated)
</file>

<file path="packages/js/data/src/settings/selectors.ts">
import { getResourceName, getResourcePrefix } from '../utils';
import { SettingsState, Settings } from './types';
⋮----
export const getSettingsGroupNames = ( state: SettingsState ) =>
⋮----
export const getSettings = ( state: SettingsState, group: string ) =>
⋮----
export const getDirtyKeys = ( state: SettingsState, group: string ) =>
⋮----
export const getIsDirty = (
	state: SettingsState,
	group: string,
	keys: string[] = []
) =>
⋮----
export const getSettingsForGroup = (
	state: SettingsState,
	group: string,
	keys: string[]
) =>
⋮----
export const isUpdateSettingsRequesting = (
	state: SettingsState,
	group: string
) =>
⋮----
export function getSetting(
	state: SettingsState,
	group: string,
	name: string,
... (15 lines truncated)
</file>

<file path="packages/js/data/src/settings/types.ts">
export type Settings = {
	[ key: string ]: unknown;
} & { siteUrl?: string; shopUrl?: string } & {
	general?: {
		[ key: string ]: string;
	};
	tax?: {
		[ key: string ]: string;
	};
};
⋮----
export type SettingsState = {
	[ key: string ]: {
		data?: unknown;
		lastReceived?: Date;
		error?: unknown;
		isRequesting?: boolean;
		dirty?: string[];
	};
};
</file>

<file path="packages/js/data/src/settings/use-settings.ts">
import { useSelect, useDispatch } from '@wordpress/data';
import { useCallback } from '@wordpress/element';
⋮----
import { store } from './';
import type { Settings } from './types';
⋮----
export const useSettings = ( group: string, settingsKeys: string[] = [] ) =>
</file>

<file path="packages/js/data/src/settings/with-settings-hydration.tsx">
import { createHigherOrderComponent } from '@wordpress/compose';
import { useDispatch, useSelect } from '@wordpress/data';
import { createElement, useRef, useEffect } from '@wordpress/element';
⋮----
import { store } from './';
import { Settings } from './types';
⋮----
export const withSettingsHydration = ( group: string, settings: Settings )
</file>

<file path="packages/js/data/src/shipping-methods/action-types.ts">
export enum ACTION_TYPES {
	GET_SHIPPING_METHODS_REQUEST = 'GET_SHIPPING_METHODS_REQUEST',
	GET_SHIPPING_METHODS_SUCCESS = 'GET_SHIPPING_METHODS_SUCCESS',
	GET_SHIPPING_METHODS_ERROR = 'GET_SHIPPING_METHODS_ERROR',
}
</file>

<file path="packages/js/data/src/shipping-methods/actions.ts">
import { ACTION_TYPES } from './action-types';
import { ShippingMethod } from './types';
⋮----
export function getShippingMethodsRequest()
⋮----
export function getShippingMethodsSuccess( shippingMethods: ShippingMethod[] )
⋮----
export function getShippingMethodsError( error: unknown )
⋮----
export type Actions =
	| ReturnType< typeof getShippingMethodsRequest >
	| ReturnType< typeof getShippingMethodsSuccess >
	| ReturnType< typeof getShippingMethodsError >;
</file>

<file path="packages/js/data/src/shipping-methods/constants.ts">

</file>

<file path="packages/js/data/src/shipping-methods/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
⋮----
import reducer from './reducer';
import { STORE_KEY } from './constants';
⋮----
interface StoreRegistry {
		[ STORE_KEY ]: typeof store;
	}
</file>

<file path="packages/js/data/src/shipping-methods/reducer.ts">
import { Reducer } from 'redux';
⋮----
import { ACTION_TYPES } from './action-types';
import { ShippingMethod } from './types';
import { Actions } from './actions';
⋮----
export type ShippingMethodsState = {
	shippingMethods: ShippingMethod[];
	isUpdating: boolean;
	errors: Record< string, unknown >;
};
⋮----
const reducer: Reducer< ShippingMethodsState, Actions > = (
	state = {
		shippingMethods: [],
		isUpdating: false,
		errors: {},
	},
	payload
) =>
</file>

<file path="packages/js/data/src/shipping-methods/resolvers.ts">
import { apiFetch } from '@wordpress/data-controls';
⋮----
import {
	getShippingMethodsSuccess,
	getShippingMethodsRequest,
	getShippingMethodsError,
} from './actions';
import { ShippingMethod } from './types';
import { WC_ADMIN_NAMESPACE } from '../constants';
</file>

<file path="packages/js/data/src/shipping-methods/selectors.ts">
import { ShippingMethodsState } from './reducer';
import { ShippingMethod } from './types';
import { WPDataSelector, WPDataSelectors } from '../types';
⋮----
export const getShippingMethods = (
	state: ShippingMethodsState
): ShippingMethod[] =>
⋮----
export function isShippingMethodsUpdating(
	state: ShippingMethodsState
): boolean
export type ShippingMethodsSelectors = {
	getShippingMethods: WPDataSelector< typeof getShippingMethods >;
} & WPDataSelectors;
</file>

<file path="packages/js/data/src/shipping-methods/types.ts">
type Feature = {
	icon: string;
	title?: string;
	description: string;
};
⋮----
type Layout = {
	image: string;
	image_label?: string;
	description?: string;
	features: Feature[];
};
⋮----
type LayoutType = 'row' | 'column';
⋮----
export type ShippingMethod = {
	name: string;
	slug: string;
	description: string;
	learn_more_link: string;
	is_visible: boolean;
	available_layouts: LayoutType[];
	layout_column?: Layout;
	layout_row?: Layout;
	dependencies?: string[];
};
</file>

<file path="packages/js/data/src/shipping-zones/constants.ts">

</file>

<file path="packages/js/data/src/shipping-zones/index.ts">
import { STORE_NAME, WC_SHIPPING_ZONES_NAMESPACE } from './constants';
import { createCrudDataStore } from '../crud';
import { ShippingZonesActions, ShippingZonesSelectors } from './types';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/shipping-zones/README.md">
# Shipping Zones Data Store

This data store provides functions to interact with the [Shipping Zones REST endpoints](https://developer.woocommerce.com/docs/apis/rest-api/v3/shipping-zones/).
Under the hood this data store makes use of the [CRUD data store](../crud/README.md).

**Note: This data store is listed as experimental still as it is still in active development.**

## Usage

This data store can be accessed under the `experimental/wc/admin/shipping/zones` name. It is recommended you make use of the export store `experimentalShippingZonesStore`.

Example:

```ts
import {
	experimentalShippingZonesStore,
} from '@woocommerce/data';
import { useDispatch } from '@wordpress/data';

function Component() {
	const actions = useDispatch(
		experimentalShippingZonesStore
	);
	actions.createShippingZone( { name: 'test' } );
}
```

## Selections and actions

| Selector                              | Description                                             |
... (16 lines truncated)
</file>

<file path="packages/js/data/src/shipping-zones/types.ts">
import { CrudActions, CrudSelectors } from '../crud/types';
import { DispatchFromMap } from '../types';
⋮----
export type ShippingZone = {
	id: number;
	name: string;
	order: number;
};
⋮----
type ReadOnlyProperties = 'id';
⋮----
type MutableProperties = Omit< ShippingZone, ReadOnlyProperties >;
⋮----
export type ShippingZonesActions = CrudActions<
	'ShippingZone',
	ShippingZone,
	MutableProperties,
	'name'
>;
⋮----
export type ShippingZonesSelectors = CrudSelectors<
	'ShippingZone',
	'ShippingZones',
	ShippingZone,
	undefined,
	MutableProperties
>;
⋮----
export type ActionDispatchers = DispatchFromMap< ShippingZonesActions >;
</file>

<file path="packages/js/data/src/tax-classes/constants.ts">

</file>

<file path="packages/js/data/src/tax-classes/index.ts">
import { createCrudDataStore } from '../crud';
import { STORE_NAME, WC_TAX_CLASSES_NAMESPACE } from './constants';
⋮----
import { TaxClassActions, TaxClassSelectors } from './types';
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: typeof store;
	}
</file>

<file path="packages/js/data/src/tax-classes/resolvers.ts">
import {
	getItemsError,
	getItemsSuccess,
	getItemsTotalCountError,
	getItemsTotalCountSuccess,
} from '../crud/actions';
import { getUrlParameters, getRestPath, cleanQuery } from '../crud/utils';
import { Item, ItemQuery } from '../crud/types';
import { request } from '../utils';
import { WC_TAX_CLASSES_NAMESPACE } from './constants';
</file>

<file path="packages/js/data/src/tax-classes/types.ts">
import { CrudActions, CrudSelectors } from '../crud/types';
import { BaseQueryParams, DispatchFromMap } from '../types';
⋮----
export interface TaxClass {
	readonly slug: string;
	name: string;
}
⋮----
type Query = BaseQueryParams< keyof TaxClass >;
⋮----
type ReadOnlyProperties = 'slug';
⋮----
type MutableProperties = Omit< TaxClass, ReadOnlyProperties >;
⋮----
export type TaxClassActions = CrudActions<
	'TaxClass',
	TaxClass,
	MutableProperties,
	'name'
>;
⋮----
export type TaxClassSelectors = CrudSelectors<
	'TaxClass',
	'TaxClasses',
	TaxClass,
	Query,
	MutableProperties
>;
⋮----
export type ActionDispatchers = DispatchFromMap< TaxClassActions >;
... (1 lines truncated)
</file>

<file path="packages/js/data/src/types/api.ts">
type WPApiFetchError = {
	code: string;
	message: string;
};
⋮----
type WPInternalServerError = {
	code: string;
	message: string;
	additional_errors: unknown[];
	data: {
		status: number;
	};
};
⋮----
export type RestApiError = WPApiFetchError | WPInternalServerError;
⋮----
export const isRestApiError = ( error: unknown ): error is RestApiError
</file>

<file path="packages/js/data/src/types/index.ts">

</file>

<file path="packages/js/data/src/types/promiseify-selectors.ts">
export type PromiseifySelectors< Selectors > = {
	[ SelectorFunction in keyof Selectors ]: Selectors[ SelectorFunction ] extends (
		...args: infer SelectorArgs
	) => infer SelectorReturnType
		? ( ...args: SelectorArgs ) => Promise< SelectorReturnType >
		: never;
};
</file>

<file path="packages/js/data/src/types/query-params.ts">
export type BaseQueryParams< Fields = string > = {
	context?: string;
	page?: number;
	per_page?: number;
	search?: string;
	after?: string;
	before?: string;
	exclude?: string | number[];
	include?: string | number[];
	offset?: number;
	order?: 'asc' | 'desc';
	orderby?: 'date' | 'id' | 'include' | 'title' | 'slug' | 'menu_order';
	parent?: number[];
	parent_exclude?: number[];
	_fields?: Fields[];
};
</file>

<file path="packages/js/data/src/types/rule-processor.ts">
export type RuleProcessor = {
	type: RuleType;
	value?: string | number | boolean;
	default?: string | number | boolean;
	index?: string;
	operation?: RuleOperation;
	status?: string;
	operand?: RuleProcessor;
	operands?: RuleProcessor[] | RuleProcessor[][];
	option_name?: string;
	plugin?: string;
	plugins?: string[];
	publish_after?: string;
};
⋮----
export type RuleType =
	| 'plugins_activated'
	| 'publish_after_time'
	| 'publish_before_time'
	| 'not'
	| 'or'
	| 'fail'
	| 'pass'
	| 'plugin_version'
	| 'stored_state'
	| 'order_count'
	| 'wcadmin_active_for'
	| 'product_count'
	| 'onboarding_profile'
	| 'is_ecommerce'
... (16 lines truncated)
</file>

<file path="packages/js/data/src/types/wp-data.ts">
export type WPDataSelectors = {
	getIsResolving: ( selector: string, args?: unknown[] ) => boolean;
	hasStartedResolution: ( selector: string, args?: unknown[] ) => boolean;
	hasFinishedResolution: ( selector: string, args?: unknown[] ) => boolean;
	isResolving: ( selector: string, args?: unknown[] ) => boolean;
	getCachedResolvers: () => unknown;
};
⋮----
export type WPDataActions = {
	startResolution: ( selector: string, args?: unknown[] ) => void;
	finishResolution: ( selector: string, args?: unknown[] ) => void;
	invalidateResolution: ( selector: string, args?: unknown[] ) => void;
	invalidateResolutionForStore: ( selector: string ) => void;
	invalidateResolutionForStoreSelector: ( selector: string ) => void;
};
⋮----
export type WPDataSelector< T > = T extends (
	state: infer S,
	...args: infer A
) => infer R
	? ( ...args: A ) => R
	: T;
⋮----
export type WPError< ErrorKey extends string = string, ErrorData = unknown > = {
	errors: Record< ErrorKey, string[] >;
	error_data?: Record< ErrorKey, ErrorData >;
	additional_data?: Record< ErrorKey, ErrorData[] >;
};
⋮----
type GeneratorReturnType< T extends ( ...args: any[] ) => Generator > =
... (32 lines truncated)
</file>

<file path="packages/js/data/src/user/constants.ts">

</file>

<file path="packages/js/data/src/user/index.ts">
import { STORE_NAME } from './constants';
</file>

<file path="packages/js/data/src/user/types.ts">
import type { User, Context } from '@wordpress/core-data';
⋮----
export type UserPreferences = {
	activity_panel_inbox_last_read?: string;
	activity_panel_reviews_last_read?: string;
	android_app_banner_dismissed?: string;
	categories_report_columns?: string;
	coupons_report_columns?: string;
	customers_report_columns?: string;
	dashboard_chart_interval?: string;
	dashboard_chart_type?: string;
	dashboard_leaderboard_rows?: string;
	dashboard_sections?: string;
	homepage_layout?: string;
	homepage_stats?: string;
	orders_report_columns?: string;
	products_report_columns?: string;
	revenue_report_columns?: string;
	task_list_tracked_started_tasks?: {
		[ key: string ]: number;
	};
	taxes_report_columns?: string;
	variable_product_tour_shown?: string;
	variable_product_block_tour_shown?: string;
	variations_report_columns?: string;
	local_attributes_notice_dismissed_ids?: number[];
	variable_items_without_price_notice_dismissed?: Record< number, string >;
	product_advice_card_dismissed?: {
		[ key: string ]: 'yes' | 'no';
	};
... (14 lines truncated)
</file>

<file path="packages/js/data/src/user/use-user-preferences.ts">
import { mapValues } from 'lodash';
import { useDispatch, useSelect } from '@wordpress/data';
⋮----
import { WCUser, UserPreferences } from './types';
import { store } from './';
⋮----
const getWooCommerceMeta = ( user: WCUser ) =>
⋮----
// If we can't parse the value, return the raw data. The meta value could be a string like 'yes' or 'no'.
⋮----
type SaveUserFn = ( userToSave: {
	id: number;
	woocommerce_meta: WCUser[ 'woocommerce_meta' ];
} ) => Promise< WCUser | undefined >;
⋮----
async function updateUserPrefs(
	receiveCurrentUser: ( user: WCUser ) => void,
	user: WCUser,
	saveUser: SaveUserFn,
	getLastEntitySaveError: (
		kind: string,
		name: string,
		recordId: number
	) => unknown,
	userPrefs: UserPreferences
)
⋮----
export const useUserPreferences = () =>
⋮----
const updateUserPreferences = <
... (7 lines truncated)
</file>

<file path="packages/js/data/src/user/use-user.ts">
import { useSelect } from '@wordpress/data';
⋮----
import { store } from './';
import { WCUser } from './types';
⋮----
export const useUser = () =>
⋮----
const currentUserCan = ( capability: string ) =>
</file>

<file path="packages/js/data/src/user/with-current-user-hydration.tsx">
import { createHigherOrderComponent } from '@wordpress/compose';
import { useSelect, useDispatch } from '@wordpress/data';
import { createElement } from '@wordpress/element';
⋮----
import { store } from './';
import { WCUser } from './types';
⋮----
export const withCurrentUserHydration = ( currentUser: WCUser )
</file>

<file path="packages/js/data/src/woopayments-onboarding/actions.ts">
import { OnboardingDataResponse } from './types';
⋮----
export function getOnboardingDataRequest()
⋮----
export function getOnboardingDataSuccess( data: OnboardingDataResponse )
⋮----
export function getOnboardingDataError( error: unknown )
⋮----
export type Action =
	| ReturnType< typeof getOnboardingDataRequest >
	| ReturnType< typeof getOnboardingDataSuccess >
	| ReturnType< typeof getOnboardingDataError >;
</file>

<file path="packages/js/data/src/woopayments-onboarding/constants.ts">

</file>

<file path="packages/js/data/src/woopayments-onboarding/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
⋮----
import reducer from './reducer';
⋮----
import { STORE_KEY } from './constants';
⋮----
interface StoreRegistry {
		[ STORE_KEY ]: typeof store;
	}
</file>

<file path="packages/js/data/src/woopayments-onboarding/reducer.ts">
import { Action } from './actions';
import { OnboardingState } from './types';
⋮----
const reducer = ( state = initialState, action: Action ): OnboardingState =>
</file>

<file path="packages/js/data/src/woopayments-onboarding/resolvers.ts">
import { apiFetch, select } from '@wordpress/data-controls';
⋮----
import { WC_ADMIN_NAMESPACE } from '../constants';
import { OnboardingDataResponse } from './types';
import { STORE_KEY } from './constants';
import {
	getOnboardingDataRequest,
	getOnboardingDataSuccess,
	getOnboardingDataError,
} from './actions';
</file>

<file path="packages/js/data/src/woopayments-onboarding/selectors.ts">
import { OnboardingState } from './types';
import { WPDataSelector, WPDataSelectors } from '../types';
⋮----
export const getOnboardingData = (
	state: OnboardingState,
	sessionEntryPoint?: string | null
): OnboardingState
⋮----
export const isOnboardingDataRequestPending = (
	state: OnboardingState
): boolean
⋮----
export const getOnboardingDataError = ( state: OnboardingState ): unknown
⋮----
export type WooPaymentsOnboardingSelectors = {
	getOnboardingData: WPDataSelector< typeof getOnboardingData >;
	isOnboardingDataRequestPending: WPDataSelector<
		typeof isOnboardingDataRequestPending
	>;
	getOnboardingDataError: WPDataSelector< typeof getOnboardingDataError >;
} & WPDataSelectors;
</file>

<file path="packages/js/data/src/woopayments-onboarding/types.ts">
export interface StepContent {
	id: string;
	label: string;
	path: string;
	order: number;
	status: 'completed' | 'started' | 'not_started';
	dependencies: string[];
	actions: Record< string, unknown >;
	context: object;
}
⋮----
export interface OnboardingState {
	steps: StepContent[];
	context: object;
	isFetching: boolean;
	errors: Record< string, unknown >;
}
⋮----
export type OnboardingDataResponse = {
	steps: StepContent[];
	context: object;
};
</file>

<file path="packages/js/data/src/constants.ts">

</file>

<file path="packages/js/data/src/controls.ts">
import { controls as dataControls } from '@wordpress/data-controls';
import apiFetch, { APIFetchOptions } from '@wordpress/api-fetch';
import { AnyAction } from 'redux';
⋮----
export const fetchWithHeaders = (
	options: APIFetchOptions
): AnyAction &
⋮----
export type FetchWithHeadersResponse< Data > = {
	headers: Response[ 'headers' ];
	status: Response[ 'status' ];
	data: Data;
};
⋮----
FETCH_WITH_HEADERS( action: AnyAction )
</file>

<file path="packages/js/data/src/index.ts">
import type { REVIEWS_STORE_NAME } from './reviews';
import type { SETTINGS_STORE_NAME } from './settings';
import type { PLUGINS_STORE_NAME } from './plugins';
import type { ONBOARDING_STORE_NAME } from './onboarding';
import type { USER_STORE_NAME } from './user';
import type { OPTIONS_STORE_NAME } from './options';
import type { NAVIGATION_STORE_NAME } from './navigation';
import type { NOTES_STORE_NAME } from './notes';
import type { REPORTS_STORE_NAME } from './reports';
import type { ITEMS_STORE_NAME } from './items';
import type { COUNTRIES_STORE_NAME } from './countries';
import type { PAYMENT_GATEWAYS_STORE_NAME } from './payment-gateways';
import type { PAYMENT_SETTINGS_STORE_NAME } from './payment-settings';
import type { WOOPAYMENTS_ONBOARDING_STORE_NAME } from './woopayments-onboarding';
import type { SHIPPING_METHODS_STORE_NAME } from './shipping-methods';
import type { PRODUCTS_STORE_NAME } from './products';
import type { ORDERS_STORE_NAME } from './orders';
import type { EXPERIMENTAL_PRODUCT_ATTRIBUTES_STORE_NAME } from './product-attributes';
import type { EXPERIMENTAL_PRODUCT_SHIPPING_CLASSES_STORE_NAME } from './product-shipping-classes';
import type { EXPERIMENTAL_SHIPPING_ZONES_STORE_NAME } from './shipping-zones';
import type { EXPERIMENTAL_PRODUCT_TAGS_STORE_NAME } from './product-tags';
import type { EXPERIMENTAL_PRODUCT_CATEGORIES_STORE_NAME } from './product-categories';
import type { EXPERIMENTAL_PRODUCT_ATTRIBUTE_TERMS_STORE_NAME } from './product-attribute-terms';
import type { EXPERIMENTAL_PRODUCT_VARIATIONS_STORE_NAME } from './product-variations';
import type { EXPERIMENTAL_TAX_CLASSES_STORE_NAME } from './tax-classes';
import type { EXPERIMENTAL_PRODUCT_FORM_STORE_NAME } from './product-form';
import type { ACTIVITY_PANEL_STORE_NAME } from './activity-panel';
⋮----
export type WCDataStoreName =
	| typeof REVIEWS_STORE_NAME
... (108 lines truncated)
</file>

<file path="packages/js/data/src/use-select-with-refresh.ts">
import { useEffect, useRef } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import type { MapSelect } from '@wordpress/data/build-types/types';
⋮----
const useInterval = (
	callback: ( ...args: unknown[] ) => void,
	interval: Parameters< typeof setInterval >[ 1 ]
) =>
⋮----
const handler = ( ...args: unknown[] ) =>
⋮----
export const useSelectWithRefresh = (
	mapSelectToProps: MapSelect,
	invalidationCallback: Parameters< typeof useInterval >[ 0 ],
	interval: Parameters< typeof useInterval >[ 1 ],
	dependencies?: unknown[]
) =>
</file>

<file path="packages/js/data/src/utils.ts">
import { addQueryArgs } from '@wordpress/url';
import { controls } from '@wordpress/data';
import { apiFetch } from '@wordpress/data-controls';
⋮----
import { BaseQueryParams } from './types/query-params';
import { fetchWithHeaders } from './controls';
import { store as userStore } from './user';
import { WCUser } from './user/types';
⋮----
function replacer( _: string, value: unknown )
⋮----
export function getResourceName( prefix: string, ...identifier: unknown[] )
⋮----
/**
 * Generate a resource name for order totals count.
 *
 * It omits query parameters from the identifier that don't affect
 * totals values like pagination and response field filtering.
 *
 * @param {string} prefix Resource name prefix.
 * @param {Object} query  Query for order totals count.
 * @return {string} Resource name for order totals.
 */
export function getTotalCountResourceName(
	prefix: string,
	query: Record< string, unknown >
)
⋮----
export function getResourcePrefix( resourceName: string )
⋮----
... (11 lines truncated)
</file>

<file path="packages/js/data/typings/index.d.ts">
import { Entity } from '@wordpress/core-data';
</file>

<file path="packages/js/data/typings/monorepo-enhancements.d.ts">

</file>

<file path="packages/js/data/.npmrc">
package-lock=false
</file>

<file path="packages/js/data/babel.config.js">

</file>

<file path="packages/js/data/build.mjs">

</file>

<file path="packages/js/data/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [7.0.0](https://www.npmjs.com/package/@woocommerce/data/v/7.0.0) - 2026-06-11 

-   Major - Update @wordpress/* dependencies to WordPress 6.8 minimum. [#64114]
-   Minor - Add notice property to RecommendedPaymentMethod type for payment method warnings. [#63776]
-   Minor - Add ShipStation and Packlink as shipping extension options in the Core Profiler for supported countries (ShipStation: CA, DE, GB, AU, NZ; Packlink: FR, ES, IT, NL, AT, BE). [#63385]
-   Minor - Navigation store: don't call deprecated onHistoryChange. [#62049]
-   Minor - Update the payments settings types to support payment provider onboarding supported details. [#61574]
-   Patch - Add row layout data to the WooCommerce Shipping partner suggestion so the card renders correctly in row / vertical placements. [#64523]
-   Patch - Allow product queries to type multiple stock statuses. [#65155]
-   Patch - Monorepo: address circular dependencies surfaced by SWC TDZ. [#64797]
-   Patch - Move the CommonJS build to prepack so day-to-day development only builds the ESM output. [#64876]
-   Patch - Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking. [#65168]
-   Patch - Replaced patched `@wordpress/data` types with opt-in internal package types. [#63483]
-   Patch - Replaced wireit + tsc package build pipeline with a per-package esbuild script. [#65210]
-   Patch - Setting options: register the core-data store in tests. [#65375]
-   Patch - Show a clear permission error message when users without install_plugins capability attempt to install plugins. [#64187]
-   Patch - Update @wordpress/* peerDependencies from dist-tags to semver ranges for pnpm 10 compatibility. [#63964]
-   Patch - Update UserPreferences type to include scheduled_updates_promotion_notice_dismissed field. [#62225]
-   Patch - Updates internal references to REST API documentation. [#64720]

## [6.0.0](https://www.npmjs.com/package/@woocommerce/data/v/6.0.0) - 2025-10-27 

-   Minor - Added pre-API call permission checks for some API calls that were being called on non-admin accessible screens [#51406]
-   Patch - Changes to support React powered settings page [#52785]
-   Patch - Fix payment store selector type [#50825]
-   Patch - Fix review store error type [#48415]
... (273 lines truncated)
</file>

<file path="packages/js/data/composer.json">
{
	"name": "woocommerce/data",
	"description": "WooCommerce Admin data store and utilities",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/data/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/data/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/data/package.json">
{
	"name": "@woocommerce/data",
	"version": "7.0.0",
	"description": "WooCommerce Admin data store and utilities",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"keywords": [
		"wordpress",
		"woocommerce",
		"data"
	],
	"engines": {
		"node": "^24.15.0"
	},
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/data/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
... (122 lines truncated)
</file>

<file path="packages/js/data/PREVIOUS_CHANGELOG.md">
# Unreleased

## Breaking change

-   Remove `PaymentMethodsState` type. Use `Plugin` instead. #32683

# 3.1.0

-   Add "moment" to peerDependencies. #8349
-   Update all js packages with minor/patch version changes. #8392
-   Fix type errors. #8392

# 3.0.0

## Breaking changes

-   Update dependencies to support react 17. #8305
-   Drop support for IE11. #8305

# 2.0.0

## Breaking changes

-   Fix the batch fetch logic for the options data store. #7587
-   Add backwards compatibility for old function format. #7688
-   Add console warning for inbox note contents exceeding 320 characters and add dompurify dependency. #7869
-   Fix race condition in data package's options module. #7947
-   Remove dev dependency `@woocommerce/wc-admin-settings`. #8057
-   Update plugins data store actions #8042
-   Add `defaultDateRange` parameter to `getRequestQuery` #8189
... (68 lines truncated)
</file>

<file path="packages/js/data/README.md">
# Data

WooCommerce Admin data store and utilities.

WooCommerce registers the `wc-store-data` script in wp-admin only, so these stores are not available on the storefront or in blocks rendered there. For settings in blocks and storefront code, use `getSetting` from `wc.wcSettings` instead. See [`@woocommerce/settings` in the dependency extraction plugin README](https://github.com/woocommerce/woocommerce/blob/trunk/packages/js/dependency-extraction-webpack-plugin/README.md#woocommercesettings).

## Installation

Install the module

```bash
pnpm install @woocommerce/data --save
```

_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for ES2015+ such as lower versions of IE then using [core-js](https://github.com/zloirock/core-js) or [@babel/polyfill](https://babeljs.io/docs/en/next/babel-polyfill) will add support for these methods. Learn more about it in [Babel docs](https://babeljs.io/docs/en/next/caveats)._

## Usage

```JS
import { settingsStore } from '@woocommerce/data';
import { useSelect } from '@wordpress/data';

function MySettings() {
	const settings = useSelect( select => {
		return select( settingsStore ).getSettings('general').general;
	} );
	return (
		<ul>
			{ Object.keys( settings ?? {} ).map( setting => (
				<li key={ setting }>{ setting }</li>
... (10 lines truncated)
</file>

<file path="packages/js/data/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"noCheck": false,
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": [
		{
			"path": "../date"
		},
		{
			"path": "../navigation"
		},
		{
... (5 lines truncated)
</file>

<file path="packages/js/date/changelog/.gitkeep">

</file>

<file path="packages/js/date/changelog/fix-53303-day-range-in-localized-format">
Significance: patch
Type: fix

Build the same-month range label by substituting the day token in the date format, so month names that contain digits are no longer corrupted (#53303).
</file>

<file path="packages/js/date/changelog/fix-64020-moment-tz-clobber">
Significance: patch
Type: fix

Resolve the store timezone offset via date-fns-tz instead of moment-timezone's .tz() so Analytics no longer crashes with "tz is not a function" when a plugin replaces the global window.moment (#64020).
</file>

<file path="packages/js/date/changelog/fix-week-start-setting">
Significance: patch
Type: fix

Respect the WordPress "Week Starts On" setting in Analytics week date ranges and calendars.
</file>

<file path="packages/js/date/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/date/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/date/src/index.ts">
import moment from 'moment';
import { getTimezoneOffset } from 'date-fns-tz';
import { getSettings as getDateSettings } from '@wordpress/date';
import { find, memoize } from 'lodash';
import { __ } from '@wordpress/i18n';
import { parse } from 'qs';
⋮----
type Query = {
	[ key: string ]: string | undefined;
};
⋮----
export type DateValue = {
	primaryStart: moment.Moment;
	primaryEnd: moment.Moment;
	secondaryStart: moment.Moment;
	secondaryEnd: moment.Moment;
};
⋮----
export type DataPickerOptions = {
	label: string;
	range: string;
	after: moment.Moment;
	before: moment.Moment;
};
⋮----
export type DateParams = {
	period: string;
	compare: string;
	after: moment.Moment | null;
	before: moment.Moment | null;
... (126 lines truncated)
</file>

<file path="packages/js/date/typings/global.d.ts">
interface Window {
		wcSettings: {
			timeZone?: string;
			admin?: {
				timeZone?: string;
			};
		};
	}
</file>

<file path="packages/js/date/.npmrc">
package-lock=false
</file>

<file path="packages/js/date/babel.config.js">

</file>

<file path="packages/js/date/build.mjs">

</file>

<file path="packages/js/date/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [5.0.0](https://www.npmjs.com/package/@woocommerce/date/v/5.0.0) - 2026-06-10 

-   Major - Update @wordpress/* dependencies to WordPress 6.8 minimum. [#64114]
-   Major - Updated declared dependencies to React 18 and WordPress 6.6. [#53531]
-   Minor - Bump jest package dependency to 29.5.x. [#60324]
-   Minor - Fix typos in inline documentation. [#48640]
-   Minor - Fix typos in README.md files. [#48569]
-   Minor - Monorepo: bump pnpm version to 9.15.0. [#54189]
-   Minor - Upgraded TypeScript in the monorepo to 5.7.2. [#53165]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - CI: leverage composer packages cache in lint monorepo job. [#52054]
-   Patch - Clean up CI job config options; remove unused cascading keys. [#55863]
-   Patch - Comment: Fix comment typos across various files. [#50047]
-   Patch - Comment: Fix typos in documentation. [#50282]
-   Patch - Fix getStoreTimeZoneMoment() to check wcSettings.admin.timeZone when wcSettings.timeZone is not set. [#62872]
-   Patch - Fix pnpm version to 9.1.3 to avoid dependency installation issues. [#50828]
-   Patch - Monorepo: build RAM usage optimization. [#58861]
-   Patch - Monorepo: consolidate @babel/* dependencies versions across the monorepo. [#56575]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Monorepo: consolidate syncpack config around React 17/18 usage. [#52022]
-   Patch - Monorepo: consolidate TypeScript config files and JS test directories naming. [#52191]
-   Patch - Monorepo: drop the unused `concurrently` package from dependencies. [#58765]
-   Patch - Monorepo: refresh wireit dependencyOutputs configuration synchronization when installing dependencies. [#55095]
-   Patch - Move the CommonJS build to prepack so day-to-day development only builds the ESM output. [#64876]
-   Patch - Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking. [#65168]
-   Patch - Replaced patched `@wordpress/data` types with opt-in internal package types. [#63483]
... (38 lines truncated)
</file>

<file path="packages/js/date/composer.json">
{
	"name": "woocommerce/date",
	"description": "WooCommerce date utilities.",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/date/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/date/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/date/package.json">
{
	"name": "@woocommerce/date",
	"version": "5.0.0",
	"description": "WooCommerce date utilities.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"keywords": [
		"wordpress",
		"woocommerce",
		"date"
	],
	"engines": {
		"node": "^24.15.0"
	},
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/date/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
... (103 lines truncated)
</file>

<file path="packages/js/date/PREVIOUS_CHANGELOG.md">
# 4.0.1

-   Update all js packages with minor/patch version changes. #8392

# 4.0.0

## Breaking changes

-   Update dependencies to support react 17. #8305
-   Drop support for IE11. #8305

# 3.2.0

-   Remove dev dependency `@woocommerce/wc-admin-settings`. #8057
-   Add "defaultDateRange" argument to "getAllowedIntervalsForQuery" for default period value. #8189
-   Add type option to `getDateFormatsForInterval` to support `getDateFormatsForIntervalPhp` feature. #8129
-   Sentence case all the things analytics #6501
-   Fix end date for last periods #6584

# 3.1.0

-   Fix commonjs module build, allow package to be built in isolation. #7286

# 3.0.0

-   Take into account leap year in calculating `getLastPeriod`.

## Breaking changes

-   Move Lodash to a peer dependency.
... (47 lines truncated)
</file>

<file path="packages/js/date/README.md">
# Date

A collection of utilities to display and work with date values.

## Installation

Install the module

```bash
pnpm install @woocommerce/date --save
```

_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for ES2015+ such as lower versions of IE then using [core-js](https://github.com/zloirock/core-js) or [@babel/polyfill](https://babeljs.io/docs/en/next/babel-polyfill) will add support for these methods. Learn more about it in [Babel docs](https://babeljs.io/docs/en/next/caveats)._

## Usage

The `date` package makes use of the global `window.wcSettings.timeZone`.  If a timezone is set, the current and last periods will be converted from your browser's timezone to the store timezone.  If none is set, these periods will be based on your browser's timezone.

### Functions

<dl>
<dt><a href="#appendTimestamp">appendTimestamp</a> ⇒ <code>string</code></dt>
<dd><p>Adds timestamp to a string date.</p>
</dd>
<dt><a href="#getDateValue">getDateValue</a> ⇒ <code><a href="#DateValue">DateValue</a></code></dt>
<dd><p>Get a DateValue object for a period described by a period, compare value, and start/end
dates, for custom dates.</p>
</dd>
<dt><a href="#getDateParamsFromQueryMemoized">getDateParamsFromQueryMemoized</a> ⇒ <code>Object</code></dt>
<dd><p>Memoized internal logic of getDateParamsFromQuery().</p>
... (420 lines truncated)
</file>

<file path="packages/js/date/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": []
}
</file>

<file path="packages/js/dependency-extraction-webpack-plugin/changelog/.gitkeep">

</file>

<file path="packages/js/dependency-extraction-webpack-plugin/changelog/remove-experimental-products-app">
Significance: patch
Type: dev
Comment: Remove the deleted experimental products app from the dependency extraction package list.
</file>

<file path="packages/js/dependency-extraction-webpack-plugin/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/dependency-extraction-webpack-plugin/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/dependency-extraction-webpack-plugin/changelog/wooplug-929-settings-alias-docs">
Significance: patch
Type: dev
Comment: Document that @woocommerce/settings is an alias for wc.wcSettings, not the deprecated npm package, and how to mock it in Jest.
</file>

<file path="packages/js/dependency-extraction-webpack-plugin/src/index.js">
function camelCaseDash( string )
⋮----
const wooRequestToExternal = ( request, excludedExternals ) =>
⋮----
const wooRequestToHandle = ( request ) =>
⋮----
class DependencyExtractionWebpackPlugin extends WPDependencyExtractionWebpackPlugin
⋮----
requestToExternal: ( request ) =>
requestToHandle: ( request ) =>
⋮----
apply( compiler )
</file>

<file path="packages/js/dependency-extraction-webpack-plugin/.npmrc">
package-lock=false
</file>

<file path="packages/js/dependency-extraction-webpack-plugin/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [5.1.0](https://www.npmjs.com/package/@woocommerce/dependency-extraction-webpack-plugin/v/5.1.0) - 2026-06-30 

-   Minor - Replace the @woocommerce/settings-ui-sdk dependency-extraction entry with @woocommerce/settings-ui, matching the renamed package. The previous entry was never consumable: the package is unpublished and no WooCommerce release registers its script handle. [#65719]

## [5.0.0](https://www.npmjs.com/package/@woocommerce/dependency-extraction-webpack-plugin/v/5.0.0) - 2026-06-10 

-   Major [ **BREAKING CHANGE** ] - Remove the block templates package from dependency extraction. [#65503]
-   Major [ **BREAKING CHANGE** ] - Remove the product editor package from dependency extraction. [#65500]
-   Major [ **BREAKING CHANGE** ] - Remove the settings editor package from dependency extraction. [#65316]
-   Minor - Include @woocommerce/sanitize package in dependency extraction. [#60324]
-   Patch - Monorepo: refresh DependencyExtractionWebpackPlugin for compatibility with filesystem cache, admin build cleanup. [#64111]
-   Patch - Register the settings UI SDK package with dependency extraction. [#64387]
-   Patch - Removed stray wireit devDependency. [#65210]

## [4.0.0](https://www.npmjs.com/package/@woocommerce/dependency-extraction-webpack-plugin/v/4.0.0) - 2025-06-24 

-   Major [ **BREAKING CHANGE** ] - Monorepo: bump @wordpress/dependency-extraction-webpack-plugin dependency version to the latest (breaking changes, see [upstream CHANGELOG](https://github.com/WordPress/gutenberg/blob/trunk/packages/dependency-extraction-webpack-plugin/CHANGELOG.md) for details). [#59106]
-   Patch - Monorepo: consolidate @babel/* dependencies versions across the monorepo. [#56575]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Monorepo: consolidate Webpack dependencies versions across the monorepo. [#59104]

## [3.1.0](https://www.npmjs.com/package/@woocommerce/dependency-extraction-webpack-plugin/v/3.1.0) - 2025-01-06 

-   Minor - Add JS remote logging package [#49702]
-   Minor - Add Settings package, feature flag, and initial page. [#52391]
-   Minor - Upgraded Typescript in the monorepo to 5.7.2 [#53165]
... (45 lines truncated)
</file>

<file path="packages/js/dependency-extraction-webpack-plugin/composer.json">
{
	"name": "woocommerce/dependency-extraction-webpack-plugin",
	"description": "WooCommerce Dependency Extraction Webpack Plugin",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/dependency-extraction-webpack-plugin/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/dependency-extraction-webpack-plugin/package.json">
{
	"name": "@woocommerce/dependency-extraction-webpack-plugin",
	"version": "5.1.0",
	"description": "WooCommerce Dependency Extraction Webpack Plugin",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"keywords": [
		"wordpress",
		"woocommerce"
	],
	"engines": {
		"node": "^24.15.0"
	},
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/dependency-extraction-webpack-plugin/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"main": "src/index.js",
	"files": [
		"src/",
		"assets/"
	],
	"dependencies": {
		"@wordpress/dependency-extraction-webpack-plugin": "next"
	},
	"publishConfig": {
... (38 lines truncated)
</file>

<file path="packages/js/dependency-extraction-webpack-plugin/PREVIOUS_CHANGELOG.md">
# 2.0.0

-   Update all js packages with minor/patch version changes. #8392

## Breaking changes

    -   Updated to webpack 5 compatible #8476
    -   Will need to change webpack config output.libraryTarget from 'this' to 'window' #8476

# 1.6.0

-   Add new `bundledPackages` option to bundle in specific packages.

# 1.5.0

-   Add `@woocommerce/explat` to list of packages.
-   Add `@woocommerce/experimental` to list of packages.

# 1.4.0

-   Add `@woocommerce/settings` to list of packages.

# 1.3.0

-   Remove `@woocommerce/block-settings` from internal maps and use `@woocommerce/settings` instead. This external exposes the `getSetting` API interface which encourages read only use of the global.
-   Remove explicitly scoping externals to `this`. The plugin compiler will take care of scoping the external to the correct context and `this` is not correct in some contexts consuming this package.

# 1.2.0

-   Add WooCommerce Blocks Dependencies. #6228
... (13 lines truncated)
</file>

<file path="packages/js/dependency-extraction-webpack-plugin/README.md">
# Dependency Extraction Webpack Plugin

Extends WordPress [Dependency Extraction Webpack Plugin](https://github.com/WordPress/gutenberg/tree/trunk/packages/dependency-extraction-webpack-plugin) to automatically include WooCommerce dependencies in addition to WordPress dependencies.

## Installation

Install the module

```bash
pnpm install @woocommerce/dependency-extraction-webpack-plugin --save-dev
```

## Usage

Use this as you would [Dependency Extraction Webpack Plugin](https://github.com/WordPress/gutenberg/tree/trunk/packages/dependency-extraction-webpack-plugin). The API is exactly the same, except that WooCommerce packages are also handled automatically.

```js
// webpack.config.js
const WooCommerceDependencyExtractionWebpackPlugin = require( '@woocommerce/dependency-extraction-webpack-plugin' );

module.exports = {
 // …snip
 plugins: [ new WooCommerceDependencyExtractionWebpackPlugin() ],
};
```

**Note:** If you plan to extend the webpack configuration from `@wordpress/scripts` with `WooCommerceDependencyExtractionWebpackPlugin`, be sure to remove the default instance of the plugin:

```js
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
... (93 lines truncated)
</file>

<file path="packages/js/e2e-utils-playwright/changelog/.gitkeep">

</file>

<file path="packages/js/e2e-utils-playwright/changelog/woo6-108-resolve-high-npm-alerts">
Significance: patch
Type: dev

Update npm dependencies that resolve high-severity security advisories.
</file>

<file path="packages/js/e2e-utils-playwright/src/api-client.ts">
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import OAuth from 'oauth-1.0a';
import { createHmac } from 'crypto';
⋮----
import type { Auth, ApiClient } from './types';
⋮----
interface OAuthRequestOptions {
	params?: Record< string, unknown >;
	data?: Record< string, unknown >;
	debug?: boolean;
}
⋮----
export function createClient( baseURL: string, auth: Auth ): ApiClient
⋮----
function redact(
		obj: Record< string, unknown > | null | undefined,
		keys: string[] = [
			'password',
			'token',
			'authorization',
			'cookie',
			'secret',
		]
): Record< string, unknown > | null | undefined
⋮----
function logRequest( label: string, details: Record< string, unknown > )
⋮----
function oauthRequest(
		method: string,
		path: string,
... (27 lines truncated)
</file>

<file path="packages/js/e2e-utils-playwright/src/cart.ts">
import type { Page } from '@playwright/test';
⋮----
export const addAProductToCart = async (
	page: Page,
	productId: string,
	quantity = 1
): Promise< void > =>
⋮----
export async function addOneOrMoreProductToCart(
	page: Page,
	productName: string,
	quantityCount = 1
): Promise< void >
</file>

<file path="packages/js/e2e-utils-playwright/src/checkout.ts">
import type { Page, Locator } from '@playwright/test';
⋮----
import type { CheckoutDetails, AddressType } from './types';
⋮----
async function setDynamicFieldType( field: Locator, value: string )
⋮----
async function ensureAddressFieldsEditable( page: Page, type: AddressType )
⋮----
async function fillCheckoutBlocks(
	page: Page,
	details: CheckoutDetails = {},
	type: AddressType = 'shipping'
)
⋮----
export async function fillShippingCheckoutBlocks(
	page: Page,
	shippingDetails: CheckoutDetails = {}
): Promise< void >
⋮----
export async function fillBillingCheckoutBlocks(
	page: Page,
	billingDetails: CheckoutDetails = {}
): Promise< void >
</file>

<file path="packages/js/e2e-utils-playwright/src/editor.ts">
import type { Page } from '@playwright/test';
⋮----
import type { PageContext, EditorCanvas } from './types';
⋮----
interface WpData {
	select: ( store: string ) => {
		isFeatureActive: ( feature: string ) => boolean;
	};
	dispatch: ( store: string ) => {
		toggleFeature: ( feature: string ) => void;
	};
}
⋮----
type WindowWithWp = Window & { wp?: { data?: WpData } };
⋮----
export const closeChoosePatternModal = async ( {
	page,
}: PageContext ): Promise< void > =>
⋮----
export const disableWelcomeModal = async ( {
	page,
}: PageContext ): Promise< void > =>
⋮----
export const openEditorSettings = async ( {
	page,
}: PageContext ): Promise< void > =>
⋮----
export const getCanvas = async ( page: Page ): Promise< EditorCanvas > =>
⋮----
export const goToPageEditor = async ( {
... (32 lines truncated)
</file>

<file path="packages/js/e2e-utils-playwright/src/index.ts">

</file>

<file path="packages/js/e2e-utils-playwright/src/order.ts">
import type { Page } from '@playwright/test';
⋮----
export function getOrderIdFromUrl( page: Page ): string | undefined
</file>

<file path="packages/js/e2e-utils-playwright/src/types.ts">
import type { Page, FrameLocator } from '@playwright/test';
import type { AxiosResponse } from 'axios';
⋮----
export interface BasicAuth {
	type: 'basic';
	username: string;
	password: string;
}
⋮----
export interface OAuth1Auth {
	type: 'oauth1';
	consumerKey: string;
	consumerSecret: string;
}
⋮----
export type Auth = BasicAuth | OAuth1Auth;
⋮----
export interface ApiClient {
	get< T = unknown >(
		path: string,
		params?: Record< string, unknown >,
		debug?: boolean
	): Promise< AxiosResponse< T > >;
	post< T = unknown >(
		path: string,
		data?: Record< string, unknown >,
		debug?: boolean
	): Promise< AxiosResponse< T > >;
	put< T = unknown >(
		path: string,
... (63 lines truncated)
</file>

<file path="packages/js/e2e-utils-playwright/build.mjs">

</file>

<file path="packages/js/e2e-utils-playwright/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.5.1](https://www.npmjs.com/package/@woocommerce/e2e-utils-playwright/v/0.5.1) - 2026-08-14 

-   Patch - Harden `getCanvas` so the non-iframed editor path also waits for the canvas, hidden leftover iframes are ignored, and a missing canvas fails loudly instead of silently resolving to the wrong document. [#65326]

## [0.5.0](https://www.npmjs.com/package/@woocommerce/e2e-utils-playwright/v/0.5.0) - 2026-06-11 

-   Minor - Enable the Interactivity API-powered Mini Cart by default. [#60823]
-   Minor - Bump jest package dependency to 29.5.x. [#60324]
-   Minor - Converted the package source code to TypeScript. [#63102]
-   Patch - Make checkout address field helpers open collapsed address forms before filling fields. [#65548]
-   Patch - Move the CommonJS build to prepack so day-to-day development only builds the ESM output. [#64876]
-   Patch - Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking. [#65168]
-   Patch - Replaced wireit + tsc package build pipeline with a per-package esbuild script. [#65210]
-   Patch - Wait for the Gutenberg editor canvas iframe before falling back to the page context in Playwright tests. [#65532]

## [0.4.0](https://www.npmjs.com/package/@woocommerce/e2e-utils-playwright/v/0.4.0) - 2025-07-08 

-   Minor - Added api-client module [#59409]
-   Patch - Monorepo: build RAM usage optimization. [#58861]
-   Patch - Monorepo: consolidate @babel/* dependencies versions across the monorepo. [#56575]
-   Patch - Monorepo: consolidate @wordpress/babel-preset-default, @wordpress/browserslist-config, glob packages versions. [#56392]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]

## [0.3.1](https://www.npmjs.com/package/@woocommerce/e2e-utils-playwright/v/0.3.1) - 2025-03-06 

-   Patch - Updated the editor canvas frame locator to support changes in Gutenberg 20.6 [#56083]
... (25 lines truncated)
</file>

<file path="packages/js/e2e-utils-playwright/composer.json">
{
	"name": "woocommerce/e2e-utils-playwright",
	"description": "End-To-End (E2E) test Playwright utils for WooCommerce",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "^3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/e2e-utils-playwright/eslint.config.mjs">
/**
 * Internal dependencies
 */
⋮----
/*
 * The eslintrc this replaces set no `extends` and no `root`, so it inherited the
 * repo root config by cascade. Flat config does not cascade, so spread the
 * shared config explicitly.
 */
</file>

<file path="packages/js/e2e-utils-playwright/jest.config.json">
{
	"rootDir": "./",
	"roots": [ "<rootDir>/src" ],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/e2e-utils-playwright/package.json">
{
	"name": "@woocommerce/e2e-utils-playwright",
	"version": "0.5.1",
	"description": "End-To-End (E2E) test Playwright utils for WooCommerce",
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/e2e-utils-playwright/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
	"main": "build/index.js",
	"module": "build-module/index.js",
	"types": "build-types/index.d.ts",
	"files": [
		"build",
		"build-module",
		"build-types"
	],
	"scripts": {
... (72 lines truncated)
</file>

<file path="packages/js/e2e-utils-playwright/README.md">
# End-to-End Test Utilities For WooCommerce

This package contains utilities to help writing e2e tests specific to WooCommerce using Playwright.

> [!WARNING]
>
> This package is still under active development.
> Documentation might not be up-to-date, and the 0.x version can introduce breaking changes.

## Installation

```bash
npm install @woocommerce/e2e-utils-playwright --save-dev
```

## Usage

Example:

```js
import { addAProductToCart } from '@woocommerce/e2e-utils-playwright';

test('can add products to cart', async ({ page }) => {
  const product = {
    id: 1,
    name: 'Test Product',
  };

  await addAProductToCart(page, product.id);
  await page.goto('/cart/');
... (48 lines truncated)
</file>

<file path="packages/js/e2e-utils-playwright/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": []
}
</file>

<file path="packages/js/email-editor/changelog/.gitkeep">

</file>

<file path="packages/js/email-editor/changelog/testops-288-email-editor-loads">
Significance: patch
Type: dev
Comment: Move the email editor feature flag, preview send and REST failure coverage below E2E; the browser spec goes from six titles to five.
</file>

<file path="packages/js/email-editor/changelog/update-wooplug-7698-rich-text-comment-styles">
Significance: patch
Type: update

Remove the duplicated personalization tag chip styles from the sidebar stylesheet.
</file>

<file path="packages/js/email-editor/changelog/wooplug-7713-template-selector-layout-breaks-with-gutenberg-239">
Significance: minor
Type: fix

Fix the template selector layout with Gutenberg 23.9+ by giving it its own styles and using Tabs from @wordpress/ui for the category list
</file>

<file path="packages/js/email-editor/src/blocks/core/block-edit.tsx">
import { useCallback } from '@wordpress/element';
import type { BlockEditProps } from '@wordpress/blocks';
⋮----
import { addFilterForEmail } from '../../config-tools/filters';
⋮----
interface UrlAttributes {
	url?: string;
	[ key: string ]: unknown;
}
⋮----
const setUrlAttribute =
( BlockEdit: React.ElementType )
⋮----
function filterSetUrlAttribute(): void
</file>

<file path="packages/js/email-editor/src/blocks/core/buttons.ts">
import { updateBlockSettings } from '../../config-tools/block-config';
⋮----
function enhanceButtonsBlock()
</file>

<file path="packages/js/email-editor/src/blocks/core/columns.tsx">
import { InspectorControls } from '@wordpress/block-editor';
import { createHigherOrderComponent } from '@wordpress/compose';
import { BlockSupports } from '@wordpress/blocks';
⋮----
import { updateBlockSettings } from '../../config-tools/block-config';
import { addFilterForEmail } from '../../config-tools/filters';
⋮----
function deactivateStackOnMobile()
⋮----
function disableColumnsLayoutAndEnhanceColumnsBlock()
</file>

<file path="packages/js/email-editor/src/blocks/core/embed.tsx">
import { Notice } from '@wordpress/components';
import { createHigherOrderComponent } from '@wordpress/compose';
import { useDispatch } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
import type { BlockConfiguration, BlockEditProps } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
⋮----
import { updateBlockSettings } from '../../config-tools/block-config';
import { addFilterForEmail } from '../../config-tools/filters';
⋮----
export function isSupportedProviderUrl( url: string ): boolean
⋮----
interface EmbedAttributes {
	url?: string;
	type?: string;
	responsive?: boolean;
	[ key: string ]: unknown;
}
⋮----
⋮----
function removeUnsupportedVariations()
⋮----
function addEmailEmbedAdjustments()
⋮----
function enhanceEmbedBlock()
</file>

<file path="packages/js/email-editor/src/blocks/core/full-width.tsx">
import clsx from 'clsx';
import { createHigherOrderComponent } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import { store as blockEditorStore } from '@wordpress/block-editor';
⋮----
import { addFilterForEmail } from '../../config-tools/filters';
import { unwrapCompressedPresetStyleVariable } from '../../style-variables';
⋮----
type SpacingPadding =
	| string
	| { top?: string; right?: string; bottom?: string; left?: string };
⋮----
function isZeroValue( value?: string ): boolean
⋮----
function getHorizontalPadding( padding?: SpacingPadding ):
⋮----
const toCss = ( value?: string ): string | null =>
⋮----
type BreakoutInfo = {
	left: string | null;
	right: string | null;
};
⋮----
function useBreakoutPadding(
	clientId: string,
	enabled: boolean
): BreakoutInfo | false
</file>

<file path="packages/js/email-editor/src/blocks/core/general-block-support.ts">
import {
	Block as WPBlock,
	BlockSupports as WPBlockSupports,
} from '@wordpress/blocks/index';
import domReady from '@wordpress/dom-ready';
import { getBlockTypes } from '@wordpress/blocks';
import { select } from '@wordpress/data';
⋮----
import { updateBlockSettings } from '../../config-tools/block-config';
import { unregisterBlockStyleForEmail } from '../../config-tools/block-style';
⋮----
type BlockSupports = WPBlockSupports & { shadow: boolean };
type Block = WPBlock & { supports?: BlockSupports };
⋮----
function alterSupportConfiguration(): void
⋮----
function removeBlockStyles()
⋮----
function removeBlockStylesFromAllBlocks()
</file>

<file path="packages/js/email-editor/src/blocks/core/group.tsx">
import { updateBlockSettings } from '../../config-tools/block-config';
⋮----
function disableGroupVariations()
</file>

<file path="packages/js/email-editor/src/blocks/core/image.tsx">
import { InspectorControls } from '@wordpress/block-editor';
import { createHigherOrderComponent } from '@wordpress/compose';
import { BlockSupports } from '@wordpress/blocks';
⋮----
import { updateBlockSettings } from '../../config-tools/block-config';
import { addFilterForEmail } from '../../config-tools/filters';
⋮----
function disableImageFilter()
⋮----
function hideExpandOnClick()
</file>

<file path="packages/js/email-editor/src/blocks/core/post-content.tsx">
import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
⋮----
import { updateBlockSettings } from '../../config-tools/block-config';
⋮----
function Placeholder(
⋮----
function PostContentEdit( OriginalEditComponent )
⋮----
function enhancePostContentBlock()
</file>

<file path="packages/js/email-editor/src/blocks/core/quote.ts">
import { updateBlockSettings } from '../../config-tools/block-config';
⋮----
function enhanceQuoteBlock()
</file>

<file path="packages/js/email-editor/src/blocks/core/rich-text.tsx">
import {
	applyFormat,
	insert,
	create,
	toHTMLString,
} from '@wordpress/rich-text';
import { __ } from '@wordpress/i18n';
import { BlockControls } from '@wordpress/block-editor';
import { ToolbarButton, ToolbarGroup } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { useCallback, useState } from '@wordpress/element';
import { createHigherOrderComponent } from '@wordpress/compose';
⋮----
import {
	getCursorPosition,
	replacePersonalizationTagsWithHTMLComments,
} from '../../components/personalization-tags/rich-text-utils';
import { PersonalizationTagsModal } from '../../components/personalization-tags/personalization-tags-modal';
import { storeName } from '../../store';
import { PersonalizationTagsPopover } from '../../components/personalization-tags/personalization-tags-popover';
import { PersonalizationTagsLinkPopover } from '../../components/personalization-tags/personalization-tags-link-popover';
import { recordEvent } from '../../events';
import {
	registerFormatForEmail,
	unregisterFormatForEmail,
} from '../../config-tools/formats';
import { addFilterForEmail } from '../../config-tools/filters';
⋮----
function disableCertainRichTextFormats()
⋮----
... (27 lines truncated)
</file>

<file path="packages/js/email-editor/src/blocks/core/site-logo.ts">
import { registerBlockVariationForEmail } from '../../config-tools';
⋮----
function registerCustomSiteLogoBlockVariation()
⋮----
function enhanceSiteLogoBlock()
</file>

<file path="packages/js/email-editor/src/blocks/core/social-links.tsx">
import { InspectorControls } from '@wordpress/block-editor';
import type {
	Block,
	BlockConfiguration,
	InnerBlockTemplate,
} from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
⋮----
import { updateBlockSettings } from '../../config-tools/block-config';
import { registerBlockVariationForEmail } from '../../config-tools';
import { addFilterForEmail } from '../../config-tools/filters';
⋮----
function unregisterBlockVariations()
⋮----
function registerCustomSocialLinksBlockVariation()
⋮----
const disableIconColor =
( BlockEdit: React.ElementType ) => ( props: Block< unknown > ) =>
⋮----
function removeSocialLinksIconColor(): void
⋮----
function enhanceSocialLinksBlock()
</file>

<file path="packages/js/email-editor/src/blocks/woocommerce/product-image.ts">
import { updateBlockSettings } from '../../config-tools/block-config';
⋮----
function enableProductImageAlignment()
</file>

<file path="packages/js/email-editor/src/blocks/index.ts">
import { registerCoreBlocks } from '@wordpress/block-library';
import { getBlockType } from '@wordpress/blocks';
⋮----
import {
	disableColumnsLayoutAndEnhanceColumnsBlock,
	deactivateStackOnMobile,
} from './core/columns';
import { enhancePostContentBlock } from './core/post-content';
import { disableGroupVariations } from './core/group';
import { disableImageFilter, hideExpandOnClick } from './core/image';
import {
	disableCertainRichTextFormats,
	extendRichTextFormats,
	activatePersonalizationTagsReplacing,
} from './core/rich-text';
import { enhanceButtonsBlock } from './core/buttons';
import { enhanceEmbedBlock } from './core/embed';
import {
	alterSupportConfiguration,
	removeBlockStylesFromAllBlocks,
} from './core/general-block-support';
import { enhanceQuoteBlock } from './core/quote';
import { filterSetUrlAttribute } from './core/block-edit';
import { enhanceSocialLinksBlock } from './core/social-links';
import { enhanceSiteLogoBlock } from './core/site-logo';
import { enableFullWidthBlocks } from './core/full-width';
import { enableProductImageAlignment } from './woocommerce/product-image';
⋮----
export function initBlocks()
</file>

<file path="packages/js/email-editor/src/blocks/utils.ts">
import { getBlockTypes, Block } from '@wordpress/blocks';
⋮----
export function getAllowedBlockNames(): string[]
</file>

<file path="packages/js/email-editor/src/components/block-editor/editor.tsx">
import { useSelect, useDispatch } from '@wordpress/data';
import { useMemo, useEffect } from '@wordpress/element';
import { SlotFillProvider, ProgressBar } from '@wordpress/components';
import { store as coreStore, Post } from '@wordpress/core-data';
import { CommandMenu, store as commandsStore } from '@wordpress/commands';
import { PluginArea } from '@wordpress/plugins';
import {
	AutosaveMonitor as _AutosaveMonitor,
	LocalAutosaveMonitor,
	UnsavedChangesWarning,
	EditorKeyboardShortcutsRegister as _EditorKeyboardShortcutsRegister,
	ErrorBoundary,
	PostLockedModal,
	store as editorStore,
} from '@wordpress/editor';
⋮----
import { storeName } from '../../store';
import { useNavigateToEntityRecord } from '../../hooks/use-navigate-to-entity-record';
import { Editor, FullscreenMode } from '../../private-apis';
import { useEmailCss } from '../../hooks';
import { PreviewSaveGuard } from '../preview/preview-save-guard';
import { TemplateSelection } from '../template-select';
import { StylesSidebar } from '../styles-sidebar';
import { SendPreview } from '../preview';
import { MoreMenu } from '../more-menu';
import { SettingsPanel } from '../sidebar/settings-panel';
import { TemplateSettingsPanel } from '../sidebar/template-settings-panel';
import { PublishSave } from '../../hacks/publish-save';
import { EditorNotices } from '../notices';
import { BlockCompatibilityWarnings } from '../sidebar';
... (4 lines truncated)
</file>

<file path="packages/js/email-editor/src/components/block-editor/index.ts">

</file>

<file path="packages/js/email-editor/src/components/header/back-button-content.tsx">
import { Button, __unstableMotion as motion } from '@wordpress/components';
import { useLayoutEffect, useRef, useState } from '@wordpress/element';
import { __, isRTL } from '@wordpress/i18n';
import {
	Icon,
	arrowLeft,
	chevronLeft,
	chevronRight,
	wordpress,
} from '@wordpress/icons';
import { applyFilters } from '@wordpress/hooks';
import { useSelect } from '@wordpress/data';
⋮----
import { BackButton } from '../../private-apis';
import { recordEvent } from '../../events';
import { storeName } from '../../store';
⋮----
function useCloseAction()
⋮----
const defaultAction = () =>
⋮----
const CompactBackButtonContent = () =>
⋮----
label=
⋮----
const FullscreenBackButtonContent = () =>
⋮----
const DefaultBackButtonContent = () =>
⋮----
export const BackButtonContent = () =>
... (1 lines truncated)
</file>

<file path="packages/js/email-editor/src/components/header/send-button.tsx">
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { applyFilters } from '@wordpress/hooks';
import { useSelect } from '@wordpress/data';
import { useEntitiesSavedStatesIsDirty } from '@wordpress/editor';
⋮----
import { storeName } from '../../store';
import { recordEvent } from '../../events';
⋮----
export function SendButton()
⋮----
function sendAction()
</file>

<file path="packages/js/email-editor/src/components/header/trash-email-post.tsx">
import { store as coreStore } from '@wordpress/core-data';
import { __, _n, sprintf } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';
import { trash } from '@wordpress/icons';
import { useState } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import {
	Button,
	__experimentalText as Text,
	__experimentalHStack as HStack,
	__experimentalVStack as VStack,
} from '@wordpress/components';
import { decodeEntities } from '@wordpress/html-entities';
import { applyFilters } from '@wordpress/hooks';
⋮----
import { storeName, CoreDataError, PostWithPermissions } from '../../store';
import { recordEvent } from '../../events';
⋮----
function getItemTitle( item: {
	title: string | { rendered: string } | { raw: string };
} )
⋮----
function getModalTitle(
	items: PostWithPermissions[],
	shouldPermanentlyDelete: boolean
)
⋮----
// translators: %d: number of items to delete.
⋮----
// translators: %s: The post's title
... (7 lines truncated)
</file>

<file path="packages/js/email-editor/src/components/more-menu/index.ts">

</file>

<file path="packages/js/email-editor/src/components/more-menu/more-menu.tsx">
import { __ } from '@wordpress/i18n';
import { useViewportMatch } from '@wordpress/compose';
import { displayShortcut } from '@wordpress/keycodes';
import { PreferenceToggleMenuItem } from '@wordpress/preferences';
⋮----
import { ViewMoreMenuGroup } from '../../private-apis';
import { storeName } from '../../store';
⋮----
export const MoreMenu = () =>
⋮----
label=
messageActivated=
</file>

<file path="packages/js/email-editor/src/components/notices/index.ts">

</file>

<file path="packages/js/email-editor/src/components/notices/notices.tsx">
import type { ComponentProps } from 'react';
import { NoticeList } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { store as noticesStore } from '@wordpress/notices';
⋮----
import { ValidationNotices } from './validation-notices';
import { EditorSnackbars } from './snackbars';
import { NoticesSlot } from '../../hacks/notices-slot';
⋮----
type NoticeListNotices = ComponentProps< typeof NoticeList >[ 'notices' ];
⋮----
interface EditorNoticesProps {
	disableSnackbarNotices?: boolean;
}
⋮----
export function EditorNotices( {
	disableSnackbarNotices = false,
}: EditorNoticesProps =
</file>

<file path="packages/js/email-editor/src/components/notices/sent-email-notice.tsx">
import { dispatch, useSelect } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
import { store as noticesStore } from '@wordpress/notices';
import { __ } from '@wordpress/i18n';
⋮----
import { storeName } from '../../store';
import { recordEvent } from '../../events';
⋮----
export function SentEmailNotice()
</file>

<file path="packages/js/email-editor/src/components/notices/snackbars.tsx">
import type { ComponentProps } from 'react';
import { SnackbarList } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { store as noticesStore } from '@wordpress/notices';
⋮----
type SnackbarListNotices = ComponentProps< typeof SnackbarList >[ 'notices' ];
⋮----
export function EditorSnackbars()
</file>

<file path="packages/js/email-editor/src/components/notices/validation-notices.tsx">
import { __ } from '@wordpress/i18n';
import { Notice, Button } from '@wordpress/components';
⋮----
import { useValidationNotices } from '../../hooks';
⋮----
export function ValidationNotices()
</file>

<file path="packages/js/email-editor/src/components/personalization-tags/category-menu.tsx">
import { MenuGroup, MenuItem } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
const getMenuItemClass = ( category: string | null )
⋮----
onClick=
</file>

<file path="packages/js/email-editor/src/components/personalization-tags/category-section.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useDispatch, useSelect } from '@wordpress/data';
import { store as blockEditorStore } from '@wordpress/block-editor';
⋮----
import { PersonalizationTag } from '../../store';
⋮----
closeCallback();
openLinkModal(
																	item
																);
</file>

<file path="packages/js/email-editor/src/components/personalization-tags/link-modal.tsx">
import { Button, Modal, TextControl } from '@wordpress/components';
import { __, TranslatableText } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
⋮----
const LinkModal = (
⋮----
onInsert( tag.token, linkText );
</file>

<file path="packages/js/email-editor/src/components/personalization-tags/personalization-tags-link-popover.tsx">
import { useEffect, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import {
	Popover,
	Button,
	TextControl,
	SelectControl,
} from '@wordpress/components';
⋮----
import { storeName } from '../../store';
⋮----
type PersonalizationTagsLinkPopoverProps = {
	contentRef: React.RefObject< HTMLElement >;
	onUpdate: (
		htmlElement: HTMLElement,
		newTag: string,
		newText: string
	) => void;
};
⋮----
// Handle clicks within the referenced container
const handleContainerClick = ( event: Event ) =>
⋮----
// Remove brackets from the text content for better user experience
⋮----
// Add the event listener to the container
⋮----
label=
⋮----
... (4 lines truncated)
</file>

<file path="packages/js/email-editor/src/components/personalization-tags/personalization-tags-modal.tsx">
import { ExternalLink, Modal, SearchControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
⋮----
import { CategoryMenu } from './category-menu';
import { CategorySection } from './category-section';
import { LinkModal } from './link-modal';
import { recordEvent, recordEventOnce } from '../../events';
import { PersonalizationTag, storeName } from '../../store';
⋮----
onInsert( tag, linkText );
setIsLinkModalOpened( false );
⋮----
closeCallback();
recordEvent( 'personalization_tags_modal_closed', {
					openedBy,
				} );
⋮----
href="https://kb.mailpoet.com/article/435-a-guide-to-personalisation-tags-for-tailored-newsletters#list"
⋮----
setSearchQuery( theSearchQuery );
recordEventOnce(
						'personalization_tags_modal_search_control_input_updated',
						{ openedBy }
					);
</file>

<file path="packages/js/email-editor/src/components/personalization-tags/personalization-tags-popover.tsx">
import { useEffect, useState } from '@wordpress/element';
import { Popover, Button, TextControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
type PersonalizationTagsPopoverProps = {
	contentRef: React.RefObject< HTMLElement >;
	onUpdate: ( originalValue: string, updatedValue: string ) => void;
};
⋮----
// Handle clicks within the referenced container
const handleContainerClick = ( event: Event ) =>
⋮----
// Remove brackets from the text content for better user experience
⋮----
// Add the event listener to the container
⋮----
label=
⋮----
setIsPopoverVisible( false );
</file>

<file path="packages/js/email-editor/src/components/personalization-tags/rich-text-utils.ts">
import { create } from '@wordpress/rich-text';
import { RichTextFormatList } from '@wordpress/rich-text/build-types/types';
⋮----
import { PersonalizationTag } from '../../store';
⋮----
type Replacement = {
	attributes: Record< string, string >;
	type: string;
};
⋮----
function getChildElement( rootElement: HTMLElement ): HTMLElement | null
⋮----
function findReplacementIndex(
	element: HTMLElement,
	replacements: ( null | Replacement )[]
): number | null
⋮----
function findLatestFormatIndex(
	element: HTMLElement,
	formats: RichTextFormatList[]
): number | null
⋮----
const getCursorPosition = (
	richTextRef: React.RefObject< HTMLElement >,
	content: string
):
⋮----
const replacePersonalizationTagsWithHTMLComments = (
	content: string,
	tags: PersonalizationTag[]
... (2 lines truncated)
</file>

<file path="packages/js/email-editor/src/components/personalization-tags/rich-text-with-button.tsx">
import type { ReactNode } from 'react';
import { BaseControl, Button } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useCallback, useRef, useState } from '@wordpress/element';
import { create, insert, toHTMLString } from '@wordpress/rich-text';
import { RichText } from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';
⋮----
import { PersonalizationTagsModal } from './personalization-tags-modal';
import {
	getCursorPosition,
	replacePersonalizationTagsWithHTMLComments,
} from './rich-text-utils';
import { storeName } from '../../store';
import { PersonalizationTagsPopover } from './personalization-tags-popover';
import { recordEvent, recordEventOnce } from '../../events';
⋮----
type Props = {
	label: string;
	labelSuffix?: ReactNode;
	help?: ReactNode;
	placeholder: string;
	attributeName: string;
	attributeValue?: string;
	updateProperty: (
		theAttributeName: string,
		theUpdatedValue: string
	) => void;
};
⋮----
... (35 lines truncated)
</file>

<file path="packages/js/email-editor/src/components/preview/index.ts">

</file>

<file path="packages/js/email-editor/src/components/preview/preview-save-guard.ts">
import { __ } from '@wordpress/i18n';
import { useCallback, useEffect } from '@wordpress/element';
import { select, dispatch } from '@wordpress/data';
import { store as editorStore } from '@wordpress/editor';
import { store as noticesStore } from '@wordpress/notices';
⋮----
export const PreviewSaveGuard = () =>
⋮----
const guard = async ( event ) =>
</file>

<file path="packages/js/email-editor/src/components/preview/send-preview-email.tsx">
import { Button, Modal, TextControl } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { check, Icon } from '@wordpress/icons';
import { __, sprintf } from '@wordpress/i18n';
import {
	useEffect,
	useRef,
	createInterpolateElement,
	memo,
	useMemo,
} from '@wordpress/element';
import { ENTER } from '@wordpress/keycodes';
import { isEmail } from '@wordpress/url';
import { applyFilters } from '@wordpress/hooks';
⋮----
import { SendingPreviewStatus, storeName } from '../../store';
import { recordEvent, recordEventOnce } from '../../events';
⋮----
const handleSendPreviewEmail = () =>
⋮----
const closeCallback = () =>
⋮----
title=
⋮----
href={ `https://account.mailpoet.com/?s=1&g=1&utm_source=woocommerce_email_editor&utm_medium=plugin&utm_source_platform=${ postType }` }
</file>

<file path="packages/js/email-editor/src/components/preview/send-preview.tsx">
import { useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { external } from '@wordpress/icons';
import { PluginPreviewMenuItem } from '@wordpress/editor';
⋮----
import { storeName } from '../../store/constants';
import { SendPreviewEmail } from './send-preview-email';
import { recordEvent } from '../../events';
⋮----
export function SendPreview()
⋮----
recordEvent(
						'header_preview_dropdown_send_test_email_selected'
					);
void togglePreviewModal( true );
</file>

<file path="packages/js/email-editor/src/components/sidebar/block-compatibility-warnings.tsx">
import { hasBlockSupport, getBlockSupport } from '@wordpress/blocks';
import { Fill, Notice } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
⋮----
export const hasBackgroundImageSupport = ( nameOrType: string ) =>
⋮----
</file>

<file path="packages/js/email-editor/src/components/sidebar/edit-template-modal.tsx">
import { __ } from '@wordpress/i18n';
import { Button, Flex, FlexItem, Modal } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { store as editorStore } from '@wordpress/editor';
⋮----
import { storeName } from '../../store';
import { recordEvent, recordEventOnce } from '../../events';
⋮----
export function EditTemplateModal(
⋮----
</file>

<file path="packages/js/email-editor/src/components/sidebar/index.ts">

</file>

<file path="packages/js/email-editor/src/components/sidebar/reset-email-template.tsx">
import { __, sprintf, TranslatableText } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';
import { store as coreStore, type WpTemplate } from '@wordpress/core-data';
import { backup } from '@wordpress/icons';
import { useState } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import {
	Button,
	__experimentalText as Text,
	__experimentalHStack as HStack,
	__experimentalVStack as VStack,
} from '@wordpress/components';
import { decodeEntities } from '@wordpress/html-entities';
import { parse, serialize } from '@wordpress/blocks';
import apiFetch from '@wordpress/api-fetch';
⋮----
import { type PostWithPermissions } from '../../store';
import { recordEvent } from '../../events';
⋮----
function getItemTitle( item: {
	title: string | { rendered: string } | { raw: string };
} )
⋮----
const getResetEmailTemplateAction = () =>
⋮----
/**
	 * Reset email template action.
	 * Resets a wp_template to its default state by deleting the customized version.
	 */
⋮----
... (6 lines truncated)
</file>

<file path="packages/js/email-editor/src/components/sidebar/settings-panel.tsx">
import { __ } from '@wordpress/i18n';
import { applyFilters } from '@wordpress/hooks';
import { useMemo } from '@wordpress/element';
import { createSlotFill } from '@wordpress/components';
import { ErrorBoundary, PluginDocumentSettingPanel } from '@wordpress/editor';
⋮----
import { RichTextWithButton } from '../personalization-tags/rich-text-with-button';
import {
	recordEvent,
	recordEventOnce,
	debouncedRecordEvent,
} from '../../events';
⋮----
export function SettingsPanel()
</file>

<file path="packages/js/email-editor/src/components/sidebar/template-selection.tsx">
import {
	PanelRow,
	Flex,
	FlexItem,
	DropdownMenu,
	MenuItem,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { useState } from '@wordpress/element';
⋮----
import { storeName } from '../../store';
import { EditTemplateModal } from './edit-template-modal';
import { SelectTemplateModal } from '../template-select';
import { recordEvent } from '../../events';
import { usePreviewTemplates } from '../../hooks';
⋮----
label={ __(
										'Template actions',
										__i18n_text_domain__
									) }
onToggle=
⋮----
recordEvent(
															'sidebar_template_actions_edit_template_clicked'
														);
setEditTemplateModalOpen(
															true
														);
onClose();
... (10 lines truncated)
</file>

<file path="packages/js/email-editor/src/components/sidebar/template-settings-panel.tsx">
import { __ } from '@wordpress/i18n';
import { applyFilters } from '@wordpress/hooks';
import { PluginDocumentSettingPanel, ErrorBoundary } from '@wordpress/editor';
⋮----
import {
	recordEvent,
	recordEventOnce,
	debouncedRecordEvent,
} from '../../events';
⋮----
interface TemplatePanelSection {
	id: string;
	render: () => JSX.Element | null;
}
⋮----
export function TemplateSettingsPanel()
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/panels/color-dropdown-item.tsx">
import clsx from 'clsx';
import { __ } from '@wordpress/i18n';
import { useRef } from '@wordpress/element';
import { reset as resetIcon } from '@wordpress/icons';
import {
	Button,
	ColorIndicator,
	Dropdown,
	FlexItem,
	__experimentalDropdownContentWrapper as DropdownContentWrapper,
	__experimentalHStack as HStack,
	__experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';
⋮----
import {
	__experimentalColorGradientControl as ColorGradientControl,
} from '@wordpress/block-editor';
⋮----
label=
⋮----
resetValue();
if ( isOpen )
onToggle();
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/panels/dimensions-panel.tsx">
import { __ } from '@wordpress/i18n';
import { isEqual } from 'lodash';
import {
	__experimentalSpacingSizesControl as SpacingSizesControl,
	useSettings,
} from '@wordpress/block-editor';
⋮----
import {
	__experimentalToolsPanel as ToolsPanel,
	__experimentalToolsPanelItem as ToolsPanelItem,
	__experimentalUseCustomUnits as useCustomUnits,
} from '@wordpress/components';
⋮----
import { useEmailStyles } from '../../../hooks';
import { recordEvent, debouncedRecordEvent } from '../../../events';
⋮----
export function DimensionsPanel()
⋮----
label=
⋮----
updateStyleProp( [ 'spacing' ], defaultStyles.spacing );
recordEvent(
					'styles_sidebar_screen_layout_dimensions_reset_all_selected'
				);
⋮----
label={ __( 'Padding', __i18n_text_domain__ ) }
onDeselect=
⋮----
updateStyleProp( [ 'spacing', 'padding' ], value );
debouncedRecordEvent(
... (10 lines truncated)
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/panels/typography-element-panel.tsx">
import { __ } from '@wordpress/i18n';
import { useCallback } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import {
	getValueFromVariable,
	getPresetVariableFromValue,
} from '@wordpress/global-styles-engine';
import {
	FontSizePicker,
	__experimentalToolsPanel as ToolsPanel,
	__experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';
⋮----
import {
	useSettings,
	__experimentalFontAppearanceControl as FontAppearanceControl,
	__experimentalLetterSpacingControl as LetterSpacingControl,
	__experimentalFontFamilyControl as FontFamilyControl,
	LineHeightControl,
	__experimentalTextDecorationControl as TextDecorationControl,
	__experimentalTextTransformControl as TextTransformControl,
	__experimentalUseMultipleOriginColorsAndGradients as useMultipleOriginColorsAndGradients,
} from '@wordpress/block-editor';
⋮----
import { useEmailStyles, setImmutably } from '../../../hooks';
import { storeName } from '../../../store';
import { getElementStyles } from '../utils';
import { useHasTextColorInTypographyPanel } from '../hooks';
import { ColorDropdownItem } from './color-dropdown-item';
import { recordEvent, debouncedRecordEvent } from '../../../events';
... (33 lines truncated)
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/panels/typography-panel.tsx">
import { __, sprintf } from '@wordpress/i18n';
import {
	__experimentalItemGroup as ItemGroup,
	__experimentalItem as Item,
	__experimentalVStack as VStack,
	__experimentalHStack as HStack,
	__experimentalHeading as Heading,
	__experimentalNavigatorButton as NavigatorButton,
	FlexItem,
	Card,
	CardBody,
} from '@wordpress/components';
⋮----
import { useEmailStyles } from '../../../hooks';
import { getElementStyles } from '../utils';
import { recordEvent } from '../../../events';
⋮----
function ElementItem(
⋮----
export function TypographyPanel()
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/previews/typography-preview.tsx">
import { useEmailStyles } from '../../../hooks';
import { getElementStyles } from '../utils';
⋮----
export default function TypographyPreview( {
	element,
	headingLevel,
}: {
	element: string;
	headingLevel: string;
} )
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/screens/index.ts">

</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/screens/preview.tsx">
import { useSelect } from '@wordpress/data';
import { useState, useMemo } from '@wordpress/element';
import {
	__experimentalHStack as HStack,
	__experimentalVStack as VStack,
	__unstableMotion as motion,
} from '@wordpress/components';
⋮----
import { storeName } from '../../../store';
import { useEmailStyles } from '../../../hooks';
import { getCompressedVariableValue } from '../../../style-variables';
⋮----
type Props = {
	label?: string;
	isFocused?: boolean;
	withHoverView?: boolean;
};
⋮----
onMouseEnter=
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/screens/screen-background.tsx">
import { __ } from '@wordpress/i18n';
⋮----
import ScreenHeader from './screen-header';
import { useEmailStyles } from '../../../hooks';
import { useBackgroundScreenSettings } from '../hooks';
import { recordEvent, recordEventOnce } from '../../../events';
import { StylesBackgroundPanel } from '../../../private-apis';
⋮----
export function ScreenBackground(): JSX.Element
⋮----
const handleOnChange = ( newStyles ) =>
⋮----
title=
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/screens/screen-colors.tsx">
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
⋮----
import ScreenHeader from './screen-header';
import { useEmailStyles } from '../../../hooks';
import { storeName } from '../../../store';
import { recordEvent, recordEventOnce } from '../../../events';
import { StylesColorPanel } from '../../../private-apis';
⋮----
export function ScreenColors(): JSX.Element
⋮----
const handleOnChange = ( newStyles ) =>
⋮----
title=
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/screens/screen-header.tsx">
import { __ } from '@wordpress/i18n';
import { chevronLeft } from '@wordpress/icons';
import {
	__experimentalHStack as HStack,
	__experimentalVStack as VStack,
	__experimentalSpacer as Spacer,
	__experimentalHeading as Heading,
	__experimentalView as View,
} from '@wordpress/components';
⋮----
import { Navigator } from '../navigator';
⋮----
type Props = {
	title: string;
	description?: string;
	onBack?: () => void;
};
⋮----
export function ScreenHeader(
⋮----
aria-label=
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/screens/screen-layout.tsx">
import { __ } from '@wordpress/i18n';
⋮----
import { DimensionsPanel } from '../panels/dimensions-panel';
import { ScreenHeader } from './screen-header';
import { recordEventOnce } from '../../../events';
⋮----
export function ScreenLayout(): JSX.Element
⋮----
<ScreenHeader title=
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/screens/screen-root.tsx">
import { __ } from '@wordpress/i18n';
import { typography, color, background, layout } from '@wordpress/icons';
import {
	__experimentalVStack as VStack,
	Card,
	CardBody,
	CardMedia,
	__experimentalItemGroup as ItemGroup,
	__experimentalItem as Item,
	__experimentalHStack as HStack,
	__experimentalNavigatorButton as NavigatorButton,
	Icon,
	FlexItem,
} from '@wordpress/components';
⋮----
import { Preview } from './preview';
import { useHasBackgroundScreen } from '../hooks';
import { recordEvent } from '../../../events';
⋮----
export function ScreenRoot(): JSX.Element
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/screens/screen-typography-element.tsx">
import { __, _x } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import {
	__experimentalToggleGroupControl as ToggleGroupControl,
	__experimentalToggleGroupControlOption as ToggleGroupControlOption,
	__experimentalSpacer as Spacer,
} from '@wordpress/components';
⋮----
import TypographyElementPanel, {
	DEFAULT_CONTROLS,
} from '../panels/typography-element-panel';
import TypographyPreview from '../previews/typography-preview';
import ScreenHeader from './screen-header';
import { recordEvent, recordEventOnce } from '../../../events';
⋮----
label=
⋮----
setHeadingLevel( value.toString() );
recordEvent(
								'styles_sidebar_screen_typography_element_heading_level_selected',
								{ value }
							);
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/screens/screen-typography.tsx">
import { __ } from '@wordpress/i18n';
⋮----
import TypographyPanel from '../panels/typography-panel';
import ScreenHeader from './screen-header';
import { recordEventOnce } from '../../../events';
⋮----
export function ScreenTypography(): JSX.Element
⋮----
title=
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/hooks.ts">
import { useMemo } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
⋮----
import { storeName } from '../../store';
import {
	useHasStylesColorPanel,
	useHasStylesBackgroundPanel,
} from '../../private-apis';
⋮----
export function useHasTextColorInTypographyPanel(): boolean
⋮----
export function useBackgroundScreenSettings()
⋮----
export function useHasBackgroundScreen(): boolean
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/index.ts">

</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/navigator.ts">
import {
	Navigator as WPNavigator,
	__experimentalNavigatorProvider as NavigatorProvider,
	__experimentalNavigatorScreen as NavigatorScreen,
	__experimentalNavigatorBackButton as NavigatorBackButton,
} from '@wordpress/components';
⋮----
type NavigatorWithCompound = typeof WPNavigator & {
	Screen: typeof NavigatorScreen;
	BackButton: typeof NavigatorBackButton;
};
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/styles-sidebar.tsx">
import { memo } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { styles } from '@wordpress/icons';
import { PluginSidebar, PluginSidebarMoreMenuItem } from '@wordpress/editor';
⋮----
import { storeName } from '../../store';
import {
	ScreenTypography,
	ScreenTypographyElement,
	ScreenLayout,
	ScreenRoot,
	ScreenColors,
	ScreenBackground,
} from './screens';
import { Navigator } from './navigator';
⋮----
export function RawStylesSidebar(): JSX.Element
⋮----
</file>

<file path="packages/js/email-editor/src/components/styles-sidebar/utils.ts">
import deepmerge from 'deepmerge';
⋮----
import { EmailStyles } from '../../store';
⋮----
export const getHeadingElementStyles = (
	styles: EmailStyles,
	headingLevel = 'heading',
	merge = false
): EmailStyles
⋮----
export const getElementStyles = (
	styles: EmailStyles,
	element: string,
	headingLevel = 'heading',
	merge = false
): EmailStyles =>
</file>

<file path="packages/js/email-editor/src/components/template-canvas-affordance/index.ts">

</file>

<file path="packages/js/email-editor/src/components/template-canvas-affordance/template-canvas-affordance.tsx">
import { Button } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { store as editorStore } from '@wordpress/editor';
import {
	createPortal,
	useCallback,
	useEffect,
	useRef,
	useState,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Icon, layout } from '@wordpress/icons';
⋮----
import { storeName } from '../../store';
import { recordEvent } from '../../events';
⋮----
function ensureCanvasStyles( canvasDocument: Document ): void
⋮----
type NavigateToEntityRecord = ( params: {
	postId: number | string;
	postType: string;
} ) => void;
⋮----
type AffordancePosition = {
	frame: {
		height: number;
		left: number;
		top: number;
		width: number;
	};
... (20 lines truncated)
</file>

<file path="packages/js/email-editor/src/components/template-select/async.ts">
import { useEffect, useState, flushSync } from '@wordpress/element';
import { createQueue } from '@wordpress/priority-queue';
⋮----
export function Async(
</file>

<file path="packages/js/email-editor/src/components/template-select/index.ts">

</file>

<file path="packages/js/email-editor/src/components/template-select/select-modal.tsx">
import { useState, useEffect, useMemo, memo } from '@wordpress/element';
import { store as editorStore } from '@wordpress/editor';
import { store as coreStore } from '@wordpress/core-data';
import type { UserPatternCategory } from '@wordpress/core-data/build-types/selectors';
import { dispatch, useSelect } from '@wordpress/data';
import { Modal, Button, Flex, FlexItem } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { Tabs } from '@wordpress/ui';
⋮----
import { usePreviewTemplates } from '../../hooks';
import {
	EmailEditorPostType,
	storeName,
	TemplateCategory,
	TemplatePreview,
} from '../../store';
import { TemplateList } from './template-list';
import { TemplateCategoriesListSidebar } from './template-categories-list-sidebar';
import { recordEvent, recordEventOnce } from '../../events';
⋮----
function getCategoriesFromTemplates(
	templates: TemplatePreview[],
	patternCategories: UserPatternCategory[]
): Array<
⋮----
function SelectTemplateBody( {
	templates,
	handleTemplateSelection,
	templateSelectMode,
} )
... (14 lines truncated)
</file>

<file path="packages/js/email-editor/src/components/template-select/template-categories-list-sidebar.tsx">
import { Tabs } from '@wordpress/ui';
⋮----
import { TemplateCategory } from '../../store';
⋮----
type Props = {
	templateCategories: Array< { name: TemplateCategory; label: string } >;
};
⋮----
export function TemplateCategoriesListSidebar(
</file>

<file path="packages/js/email-editor/src/components/template-select/template-list.tsx">
import { useMemo, memo } from '@wordpress/element';
import { store as editorStore } from '@wordpress/editor';
import { useSelect } from '@wordpress/data';
import { blockDefault } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
import { EmptyState, Notice, Stack } from '@wordpress/ui';
⋮----
import { BlockPreview } from '@wordpress/block-editor';
⋮----
import { Async } from './async';
import { TemplateCategory, TemplatePreview } from '../../store';
import { useEmailCss } from '../../hooks';
⋮----
type Props = {
	templates: TemplatePreview[];
	onTemplateSelection: ( template: TemplatePreview ) => void;
	selectedCategory?: TemplateCategory;
};
⋮----
function TemplateNoResults()
⋮----
const compareProps = ( prev, next )
</file>

<file path="packages/js/email-editor/src/components/template-select/template-selection.tsx">
import { useDispatch, useSelect } from '@wordpress/data';
⋮----
import { storeName } from '../../store';
import { SelectTemplateModal } from './select-modal';
⋮----
export function TemplateSelection()
⋮----
onSelectCallback=
</file>

<file path="packages/js/email-editor/src/config-tools/block-config.ts">
import {
	getBlockType,
	unregisterBlockType,
	registerBlockType,
} from '@wordpress/blocks';
import type { BlockConfiguration } from '@wordpress/blocks';
⋮----
export function updateBlockSettings<
	TAttributes extends Record< string, unknown > = Record< string, unknown >,
>(
	name: string,
	updater: (
		settings: BlockConfiguration< TAttributes >
)
⋮----
export function restoreAllModifiedBlockSettings(): string[]
</file>

<file path="packages/js/email-editor/src/config-tools/block-style.ts">
import { registerBlockStyle, unregisterBlockStyle } from '@wordpress/blocks';
import { select } from '@wordpress/data';
⋮----
export type BlockStyle = { name: string; label: string; isDefault?: boolean };
⋮----
function makeKey( blockName: string, styleName: string ): string
⋮----
export function registerBlockStyleForEmail(
	blockName: string,
	style: BlockStyle
): void
⋮----
export function unregisterBlockStyleForEmail(
	blockName: string,
	styleName: string
): void
⋮----
export function resetBlockStyles(): void
</file>

<file path="packages/js/email-editor/src/config-tools/block-variations.ts">
import {
	registerBlockVariation,
	unregisterBlockVariation,
	type BlockVariation,
} from '@wordpress/blocks';
⋮----
function makeKey( blockName: string, variationName: string ): string
⋮----
export function registerBlockVariationForEmail(
	blockName: string,
	variation: BlockVariation
): void
⋮----
export function resetBlockVariations(): void
</file>

<file path="packages/js/email-editor/src/config-tools/filters.ts">
import {
	addFilter,
	removeFilter,
	addAction,
	removeAction,
} from '@wordpress/hooks';
⋮----
function makeKey( hookName: string, namespace: string ): string
⋮----
export function addFilterForEmail<
	TCallback extends ( ...args: any[] ) => any,
>(
	hookName: string,
	namespace: string,
	callback: TCallback,
	priority?: number
): void
⋮----
export function addActionForEmail<
	TCallback extends ( ...args: any[] ) => any,
>(
	hookName: string,
	namespace: string,
	callback: TCallback,
	priority?: number
): void
⋮----
export function clearEmailFilters(): void
⋮----
export function clearEmailActions(): void
... (3 lines truncated)
</file>

<file path="packages/js/email-editor/src/config-tools/formats.ts">
import { registerFormatType, unregisterFormatType } from '@wordpress/rich-text';
⋮----
type WPFormat = {
	name: string;
	tagName: string;
	interactive: boolean;
	title: string;
	edit: any;
	className?: string;
	attributes?: Record< string, string >;
	object?: boolean;
};
⋮----
export function registerFormatForEmail(
	name: string,
	settings: WPFormat
): void
⋮----
export function unregisterFormatForEmail( name: string ): void
⋮----
export function resetFormats(): void
</file>

<file path="packages/js/email-editor/src/config-tools/index.ts">
import { resetBlockStyles } from './block-style';
import { resetBlockVariations } from './block-variations';
import { resetFormats } from './formats';
import { clearAllEmailHooks } from './filters';
import { restoreAllModifiedBlockSettings } from './block-config';
⋮----
export function cleanupConfigurationChanges(): void
</file>

<file path="packages/js/email-editor/src/events/dom-tracking.ts">
import { __ } from '@wordpress/i18n';
⋮----
import { recordEvent, isEventTrackingEnabled } from '.';
⋮----
function trackMatchingEvents( event: Event )
⋮----
export function initDomTracking()
</file>

<file path="packages/js/email-editor/src/events/event-collector.ts">
import { doAction } from '@wordpress/hooks';
⋮----
import {
	EMAIL_STRING,
	dispatcher,
	isEventTrackingEnabled,
} from './event-pipeline';
⋮----
const eventListenerHandler = ( eventData ) =>
⋮----
const initEventCollector = () =>
</file>

<file path="packages/js/email-editor/src/events/event-pipeline.ts">
import { debounce } from 'lodash';
import { applyFilters } from '@wordpress/hooks';
⋮----
const isEventTrackingEnabled = () =>
⋮----
const recordEvent = ( name: string, data =
</file>

<file path="packages/js/email-editor/src/events/index.ts">

</file>

<file path="packages/js/email-editor/src/events/store-tracking.ts">
import { use, select } from '@wordpress/data';
import { store as preferencesStore } from '@wordpress/preferences';
import { store as editorStore } from '@wordpress/editor';
import { __ } from '@wordpress/i18n';
⋮----
import { recordEvent, isEventTrackingEnabled } from '.';
⋮----
const trackSetDeviceType = ( deviceType: string ) =>
⋮----
const trackSetPreference = ( scope, name, value ) =>
⋮----
const trackBlockAndPatternInsertion = ( ...args ) =>
⋮----
const trackSetRenderingMode = ( renderingMode: string ) =>
⋮----
export const initStoreTracking = () =>
</file>

<file path="packages/js/email-editor/src/hacks/index.ts">
import { modifyTemplateActions } from './modify-template-actions';
import { modifyMoveToTrashAction } from './move-to-trash';
⋮----
export function initHacks()
</file>

<file path="packages/js/email-editor/src/hacks/modify-template-actions.tsx">
import { registerEntityAction, unregisterEntityAction } from '../private-apis';
import { addActionForEmail } from '../config-tools/filters';
import getResetEmailTemplateAction from '../components/sidebar/reset-email-template';
⋮----
const modifyActionsForPostType = ( postType: string ) =>
⋮----
function modifyTemplateActions()
</file>

<file path="packages/js/email-editor/src/hacks/move-to-trash.tsx">
import { registerEntityAction, unregisterEntityAction } from '../private-apis';
import { addActionForEmail } from '../config-tools/filters';
import getTrashEmailPostAction from '../components/header/trash-email-post';
⋮----
const removeDefaultMoveToTrashActionAddCustom = ( postType: string ) =>
⋮----
function modifyMoveToTrashAction()
</file>

<file path="packages/js/email-editor/src/hacks/notices-slot.tsx">
import { useEffect, useState, createPortal } from '@wordpress/element';
⋮----
export function NoticesSlot(
</file>

<file path="packages/js/email-editor/src/hacks/publish-save.tsx">
import {
	useEffect,
	createPortal,
	useCallback,
	useRef,
} from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { store as editorStore } from '@wordpress/editor';
⋮----
import { SendButton } from '../components/header/send-button';
⋮----
type NextButtonSlotPropType = {
	children: React.ReactNode;
};
</file>

<file path="packages/js/email-editor/src/hacks/README.md">
# Email Editor Hacks

We intentionally call these "hacks" because they are workarounds for missing upstream APIs in WordPress/Gutenberg. **Our goal is to work upstream with the WordPress and Gutenberg teams to get proper APIs added so we can remove these workarounds.**

Each hack below represents functionality that should ideally be supported through official WordPress/Gutenberg APIs.

## Current Hacks

### 1. Notices Slot ([notices-slot.tsx](notices-slot.tsx))

**Purpose:** Renders a portal for displaying notices before the visual editor.

**Missing Upstream API:** There is currently no API to add notices with custom context to the content area in the block editor.

**What it does:** Creates a DOM portal that inserts a container as the first child of the visual editor, allowing notices to be rendered in a custom location.

**Upstream solution needed:** An official API for registering custom notice contexts and controlling notice placement within the editor.

---

### 2. Publish/Save Button Management ([publish-save.tsx](publish-save.tsx))

**Purpose:** Conditionally hides the default publish button and adds a custom "Send" button for email posts.

**Missing Upstream API:** No official way to customize or replace the publish button behavior based on specific post type requirements.

**What it does:**

- Uses DOM manipulation and MutationObserver to hide/show the default publish button
- Creates a portal to render a custom "Send" button next to the publish button
... (37 lines truncated)
</file>

<file path="packages/js/email-editor/src/hooks/index.ts">

</file>

<file path="packages/js/email-editor/src/hooks/use-content-validation.ts">
import { useCallback, useEffect } from '@wordpress/element';
import { useSelect, subscribe, dispatch } from '@wordpress/data';
import { store as coreDataStore } from '@wordpress/core-data';
import { applyFilters } from '@wordpress/hooks';
⋮----
import {
	EmailContentValidationRule,
	storeName as emailEditorStore,
} from '../store';
import { useShallowEqual } from './use-shallow-equal';
import { useValidationNotices } from './use-validation-notices';
⋮----
export type ContentValidationData = {
	validateContent: () => boolean;
};
⋮----
export const validateEmailContent = (
	content: string,
	templateContent: string,
	{
		addValidationNotice,
		hasValidationNotice,
		removeValidationNotice,
	}: {
		addValidationNotice: (
			id: string,
			message: string,
			actions: unknown[]
)
⋮----
... (2 lines truncated)
</file>

<file path="packages/js/email-editor/src/hooks/use-editor-mode.ts">
import { useSelect } from '@wordpress/data';
import { store as editorStore } from '@wordpress/editor';
⋮----
export function useEditorMode()
</file>

<file path="packages/js/email-editor/src/hooks/use-email-css.ts">
import { useMemo } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { store as editorStore } from '@wordpress/editor';
import deepmerge from 'deepmerge';
⋮----
import { EmailTheme, EmailBuiltStyles, storeName } from '../store';
import { useUserTheme } from './use-user-theme';
import { useGlobalStylesOutputWithConfig } from './use-global-styles-output';
import { unwrapCompressedPresetStyleVariable } from '../style-variables';
⋮----
export function useEmailCss()
</file>

<file path="packages/js/email-editor/src/hooks/use-email-styles.ts">
import deepmerge from 'deepmerge';
import { useSelect } from '@wordpress/data';
import { useCallback, useMemo } from '@wordpress/element';
⋮----
import { storeName, EmailStyles } from '../store';
import { useUserTheme } from './use-user-theme';
⋮----
interface EmailStylesData {
	styles: EmailStyles;
	userStyles: EmailStyles;
	defaultStyles: EmailStyles;
	updateStyleProp: ( path, newValue ) => void;
	updateStyles: ( newStyles: EmailStyles ) => void;
}
⋮----
function isNestedEmpty( obj )
⋮----
export function setImmutably( setObject, setPath, value ): typeof setObject
⋮----
function shortenWpPresetVariables( obj )
⋮----
const replaceVariable = ( value ) =>
⋮----
const traverse = ( current ) =>
⋮----
function cleanupUserStyles( obj )
⋮----
const cleanObject = ( current ) =>
⋮----
export const useEmailStyles = (): EmailStylesData =>
... (1 lines truncated)
</file>

<file path="packages/js/email-editor/src/hooks/use-filter-editor-content-stylesheets.ts">
import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
import { applyFilters } from '@wordpress/hooks';
import { useSelect } from '@wordpress/data';
import { store as editorStore } from '@wordpress/editor';
⋮----
export const useFilterEditorContentStylesheets = () =>
</file>

<file path="packages/js/email-editor/src/hooks/use-global-styles-output.ts">
import {
	generateGlobalStyles,
	type GlobalStylesConfig,
} from '@wordpress/global-styles-engine';
import { useMemo } from '@wordpress/element';
⋮----
export const useGlobalStylesOutputWithConfig = (
	mergedConfig: GlobalStylesConfig = {}
) =>
</file>

<file path="packages/js/email-editor/src/hooks/use-is-email-editor.ts">
import { useSelect } from '@wordpress/data';
⋮----
import { storeName } from '../store';
import { EmailTemplate } from '../store/types';
⋮----
export function useIsEmailEditor(): boolean
</file>

<file path="packages/js/email-editor/src/hooks/use-navigate-to-entity-record.js">
export function useNavigateToEntityRecord(
	initialPostId,
	initialPostType,
	defaultRenderingMode
)
</file>

<file path="packages/js/email-editor/src/hooks/use-notice-overrides.ts">
import { useEffect } from '@wordpress/element';
import { createSelector, use } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';
⋮----
interface NoticeOverride {
	content: string;
	removeActions: boolean;
	contentCheck?: ( content: string ) => boolean;
}
⋮----
function getNoticeOverrides(): Record< string, NoticeOverride >
⋮----
interface Notice {
	id: string;
	content: string;
	spokenMessage: string;
	actions: unknown[];
	[ key: string ]: unknown;
}
⋮----
function transformNotice( notice: Notice ): Notice
⋮----
function applyOverridesToNotices( notices: Notice[] ): Notice[]
⋮----
function getStoreName( namespace: string |
⋮----
export function useNoticeOverrides(): void
</file>

<file path="packages/js/email-editor/src/hooks/use-preview-templates.ts">
import { useMemo } from '@wordpress/element';
import { parse } from '@wordpress/blocks';
import { BlockInstance } from '@wordpress/blocks/index';
import { useSelect } from '@wordpress/data';
import { applyFilters } from '@wordpress/hooks';
⋮----
import {
	storeName,
	EmailTemplatePreview,
	TemplatePreview,
	EmailEditorPostType,
} from '../store';
⋮----
function setPostContentInnerBlocks(
	templateBlocks: BlockInstance[],
	innerBlocks: BlockInstance[]
): BlockInstance[]
⋮----
type GenerateTemplateCssThemeType = {
	postTemplateContent?: EmailTemplatePreview;
};
⋮----
function generateTemplateContent(
	post: EmailEditorPostType,
	allTemplates: TemplatePreview[] = []
): GenerateTemplateCssThemeType
⋮----
export function usePreviewTemplates(
	customEmailContent = '',
	includeRecentPosts = true
... (2 lines truncated)
</file>

<file path="packages/js/email-editor/src/hooks/use-remove-saving-failed-notices.ts">
import { useEffect, useMemo } from '@wordpress/element';
import { subscribe, select, dispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';
⋮----
export const useRemoveSavingFailedNotices = () =>
</file>

<file path="packages/js/email-editor/src/hooks/use-shallow-equal.ts">
import { useRef } from '@wordpress/element';
import isShallowEqual from '@wordpress/is-shallow-equal';
⋮----
export function useShallowEqual< T >( value: T ): T
</file>

<file path="packages/js/email-editor/src/hooks/use-user-theme.ts">
import { useCallback, useMemo } from '@wordpress/element';
import { useSelect, dispatch } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
⋮----
import { EmailTheme, storeName } from '../store';
⋮----
export function useUserTheme()
</file>

<file path="packages/js/email-editor/src/hooks/use-validation-notices.ts">
import { useCallback } from '@wordpress/element';
import { dispatch, useSelect } from '@wordpress/data';
import { store as noticesStore } from '@wordpress/notices';
import type {
	NoticeAction,
	NoticeListProps,
} from '@wordpress/components/build-types/notice/types';
import type { WPNoticeAction } from '@wordpress/notices/build-types/store/actions';
⋮----
export type Notice = NoticeListProps[ 'notices' ][ number ];
⋮----
export type ValidationNoticesData = {
	notices: Notice[];
	hasValidationNotice: ( noticeId?: string ) => boolean;
	addValidationNotice: (
		noticeId: string,
		message: string,
		actions?: NoticeAction[]
	) => void;
	removeValidationNotice: ( noticeId: string ) => void;
};
⋮----
export const useValidationNotices = (): ValidationNoticesData =>
</file>

<file path="packages/js/email-editor/src/layouts/flex-email.tsx">
import clsx from 'clsx';
import { createHigherOrderComponent } from '@wordpress/compose';
import {
	getBlockSupport,
	hasBlockSupport,
	getBlockTypes,
} from '@wordpress/blocks';
import { Block } from '@wordpress/blocks/index';
import { __ } from '@wordpress/i18n';
import { justifyLeft, justifyCenter, justifyRight } from '@wordpress/icons';
import {
	Flex,
	FlexItem,
	__experimentalToolsPanel as ToolsPanel,
	__experimentalToolsPanelItem as ToolsPanelItem,
	__experimentalToggleGroupControl as ToggleGroupControl,
	__experimentalToggleGroupControlOptionIcon as ToggleGroupControlOptionIcon,
} from '@wordpress/components';
import {
	BlockControls,
	InspectorControls,
	JustifyContentControl,
} from '@wordpress/block-editor';
⋮----
import { addFilterForEmail, updateBlockSettings } from '../config-tools';
⋮----
function hasLayoutBlockSupport( blockName: string )
⋮----
function JustificationControls( {
	justificationValue,
... (12 lines truncated)
</file>

<file path="packages/js/email-editor/src/middleware/content-validation.ts">
import { use } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
⋮----
import { storeName as emailEditorStore } from '../store';
⋮----
export const initContentValidationMiddleware = () =>
</file>

<file path="packages/js/email-editor/src/private-apis/index.ts">
import { dispatch } from '@wordpress/data';
import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis';
import {
	privateApis as editorPrivateApis,
	store as editorStore,
} from '@wordpress/editor';
import {
	privateApis as blockEditorPrivateApis,
} from '@wordpress/block-editor';
</file>

<file path="packages/js/email-editor/src/private-apis/README.md">
# Private APIs

This module is used to unlock the private APIs the email editor uses from WordPress.
</file>

<file path="packages/js/email-editor/src/store/actions.ts">
import { select } from '@wordpress/data';
import { store as coreDataStore } from '@wordpress/core-data';
import { apiFetch } from '@wordpress/data-controls';
⋮----
import { storeName, PERSONALIZATION_TAG_ENTITY } from './constants';
import { getPersonalizationTagsQuery } from './personalization-tags-query';
import {
	SendingPreviewStatus,
	State,
	ContentValidation,
	EmailEditorSettings,
	EmailTheme,
	EmailEditorUrls,
} from './types';
import { recordEvent } from '../events';
⋮----
export function togglePreviewModal( isOpen: boolean )
⋮----
export function updateSendPreviewEmail( toEmail: string )
⋮----
export const setEmailPost =
( postId: number | string, postType: string )
⋮----
export const invalidatePersonalizationTagsCache =
()
⋮----
export function setEmailPostType( postType: string )
⋮----
export const setTemplateToPost =
( templateSlug )
... (21 lines truncated)
</file>

<file path="packages/js/email-editor/src/store/constants.ts">

</file>

<file path="packages/js/email-editor/src/store/index.ts">

</file>

<file path="packages/js/email-editor/src/store/initial-state.ts">
import { State } from './types';
⋮----
export function getInitialState(): State
</file>

<file path="packages/js/email-editor/src/store/personalization-tags-query.ts">
export type PersonalizationTagsQuery = {
	context: string;
	per_page: number;
	post_id?: number | string;
};
⋮----
export function getPersonalizationTagsQuery(
	postId: number | string | undefined
): PersonalizationTagsQuery
</file>

<file path="packages/js/email-editor/src/store/reducer.ts">
import { State } from './types';
⋮----
export function reducer( state: State, action ): State
</file>

<file path="packages/js/email-editor/src/store/selectors.ts">
import { createRegistrySelector, createSelector } from '@wordpress/data';
import { store as coreDataStore } from '@wordpress/core-data';
import { store as editorStore } from '@wordpress/editor';
import { store as preferencesStore } from '@wordpress/preferences';
import { serialize, parse, BlockInstance } from '@wordpress/blocks';
import { applyFilters } from '@wordpress/hooks';
⋮----
import { storeName, PERSONALIZATION_TAG_ENTITY } from './constants';
import { getPersonalizationTagsQuery } from './personalization-tags-query';
import {
	State,
	EmailTemplate,
	EmailEditorPostType,
	Feature,
	PersonalizationTag,
	GlobalEmailStylesPost,
	RecentEmailsQuery,
} from './types';
⋮----
function getContentFromEntity( entity ): string
⋮----
type PatternWithContent = {
	content: string;
	emailContent?: string;
	categories?: string[];
	[ key: string ]: unknown;
};
⋮----
type EnhancedPattern = PatternWithContent & {
	readonly blocks: BlockInstance[];
... (64 lines truncated)
</file>

<file path="packages/js/email-editor/src/store/settings.ts">
import { EmailEditorSettings, EmailTheme, EmailEditorUrls } from './types';
⋮----
function getEditorSettings(): EmailEditorSettings
⋮----
function getEditorTheme(): EmailTheme
⋮----
function getUrls(): EmailEditorUrls
⋮----
export function getEditorConfigFromWindow()
</file>

<file path="packages/js/email-editor/src/store/store.ts">
import { createReduxStore, register, select, dispatch } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
⋮----
import {
	ReduxStoreConfig,
	StoreDescriptor as GenericStoreDescriptor,
} from '@wordpress/data/build-types/types';
import { controls } from '@wordpress/data-controls';
⋮----
import { storeName, PERSONALIZATION_TAG_ENTITY } from './constants';
import { getInitialState } from './initial-state';
import { reducer } from './reducer';
⋮----
const getConfig = ()
⋮----
export type EditorStoreConfig = ReturnType< typeof getConfig >;
⋮----
export const createStore = () =>
⋮----
export interface EmailEditorStore {
	getActions: () => EditorStoreConfig[ 'actions' ];
	getSelectors: () => EditorStoreConfig[ 'selectors' ];
}
⋮----
interface StoreRegistry {
		[ storeName ]: GenericStoreDescriptor<
			ReduxStoreConfig<
				unknown,
				ReturnType< EmailEditorStore[ 'getActions' ] >,
				ReturnType< EmailEditorStore[ 'getSelectors' ] >
... (4 lines truncated)
</file>

<file path="packages/js/email-editor/src/store/types.ts">
import { EditorSettings, EditorColor } from '@wordpress/block-editor/index';
import { BlockInstance } from '@wordpress/blocks/index';
import { Post } from '@wordpress/core-data/build-types/entity-types/post';
import type { WpTemplate } from '@wordpress/core-data';
import type { GlobalStylesConfig } from '@wordpress/global-styles-engine';
⋮----
export interface EmailTemplate extends Omit< WpTemplate, 'title' > {
	post_types: string[];
	title: string;
}
⋮----
export enum SendingPreviewStatus {
	SUCCESS = 'success',
	ERROR = 'error',
}
⋮----
export type ExperimentalSettings = {
	__experimentalFeatures: {
		color: {
			custom: boolean;
			text: boolean;
			background: boolean;
			customGradient: boolean;
			defaultPalette: boolean;
			palette: {
				default: EditorColor[];
				theme: EditorColor[];
			};
			gradients: {
				default: EditorColor[];
... (191 lines truncated)
</file>

<file path="packages/js/email-editor/src/types/index.ts">
export type FontFamily = {
	name: string;
	slug: string;
	fontFamily: string;
};
</file>

<file path="packages/js/email-editor/src/editor.tsx">
import { useSelect, useDispatch, select, dispatch } from '@wordpress/data';
import {
	StrictMode,
	createRoot,
	useEffect,
	useState,
	useMemo,
} from '@wordpress/element';
import { addFilter, applyFilters, hasFilter } from '@wordpress/hooks';
import { store as editorStore } from '@wordpress/editor';
import { useMergeRefs } from '@wordpress/compose';
⋮----
import { getAllowedBlockNames, initBlocks } from './blocks';
import { initializeLayout } from './layouts/flex-email';
import { InnerEditor } from './components/block-editor';
import { createStore, storeName } from './store';
import { initTextHooks } from './text-hooks';
import {
	initEventCollector,
	initStoreTracking,
	initDomTracking,
} from './events';
import { initContentValidationMiddleware } from './middleware/content-validation';
import { initHacks } from './hacks';
import {
	useContentValidation,
	useFilterEditorContentStylesheets,
	useNoticeOverrides,
	useRemoveSavingFailedNotices,
} from './hooks';
... (44 lines truncated)
</file>

<file path="packages/js/email-editor/src/global.d.ts">
interface Window {
	_wpCollaborationEnabled?: boolean;
	WooCommerceEmailEditor: {
		current_wp_user_email: string;
		user_theme_post_id: number;
		urls: {
			listings: string;
			send: string;
		};
		editor_settings: unknown;
		editor_theme: unknown;
		current_post_type: string;
		current_post_id: string;
	};
	__i18n_text_domain__?: string;
}
</file>

<file path="packages/js/email-editor/src/index.ts">
import { initialize } from './editor';
⋮----
export function initializeEditor( htmlId: string )
</file>

<file path="packages/js/email-editor/src/style-variables.ts">
export function unwrapCompressedPresetStyleVariableName(
	value: string
): string | null
⋮----
export function unwrapCompressedPresetStyleVariable( value: string ): string
⋮----
export function getCompressedVariableValue( value: string ): string
</file>

<file path="packages/js/email-editor/src/telemetry-tracking.md">
# Editor Telemetry Tracking

The email editor has a built in system for tracking its telemetry that can be used to track users interactions with the editor.

## Enabling Tracking

To enable tracking an integrator needs to add the following filters.

```js
// enable email editor event tracking
addFilter(
	'woocommerce_email_editor_events_tracking_enabled',
	'your_plugin_namespace',
	() => true
);

// process events tracked in the editor
addAction(
	'woocommerce_email_editor_events',
	'your_plugin_namespace',
	( editorEvent ) => {
		const { name, ...data } = editorEvent;
		// Replace console.log with your tracking code
		console.log( name, data );
	}
);
```

## Tracked events

... (81 lines truncated)
</file>

<file path="packages/js/email-editor/src/text-hooks.ts">
import { __ } from '@wordpress/i18n';
⋮----
import { addFilterForEmail } from './config-tools';
⋮----
export const initTextHooks = (): void =>
</file>

<file path="packages/js/email-editor/typings/monorepo-enhancements.d.ts">

</file>

<file path="packages/js/email-editor/typings/wordpress-modules.d.ts">
import { StoreDescriptor } from '@wordpress/data/build-types/types';
⋮----
import { FontSize } from '@wordpress/components/build-types/font-size-picker/types';
import {
		Color,
		Gradient,
	} from '@wordpress/components/build-types/palette-edit/types';
import { FontFamily } from '../src/types';
⋮----
export function useSettings( path: string ): unknown;
export function useSettings(
		path1: 'typography.fontSizes',
		path2: 'typography.fontFamilies'
): [ FontSize[],
export function useSettings(
		path1: 'color.palette',
		path2: 'color.gradients'
	): [ Color[], Gradient[] ];
export function useSettings( path: 'typography.fontSizes' ): [ FontSize[] ];
⋮----
export interface EditorSettings {
		gradients: {
			name: string;
			slug: string;
			gradient: string;
		}[];
	}
</file>

<file path="packages/js/email-editor/.npmrc">
package-lock=false
</file>

<file path="packages/js/email-editor/.prettierrc.js">

</file>

<file path="packages/js/email-editor/.stylelintrc">
{
	"extends": "@wordpress/stylelint-config",
	"customSyntax": "postcss-scss",
	"rules": {
		"selector-class-pattern": null,
		"at-rule-empty-line-before": null,
		"at-rule-no-unknown": null,
		"comment-empty-line-before": null,
		"declaration-colon-newline-after": null,
		"font-weight-notation": null,
		"function-parentheses-space-inside": null,
		"function-comma-space-after": null,
		"indentation": null,
		"max-line-length": null,
		"no-descending-specificity": null,
		"no-duplicate-selectors": null,
		"rule-empty-line-before": null,
		"value-keyword-case": null
	}
}
</file>

<file path="packages/js/email-editor/blueprint.json">
{
	"landingPage": "/wp-admin/admin.php?page=wc-settings&tab=email",
	"preferredVersions": {
		"php": "8.2",
		"wp": "latest"
	},
	"features": {
		"networking": true
	},
	"steps": [
		{
			"step": "login",
			"username": "admin"
		},
		{
			"step": "installPlugin",
			"pluginData": {
				"resource": "url",
				"url": "https://github-proxy.com/https://github.com/woocommerce/woocommerce/releases/download/nightly/woocommerce-trunk-nightly.zip"
			}
		},
		{
			"step": "runPHP",
			"code": "<?php include 'wordpress/wp-load.php'; delete_transient( '_wc_activation_redirect' ); update_option( 'woocommerce_feature_block_email_editor_enabled', 'yes' );"
		}
	]
}
</file>

<file path="packages/js/email-editor/build.mjs">

</file>

<file path="packages/js/email-editor/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.4.1](https://www.npmjs.com/package/@woocommerce/email-editor/v/2.4.1) - 2026-09-03 

-   Patch - Render the compact back button on WordPress 7.1 again, where the header sizes the back button column by its content [#68017]
-   Patch - Restore the Personalization Tags toolbar button on the Button block by registering the shortcode format as non-interactive [#68217]

## [2.4.0](https://www.npmjs.com/package/@woocommerce/email-editor/v/2.4.0) - 2026-08-21 

-   Minor - Add the `woocommerce_email_editor_recent_emails_query` filter so integrations can change which emails the "Recent" category of the template selection modal lists. [#67859]
-   Patch - Update npm dependencies that resolve high-severity security advisories. [#67844]

## [2.3.0](https://www.npmjs.com/package/@woocommerce/email-editor/v/2.3.0) - 2026-08-12 

-   Minor - Add optional customSaveButton prop to Editor/ExperimentalEmailEditor (threaded to the Gutenberg editor header, skipped in template mode) and extend the editor-save notice override to also match "Post published." and "Draft saved." for integrations whose save button publishes in the background. [#67025]
-   Minor - Restore text and background color controls in the styles sidebar on WordPress 7.1+ — text color moves to the typography panel and background color to a new Background screen, matching where WordPress 7.1 places them. [#67467]
-   Minor - Disable the WordPress 7.1 responsive styles feature in the email editor [#67444]
-   Minor - Render the editor back button as a compact chevron on WordPress 7.1+ to match the redesigned header, keeping the fullscreen-style button on older versions. The close button's default action now navigates only to http(s) back URLs (`urls.back`); non-web schemes no longer navigate. Integrations needing a custom scheme can provide their own callback via the `woocommerce_email_editor_close_action_callback` filter. [#67470]

## [2.2.1](https://www.npmjs.com/package/@woocommerce/email-editor/v/2.2.1) - 2026-07-30 

-   Patch - Stop regenerating the global styles stylesheet and re-filtering personalization tags on every render, which made typing in the editor canvas sluggish. [#67031]

## [2.2.0](https://www.npmjs.com/package/@woocommerce/email-editor/v/2.2.0) - 2026-07-28 

-   Patch - Fix crash when opening the typography styles panel in the email editor for elements without typography styles defined. [#65613]
-   Patch - Memoize the regularized entity record so the global styles and template selectors return a stable reference, preventing an infinite re-render loop (React error #185) for users who lack the edit_theme_options capability. [#65684]
-   Patch - Restore the "Preview in new tab" unsaved-changes guard and its telemetry event on WordPress 7.1, which dropped the editor-preview-dropdown__button-external class the code matched on. [#66736]
... (190 lines truncated)
</file>

<file path="packages/js/email-editor/composer.json">
{
	"name": "woocommerce/email-editor-config",
	"description": "Email editor based on WordPress Gutenberg package.",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/email-editor/development.md">
# Development

## Local Development

The most efficient way to develop the Email Editor is by using the WooCommerce plugin's watch command:

```bash
pnpm --filter='@woocommerce/plugin-woocommerce' watch:build:admin
```

---

## Translation text domain

Translation function calls inside the package (`__()`, `_x()`, `_n()`, `_nx()`) use the `__i18n_text_domain__` identifier as the text domain argument instead of a hardcoded string literal. This lets each consumer of the package (WooCommerce, MailPoet, or any other plugin) substitute its own text domain at bundle time and extract strings under that domain with `wp i18n make-pot`.

If the identifier is not substituted, the package falls back to `'woocommerce'` at runtime (assigned in `src/index.ts`) so the editor still loads and renders with English strings — matching the package's pre-1.11 behaviour. Consumers that want their own translations to apply **should** replace the identifier with a string literal during their own build, typically with [`webpack.DefinePlugin`](https://webpack.js.org/plugins/define-plugin/):

```js
// consumer webpack.config.js
const webpack = require( 'webpack' );

module.exports = {
	// …
	plugins: [
		new webpack.DefinePlugin( {
			__i18n_text_domain__: JSON.stringify( 'your-text-domain' ),
		} ),
	],
};
... (97 lines truncated)
</file>

<file path="packages/js/email-editor/eslint.config.mjs">
/**
 * Internal dependencies
 */
⋮----
/*
			 * Translation calls use the `__i18n_text_domain__` identifier so each
			 * consumer of this package can substitute its own text domain at
			 * bundle time (see `development.md`). The default
			 * `@wordpress/i18n-text-domain` rule expects a string literal here, so
			 * disable it for the package source.
			 */
</file>

<file path="packages/js/email-editor/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js",
	"setupFiles": [
		"<rootDir>/jest.setup.ts"
	]
}
</file>

<file path="packages/js/email-editor/jest.setup.ts">

</file>

<file path="packages/js/email-editor/package.json">
{
	"name": "@woocommerce/email-editor",
	"version": "2.4.1",
	"description": "Gutenberg based email editor that is used in WooCommerce emails.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"keywords": [
		"wordpress",
		"woocommerce",
		"email"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/email-editor",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
	"main": "build/index.js",
	"module": "build-module/index.js",
	"types": "build-types/index.d.ts",
... (156 lines truncated)
</file>

<file path="packages/js/email-editor/README.md">
# WooCommerce Email Editor

This is the WooCommerce Email Editor package - a JavaScript library for building and customizing email templates. While currently integrated with WooCommerce, this package is designed to be used as an independent library in other projects.

You can try the email editor in [the WordPress Playground](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/woocommerce/woocommerce/refs/heads/trunk/packages/js/email-editor/blueprint.json).

This JavaScript package is designed to work in conjunction with its PHP counterpart, which can be found in the same repository at `packages/php/email-editor`. Both packages are required for full functionality.

## Initializing the editor

> **Note:** The `initializeEditor` function is currently experimental and its API is subject to change in future releases. Please be aware that breaking changes may occur.

To use the email editor in your project, you'll need to initialize it using the `initializeEditor` function. The editor requires certain data to be set on the global `window.WooCommerceEmailEditor` object before initialization:

```javascript
// First, set up the required data on the window object
window.WooCommerceEmailEditor = {
    current_post_type: '', // The post type of the current post
    current_post_id: '', // The ID of the current post
    current_wp_user_email: '', // The email of the current user
    editor_settings: {
        // Standard block editor settings, plus email-editor-specific options.
        // See the "Editor settings" section below for available options.
    },
    editor_theme: {}, // The block editor theme
    user_theme_post_id: '', // The ID of the user theme post
    urls: {
        listings: '', // optional: The URL for the listings page
        send: '', // optional: The URL for the send button
        back: '', // optional: The URL for the back button (top left corner)
... (336 lines truncated)
</file>

<file path="packages/js/email-editor/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationDir": "build-types",
		"resolveJsonModule": true,
		"allowSyntheticDefaultImports": true,
		"downlevelIteration": true,
		"jsx": "react-jsx",
		"jsxFactory": null,
		"jsxFragmentFactory": null,
		"alwaysStrict": true,
		"strictBindCallApply": false,
		"strictFunctionTypes": false,
		"strictNullChecks": false,
		"strictPropertyInitialization": false,
		"noImplicitAny": false,
		"noImplicitThis": false,
		"forceConsistentCasingInFileNames": true,
		"noFallthroughCasesInSwitch": true,
		"noImplicitReturns": true,
		"noUnusedLocals": true,
		"noUnusedParameters": true,
		"typeRoots": [
			"./node_modules/@types"
		],
		"composite": true
	},
... (10 lines truncated)
</file>

<file path="packages/js/email-editor/webpack.config.js">

</file>

<file path="packages/js/email-editor/writing-e2e-tests.md">
# Writing E2E Tests for WooCommerce Email Editor

## Table of Contents

1. [Prerequisites](#prerequisites)
2. [Test Structure](#test-structure)
3. [Writing Tests](#writing-tests)
4. [Best Practices](#best-practices)
5. [Debugging Tests](#debugging-tests)

## Prerequisites

1. **Environment Setup**:

   ```bash
   # From repository root (PNPM uses the pinned Node version automatically)
   pnpm install
   pnpm --filter='@woocommerce/plugin-woocommerce' build
   cd plugins/woocommerce
   pnpm env:start 
   ```

   or 

   ```bash
   # From anywhere
   pnpm --filter='@woocommerce/plugin-woocommerce' build
   pnpm --filter='@woocommerce/plugin-woocommerce' wp-env start
   ```

... (178 lines truncated)
</file>

<file path="packages/js/eslint-plugin/changelog/.gitkeep">

</file>

<file path="packages/js/eslint-plugin/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/eslint-plugin/.npmrc">
package-lock=false
</file>

<file path="packages/js/eslint-plugin/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [4.0.0](https://www.npmjs.com/package/@woocommerce/eslint-plugin/v/4.0.0) - 2026-08-06 

-   Major [ **BREAKING CHANGE** ] - Add ESLint v9/v10 Flat Config support. `configs.recommended` is now a Flat Config array rather than an eslintrc object, the `eslint` peer range is `^9.22.0 || ^10.0.0`, and prettier `>=3` is required. There is no eslintrc compatibility wrapper: consumers must migrate to `eslint.config.mjs`. Do not register `eslint-plugin-import` or `eslint-plugin-react` yourself; neither supports ESLint v10, and `recommended` provides the wrapped instances. [#66621]
-   Major [ **BREAKING CHANGE** ] - Replace the `@woocommerce/dependency-group` rule with `import/order`. The custom rule is removed (rule, test, docs, and export); the recommended config now enforces import grouping via `import/order` and no longer requires the `/* External/Internal dependencies */` comment blocks. [#66086]

## [3.0.0](https://www.npmjs.com/package/@woocommerce/eslint-plugin/v/3.0.0) - 2026-06-10 

-   Major [ **BREAKING CHANGE** ] - Remove unused React imports from ESLint config; consuming projects may see new lint errors. [#55554]
-   Minor - Bump jest package dependency to 29.5.x. [#60324]
-   Minor - Fix typos in README.md files. [#48569]
-   Minor - Monorepo: bump pnpm version to 9.15.0. [#54189]
-   Minor - Upgraded TypeScript in the monorepo to 5.7.2. [#53165]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - CI: leverage composer packages cache in lint monorepo job. [#52054]
-   Patch - Fix pnpm version to 9.1.3 to avoid dependency installation issues. [#50828]
-   Patch - Monorepo: consolidate @babel/* dependencies versions across the monorepo. [#56575]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Monorepo: consolidate syncpack config around React 17/18 usage. [#52022]
-   Patch - Removed stray wireit devDependency. [#65210]
-   Patch - Update wireit to 0.14.10. [#54996]

## [2.3.0](https://www.npmjs.com/package/@woocommerce/eslint-plugin/v/2.3.0) - 2024-06-11 

-   Minor - Update deps and fix a bug where package rc files were not respected. [#36988]
-   Minor - Warn for jsdoc errors, use wp-prettier [#38523]
-   Minor - Bump node version. [#45148]
... (27 lines truncated)
</file>

<file path="packages/js/eslint-plugin/composer.json">
{
	"name": "woocommerce/eslint-plugin",
	"description": "ESLint plugin for WooCommerce development.",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/eslint-plugin/eslint.config.mjs">
/**
 * Internal dependencies
 */
⋮----
/*
 * This package is the base that @woocommerce/eslint-config consumes, so it lints
 * itself with its own recommended config rather than the private layer -
 * depending on that layer would be a dependency cycle. That also means it does
 * not get the private layer's relaxations, so the one that applies to this
 * package's own files is repeated here.
 */
⋮----
/*
		 * These configs are CommonJS by design - index.js requires them - so the
		 * rule typescript-eslint v8 added to its recommended set does not apply.
		 */
</file>

<file path="packages/js/eslint-plugin/index.js">
function dedupePlugins( configs )
</file>

<file path="packages/js/eslint-plugin/package.json">
{
	"name": "@woocommerce/eslint-plugin",
	"version": "4.0.0",
	"description": "ESLint plugin for WooCommerce development.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"keywords": [
		"wordpress",
		"woocommerce",
		"eslint",
		"plugin"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/eslint-plugin/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git",
		"directory": "packages/eslint-plugin"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"files": [
		"configs",
		"index.js"
	],
	"main": "index.js",
	"dependencies": {
... (43 lines truncated)
</file>

<file path="packages/js/eslint-plugin/PREVIOUS_CHANGELOG.md">
# 2.0.0

-   Update all js packages with minor/patch version changes. #8392

## Breaking changes

-   Update ESLint from v7 to ^8. #8475
-   Update `eslint-plugin-testing-library` from v3 to v5. #8475
    -   `no-unnecessary-act` is now enabled by default.
    -   `no-wait-for-multiple-assertions` is now enabled by default.
-   Update `@wordpress/eslint-plugin` from v8 to v11. #8475
-   Update `@typescript-eslint/parser` from v4 to v5. #8475
-   Drop support for Node v10. Required node version is now ^12.22.0 || ^14.17.0 || >=16.0.0. #8475
-   Update recommended eslint rules for @woocommerce/\* packages, please see `recommended.js` for details.

# 1.2.0

-   Updated `dependency-group` rule to have imports starting with `~/` labeled as local. #6517

# 1.1.0

-   Updated `@wordpress/eslint-plugin` dependency to latest version.
    -   `jsdoc` linting is configured to allow typescript style jsdocs.

# 1.0.0

-   Released package
</file>

<file path="packages/js/eslint-plugin/README.md">
# ESLint Plugin

This is an [ESLint](https://eslint.org/) plugin including configurations for WooCommerce development.

**Note:** This primarily extends the [`@wordpress/eslint-plugin/recommended`](https://github.com/WordPress/gutenberg/tree/trunk/packages/eslint-plugin) ruleset and does not change any of the rules exposed on that plugin. As a base, all WooCommerce projects are expected to follow WordPress JavaScript Code Styles.

However, this ruleset does implement the following (which do not conflict with WordPress standards):

- Using typescript eslint parser to allow for eslint Import ([see issue](https://github.com/gajus/eslint-plugin-jsdoc/issues/604#issuecomment-653962767))
- prettier formatting (using `wp-prettier`)
- Import grouping (external before internal) via `import/order`
- No yoda conditionals
- Radix argument required for `parseInt`.

## Requirements

This package is **Flat Config only**. It requires:

- ESLint `^9.22.0 || ^10.0.0` (9.22 ships the `eslint/config` helpers this uses)
- `prettier` `>=3` (WooCommerce uses `wp-prettier@3`)
- `typescript` `>=5`

There is no `.eslintrc` support and no compatibility wrapper. If you are still on
ESLint 8, stay on `@woocommerce/eslint-plugin@3`.

## Installation

Install the module

```bash
... (81 lines truncated)
</file>

<file path="packages/js/experimental/changelog/.gitkeep">

</file>

<file path="packages/js/experimental/changelog/66078-dehoist-react">
Significance: patch
Type: dev
Comment: Declare react/react-dom as devDependencies alongside the existing peerDependencies. Tooling only; no runtime change.
</file>

<file path="packages/js/experimental/changelog/add-dismiss-whats-next-tasks">
Significance: minor
Type: add

Add support for secondary actions in experimental task list items.
</file>

<file path="packages/js/experimental/changelog/consolidate-eslint-core-modules">
Significance: patch
Type: dev
Comment: Consolidate the shared `import/core-modules` list into `@woocommerce/eslint-config`. Tooling only; no runtime change.
</file>

<file path="packages/js/experimental/changelog/tweak-woo-home-dashboard-task-styles">
Significance: patch
Type: tweak

Polish experimental task and inbox note spacing used by Woo Home dashboard cards.
</file>

<file path="packages/js/experimental/changelog/woo6-109-storybook-10">
Significance: patch
Type: dev
Comment: Upgrade Storybook development tooling to version 10.
</file>

<file path="packages/js/experimental/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/experimental/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/experimental/src/experimental-list/collapsible-list/index.tsx">
import { Icon, chevronUp, chevronDown } from '@wordpress/icons';
import {
	createElement,
	useState,
	useCallback,
	useEffect,
	Children,
	useRef,
	isValidElement,
	cloneElement,
} from '@wordpress/element';
import {
	Transition,
	CSSTransition,
	TransitionGroup,
	TransitionStatus,
} from 'react-transition-group';
import clsx from 'clsx';
⋮----
import { ExperimentalListItem } from '../experimental-list-item';
import { ListProps, ExperimentalList } from '../experimental-list';
⋮----
type CollapsibleListProps = {
	collapseLabel: string;
	expandLabel: string;
	collapsed?: boolean;
	show?: number;
	onCollapse?: () => void;
	onExpand?: () => void;
	direction?: 'up' | 'down';
... (20 lines truncated)
</file>

<file path="packages/js/experimental/src/experimental-list/stories/experimental-list.story.tsx">
import { createElement } from '@wordpress/element';
import { Meta, StoryFn } from '@storybook/react-webpack5';
⋮----
import { List, ListItem, CollapsibleList } from '../..';
import { TaskItem } from '../task-item';
import { ListProps } from '../experimental-list';
⋮----
const Template: StoryFn< ListProps > = ( args ) => (
	<List { ...args }>
		<ListItem disableGutters onClick={ () => {} }>
			<div>Without gutters no padding is added to the list item.</div>
		</ListItem>
		<ListItem onClick={ () => {} }>
			<div>Any markup can go here.</div>
		</ListItem>
		<ListItem onClick={ () => {} }>
			<div>Any markup can go here.</div>
		</ListItem>
		<ListItem onClick={ () => {} }>
			<div>Any markup can go here.</div>
		</ListItem>
	</List>
);
⋮----
export const CollapsibleListExample: StoryFn = ( args ) =>
⋮----
export const TaskItemExample: StoryFn = ( args ) => (
	<List { ...args }>
		<TaskItem
action=
... (11 lines truncated)
</file>

<file path="packages/js/experimental/src/experimental-list/task-item/index.tsx">
import {
	createElement,
	Fragment,
	useEffect,
	useState,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Icon, check } from '@wordpress/icons';
import { Button, Tooltip } from '@wordpress/components';
import NoticeOutline from 'gridicons/dist/notice-outline';
import { EllipsisMenu } from '@woocommerce/components';
import clsx from 'clsx';
import { sanitizeHTML } from '@woocommerce/sanitize';
⋮----
import { Text } from '../../text';
import { ExperimentalListItem as ListItem } from '../experimental-list-item';
import { VerticalCSSTransition } from '../../vertical-css-transition';
⋮----
type TaskLevel = 1 | 2 | 3;
⋮----
type ActionArgs = {
	isExpanded?: boolean;
};
⋮----
type TaskItemProps = {
	title: string;
	completed: boolean;
	inProgress: boolean;
	inProgressLabel: string;
	onClick?: React.MouseEventHandler< HTMLElement >;
... (50 lines truncated)
</file>

<file path="packages/js/experimental/src/experimental-list/task-item/README.md">
# TaskItem

Use `TaskItem` to display a task item.

## Usage

```jsx
<TaskItem
	action={ () => alert( '"My action" button has been clicked' ) }
	actionLabel="My action"
	additionalInfo="Additional task information"
	badge="Task badge"
	completed={ true }
	content="Task content"
	expandable={ false }
	expanded={ false }
	level="Task title"
	onClick={ () => alert( 'The task has been clicked' ) }
	onCollapse={ () => alert( 'The task was collapsed' ) }
	onDelete={ () => alert( 'The task has been deleted' ) }
	onDismiss={ () => alert( 'The task was dismissed' ) }
	onExpand={ () => alert( 'The task was expanded' ) }
	onSnooze={ () => alert( 'The task was snoozed' ) }
	showActionButton={ false }
	time="10 minutes"
	title="Task title"
/>
```

### Props
... (22 lines truncated)
</file>

<file path="packages/js/experimental/src/experimental-list/experimental-list-item.tsx">
import { CSSTransition } from 'react-transition-group';
import { createElement } from '@wordpress/element';
import { ENTER } from '@wordpress/keycodes';
import clsx from 'clsx';
⋮----
function handleKeyDown(
	event: React.KeyboardEvent< HTMLElement >,
	onClick?:
		| React.MouseEventHandler< HTMLElement >
		| React.KeyboardEventHandler< HTMLElement >
)
⋮----
type CSSTransitionProps = {
	in: boolean;
	exit: boolean;
	enter: boolean;
	onExited: () => void;
};
⋮----
type ListItemProps = {
	disableGutters?: boolean;
	animation?: ListAnimation;
	className?: string;
} & Partial< CSSTransitionProps > &
	React.AllHTMLAttributes< HTMLElement >;
⋮----
export type ListAnimation = 'slide-right' | 'none' | 'custom';
⋮----
export const ExperimentalListItem = ( {
	children,
... (16 lines truncated)
</file>

<file path="packages/js/experimental/src/experimental-list/experimental-list.tsx">
import {
	createElement,
	Children,
	cloneElement,
	isValidElement,
} from '@wordpress/element';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
⋮----
import type { ListAnimation } from './experimental-list-item';
⋮----
type ListType = 'ol' | 'ul';
⋮----
export type ListProps = {
	listType?: ListType;
	animation?: ListAnimation;
} & React.HTMLAttributes< HTMLElement >;
⋮----
export const ExperimentalList = ( {
	children,
	listType,
	animation = 'none',
	...otherProps
}: ListProps ) =>
</file>

<file path="packages/js/experimental/src/inbox-note/action.tsx">
import { Button } from '@wordpress/components';
import { createElement, useState } from '@wordpress/element';
⋮----
type InboxNoteActionProps = {
	onClick: () => void;
	label: string;
	href?: string;
	preventBusyState?: boolean;
	variant: 'link' | 'secondary';
};
⋮----
export const InboxNoteActionButton = ( {
	label,
	onClick,
	href,
	preventBusyState,
	variant = 'link',
}: InboxNoteActionProps ) =>
⋮----
const handleActionClick: React.MouseEventHandler<
		HTMLAnchorElement | HTMLButtonElement
> = ( event ) =>
⋮----
isActionable = false; // link buttons shouldn't be "busy".
</file>

<file path="packages/js/experimental/src/inbox-note/inbox-dismiss-confirmation-modal.tsx">
import { __ } from '@wordpress/i18n';
import { Button, Modal } from '@wordpress/components';
import { createElement, useState } from '@wordpress/element';
⋮----
type ConfirmationModalProps = {
	onClose: () => void;
	onDismiss: () => void;
	buttonLabel?: string;
};
⋮----
title=
⋮----
<Button isSecondary onClick=
</file>

<file path="packages/js/experimental/src/inbox-note/inbox-note.tsx">
import { __ } from '@wordpress/i18n';
import { createElement, Fragment, useState } from '@wordpress/element';
import { Button } from '@wordpress/components';
import { useInView } from 'react-intersection-observer';
import moment from 'moment';
import clsx from 'clsx';
import { H, Section } from '@woocommerce/components';
import { sanitizeHTML } from '@woocommerce/sanitize';
⋮----
import { InboxNoteActionButton } from './action';
import { useCallbackOnLinkClick } from './use-callback-on-link-click';
⋮----
type InboxNoteAction = {
	id: number;
	url: string;
	label: string;
	primary: boolean;
	actioned_text?: boolean;
};
⋮----
type InboxNote = {
	id: number;
	status: string;
	title: string;
	name: string;
	content: string;
	date_created: string;
	date_created_gmt: string;
	actions: InboxNoteAction[];
	is_deleted: boolean;
... (20 lines truncated)
</file>

<file path="packages/js/experimental/src/inbox-note/index.ts">

</file>

<file path="packages/js/experimental/src/inbox-note/placeholder.tsx">
import { createElement } from '@wordpress/element';
⋮----
type PlaceholderProps = {
	className: string;
};
⋮----
const InboxNotePlaceholder = (
</file>

<file path="packages/js/experimental/src/inbox-note/use-callback-on-link-click.ts">
import { useCallback, useEffect, useRef } from '@wordpress/element';
⋮----
export function useCallbackOnLinkClick( onClick: ( link: string ) => void )
</file>

<file path="packages/js/experimental/src/vertical-css-transition/stories/vertical-css-transition.story.tsx">
import { createElement, Fragment, useState } from '@wordpress/element';
import { Meta, StoryFn } from '@storybook/react-webpack5';
⋮----
import {
	VerticalCSSTransition,
	VerticalCSSTransitionProps,
} from '../vertical-css-transition';
⋮----
const Parent = ( args: VerticalCSSTransitionProps ) =>
⋮----
<button onClick=
⋮----
const Template: StoryFn< VerticalCSSTransitionProps > = ( args ) => (
	<Parent { ...args } />
);
</file>

<file path="packages/js/experimental/src/vertical-css-transition/index.ts">

</file>

<file path="packages/js/experimental/src/vertical-css-transition/README.md">
# VerticalCSSTransition

This is a wrapper to the [React CSSTransition](https://reactcommunity.org/react-transition-group/css-transition) component, allowing for each vertical height transitions (collapsing/expanding). CSS does not support height: auto transitions, this uses JavaScript instead.

## Usage

```jsx
<VerticalCSSTransition timeout={ 500 } in={ true } classNames="my-node" defaultStyle={ transitionProperty: 'max-height, opacity' }>
	<div>some content</div>
	<div>
		some more content <br /> line 2 <br /> line 3
	</div>
</VerticalCSSTransition>
```

```css
.my-node-enter {
	opacity: 0;
}

.my-node-enter-active {
	opacity: 1;
}
```

### Props

Props extends the [CSSTransition props](https://reactcommunity.org/react-transition-group/css-transition#CSSTransition-props).
Name | Type | Default | Description
--- | --- | --- | ---
... (7 lines truncated)
</file>

<file path="packages/js/experimental/src/vertical-css-transition/vertical-css-transition.tsx">
import {
	createElement,
	useState,
	useCallback,
	useEffect,
	useRef,
} from '@wordpress/element';
import { CSSTransitionProps } from 'react-transition-group/CSSTransition';
import { CSSTransition, TransitionStatus } from 'react-transition-group';
⋮----
export type VerticalCSSTransitionProps<
	Ref extends HTMLElement | undefined = undefined,
> = CSSTransitionProps< Ref > & {
	defaultStyle?: React.CSSProperties;
	children: JSX.Element;
};
⋮----
function getContainerHeight( container: HTMLDivElement )
⋮----
export const VerticalCSSTransition = ( {
	children,
	defaultStyle,
	...props
}: VerticalCSSTransitionProps ) =>
⋮----
const getTimeouts = () =>
⋮----
const getTransitionStyle = ( state: TransitionStatus ) =>
</file>

<file path="packages/js/experimental/src/index.js">
export const useSlot = ( name ) =>
</file>

<file path="packages/js/experimental/src/text.ts">
import { __experimentalText } from '@wordpress/components';
</file>

<file path="packages/js/experimental/typings/global.d.ts">
interface Window {
		wcSettings: {
			adminUrl: string;
		};
	}
</file>

<file path="packages/js/experimental/typings/index.d.ts">

</file>

<file path="packages/js/experimental/typings/jest-dom.d.ts">

</file>

<file path="packages/js/experimental/.npmrc">
package-lock=false
</file>

<file path="packages/js/experimental/babel.config.js">

</file>

<file path="packages/js/experimental/build.mjs">

</file>

<file path="packages/js/experimental/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [4.0.0](https://www.npmjs.com/package/@woocommerce/experimental/v/4.0.0) - 2026-06-11 

-   Major - Update @wordpress/* dependencies to WordPress 6.8 minimum. [#64114]
-   Major - Updated declared dependencies to React 18 and WordPress 6.6. [#53531]
-   Minor - Adds an 'in progress' state to WooCommerce onboarding tasks, providing visual feedback when tasks are started but not completed. Initially implemented for the Payments setup task. [#59853]
-   Minor - Improve build time for experimental by using webpack filesystem cache. [#64082]
-   Minor - Monorepo: bump pnpm version to 9.15.0. [#54189]
-   Minor - Replace react-visibility-sensor with react-intersection-observer to fix deprecated findDOMNode Warning. [#55362]
-   Minor - Update storybook file format in support with Storybook 7 story indexer. [#51168]
-   Minor - Upgraded TypeScript in the monorepo to 5.7.2. [#53165]
-   Minor - Use @woocommerce/sanitize package to sanitize input. [#60324]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - CI: leverage composer packages cache in lint monorepo job. [#52054]
-   Patch - Clean up CI job config options; remove unused cascading keys. [#55863]
-   Patch - experimental package: fix TS errors. [#54160]
-   Patch - Fix pnpm version to 9.1.3 to avoid dependency installation issues. [#50828]
-   Patch - Fix task item type. [#54711]
-   Patch - Fixed stretched images in Inbox notes. [#58131]
-   Patch - Migrate from React RC types to direct React Props types with jscodeshift codemod. [#56594]
-   Patch - Monorepo: address circular dependencies surfaced by SWC TDZ. [#64797]
-   Patch - Monorepo: build RAM usage optimization. [#58861]
-   Patch - Monorepo: complete migration from `classnames` package to `clsx`. [#58699]
-   Patch - Monorepo: consolidate @babel/* dependencies versions across the monorepo. [#56575]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Monorepo: consolidate syncpack config around React 17/18 usage. [#52022]
-   Patch - Monorepo: consolidate TypeScript config files and JS test directories naming. [#52191]
... (68 lines truncated)
</file>

<file path="packages/js/experimental/composer.json">
{
	"name": "woocommerce/experimental",
	"description": "WooCommerce experimental components.",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/experimental/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/experimental/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/experimental/package.json">
{
	"name": "@woocommerce/experimental",
	"version": "4.0.0",
	"description": "WooCommerce experimental components.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"keywords": [
		"wordpress",
		"woocommerce",
		"experimental"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/experimental/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.js",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
... (129 lines truncated)
</file>

<file path="packages/js/experimental/PREVIOUS_CHANGELOG.md">
# 3.0.1

-   Update all js packages with minor/patch version changes. #8392

# 3.0.0

## Breaking changes

-   Update dependencies to support react 17. #8305
-   Drop support for IE11. #8305

# 2.2.0

-   Make the Inbox note title clickable. #7975
-   Fix incorrectly displayed note created date. #8179
-   Fix inbox note css #7983
-   Implement inbox note read state #7896

# 2.1.0

-   Renaming remindMeLater() to onSnooze() for consistency. #7616
-   Applied new Inbox 2.0 design to the inbox-note component. #7864

# 2.0.3

-   Adjust task-item css class to prevent css conflicts. #7593
-   Update task-item logic to only display content when expanded is true. #7611
-   Add expandable tasklist item. #7632

# 1.5.1
... (38 lines truncated)
</file>

<file path="packages/js/experimental/README.md">
# Experimental

This is a private package not meant for use by third parties.

A collection of component imports and exports that are aliases for components transitioning from experimental to non-experimental. This package prevents the component from being undefined when the `@wordpress/components` library version is unclear.

It also contains several in-development components that are slated for inclusion in later releases of `@woocommerce/components`.

## Installation

Install the module

```bash
pnpm install @woocommerce/experimental --save
```

## Usage

Simply import the component name with the `__experimental` prefix. If found, the non-experimental version will be imported and if not, this will fallback to the experimental version.

```jsx
import { Text } from '@woocommerce/experimental';

render() {
	return (
		<Text>
			…
		</Text>
	);
}
... (2 lines truncated)
</file>

<file path="packages/js/experimental/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"types": [
			"jest"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**",
		"**/stories/**"
	],
	"references": [
		{
			"path": "../components"
		},
		{
... (5 lines truncated)
</file>

<file path="packages/js/experimental/webpack.config.js">

</file>

<file path="packages/js/explat/changelog/.gitkeep">

</file>

<file path="packages/js/explat/changelog/dev-update-cookie-security">
Significance: patch
Type: dev

Update cookie and its type definitions to fix a security issue.
</file>

<file path="packages/js/explat/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/explat/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/explat/src/anon.ts">
import cookie from 'cookie';
⋮----
import { canTrack } from './assignment';
⋮----
export const readAnonCookie = (): string | null =>
⋮----
export const initializeAnonId = async (): Promise< string | null > =>
⋮----
const poll = () =>
⋮----
export const getAnonId = async (): Promise< string | null > =>
</file>

<file path="packages/js/explat/src/assignment.ts">
import { stringify } from 'qs';
import { applyFilters } from '@wordpress/hooks';
import apiFetch from '@wordpress/api-fetch';
⋮----
type QueryParams = {
	[ key: string ]: unknown;
} & {
	experiment_name: string;
	anon_id: string | null;
	woo_country_code: string;
	woo_wcadmin_install_timestamp: string;
};
⋮----
const isValidQueryParams = (
	queryParams: unknown
): queryParams is QueryParams =>
⋮----
const getRequestQueryParams = ( {
	experimentName,
	anonId,
}: {
	experimentName: string;
	anonId: string | null;
} ): QueryParams =>
⋮----
export const fetchExperimentAssignment = async ( {
	experimentName,
	anonId,
}: {
	experimentName: string;
... (11 lines truncated)
</file>

<file path="packages/js/explat/src/error.ts">
import { isDevelopmentMode } from './utils';
⋮----
export const logError = (
	error: Record< string, string > & { message: string }
): void =>
⋮----
const onLoggingError = ( e: unknown ) =>
</file>

<file path="packages/js/explat/src/index.ts">
import { createExPlatClient } from '@automattic/explat-client';
import createExPlatClientReactHelpers from '@automattic/explat-client-react-helpers';
⋮----
import { isDevelopmentMode } from './utils';
import { logError } from './error';
import {
	fetchExperimentAssignment,
	fetchExperimentAssignmentWithAuth,
	canTrack,
} from './assignment';
import { getAnonId, initializeAnonId } from './anon';
⋮----
interface Window {
		wcTracks: {
			isEnabled: boolean;
			enable?: ( cb: () => void ) => void;
		};
		_wca: {
			push?: ( cb: () => void ) => void;
		};
	}
⋮----
export const initializeExPlat = (): void =>
</file>

<file path="packages/js/explat/src/utils.ts">
interface generalSettings {
	woocommerce_default_country: string;
}
⋮----
interface preloadSettings {
	general: generalSettings;
}
⋮----
interface preloadOptions {
	woocommerce_admin_install_timestamp: string;
}
⋮----
interface admin {
	preloadSettings: preloadSettings;
	preloadOptions: preloadOptions;
}
⋮----
interface wcSettings {
	admin: admin;
	preloadSettings: preloadSettings;
}
⋮----
interface Window {
		wcSettings: wcSettings;
	}
</file>

<file path="packages/js/explat/.npmrc">
package-lock=false
</file>

<file path="packages/js/explat/babel.config.js">

</file>

<file path="packages/js/explat/build.mjs">

</file>

<file path="packages/js/explat/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.0.0](https://www.npmjs.com/package/@woocommerce/explat/v/3.0.0) - 2026-06-11 

-   Major - Update @wordpress/* dependencies to WordPress 6.8 minimum. [#64114]
-   Major - Updated declared dependencies to React 18 and WordPress 6.6. [#53531]
-   Minor - Bump jest package dependency to 29.5.x. [#60324]
-   Minor - Fix typos in inline documentation. [#48640]
-   Minor - Monorepo: bump pnpm version to 9.15.0. [#54189]
-   Minor - Upgraded TypeScript in the monorepo to 5.7.2. [#53165]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - CI: code style fixes to pass linting in updated CI environment. [#49020]
-   Patch - CI: leverage composer packages cache in lint monorepo job. [#52054]
-   Patch - Clean up CI job config options; remove unused cascading keys. [#55863]
-   Patch - Fix pnpm version to 9.1.3 to avoid dependency installation issues. [#50828]
-   Patch - Monorepo: build RAM usage optimization. [#59001]
-   Patch - Monorepo: consolidate @babel/* dependencies versions across the monorepo. [#56575]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Monorepo: consolidate syncpack config around React 17/18 usage. [#52022]
-   Patch - Monorepo: consolidate TypeScript config files and JS test directories naming. [#52191]
-   Patch - Monorepo: drop the unused `concurrently` package from dependencies. [#58765]
-   Patch - Monorepo: refresh wireit dependencyOutputs configuration synchronization when installing dependencies. [#55095]
-   Patch - Move the CommonJS build to prepack so day-to-day development only builds the ESM output. [#64876]
-   Patch - Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking. [#65168]
-   Patch - Replaced patched `@wordpress/data` types with opt-in internal package types. [#63483]
-   Patch - Replaced wireit + tsc package build pipeline with a per-package esbuild script. [#65210]
-   Patch - Update wireit to 0.14.10. [#54996]

... (42 lines truncated)
</file>

<file path="packages/js/explat/composer.json">
{
	"name": "woocommerce/explat",
	"description": "WooCommerce component and utils for A/B testing.",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/explat/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/explat/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/explat/package.json">
{
	"name": "@woocommerce/explat",
	"version": "3.0.0",
	"description": "WooCommerce component and utils for A/B testing.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"keywords": [
		"wordpress",
		"woocommerce",
		"abtest",
		"explat"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/explat/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
... (100 lines truncated)
</file>

<file path="packages/js/explat/PREVIOUS_CHANGELOG.md">
# 2.1.0

-   Add missing dependencies. #8349
-   Update all js packages with minor/patch version changes. #8392
-   Add `@wordpress/api-fetch` as dependencies. #8428
-   Export `*WithAuth` methods to authenticate WPCOM users. #8428

# 2.0.0

-   Make ExPlat request URL args filterable. Added woocommerce_explat_request_args filter #8231

## Breaking changes

-   Update dependencies to support react 17. #8305
-   Drop support for IE11. #8305

# 1.1.4

-   Fix an error when getting woocommerce_default_country value. #7600
-   Attempts to get the woocommerce_default_country value in wcSettings.preloadSettings.general first for the backward compatibility #7600

# 1.1.3

-   Retry fix for missing build-module folder

# 1.1.2

-   Fix missing build-module folder

# 1.1.1
... (16 lines truncated)
</file>

<file path="packages/js/explat/README.md">
# ExPlat

This packages includes a component and utility functions that can be used to run A/B Tests in WooCommerce dashboard, report pages, and frontend pages.

## Installation

Install the module

```bash
pnpm install @woocommerce/explat --save
```

This package assumes that your code will run in an ES2015+ environment. If you're using an environment that has limited or no support for ES2015+ such as lower versions of IE then using core-js or @babel/polyfill will add support for these methods. Learn more about it in Babel docs.

## Usage with Experiment Component

```js
import { Experiment } from '@woocommerce/explat';

const DefaultExperience = <div>Hello World</div>;

const TreatmentExperience = <div>Hello WooCommerce!</div>;

const LoadingExperience = <div>⏰</div>;

<Experiment
	name="woocommerce_example_experiment"
	defaultExperience={ DefaultExperience }
	treatmentExperience={ TreatmentExperience }
	loadingExperience={ LoadingExperience }
... (32 lines truncated)
</file>

<file path="packages/js/explat/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": []
}
</file>

<file path="packages/js/expression-evaluation/changelog/.gitkeep">

</file>

<file path="packages/js/expression-evaluation/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/expression-evaluation/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/expression-evaluation/src/index.ts">
import { parser } from './parser';
⋮----
export function evaluate( expression: string, context =
</file>

<file path="packages/js/expression-evaluation/src/parser.ts">

</file>

<file path="packages/js/expression-evaluation/.npmrc">
package-lock=false
</file>

<file path="packages/js/expression-evaluation/babel.config.js">

</file>

<file path="packages/js/expression-evaluation/build.mjs">

</file>

<file path="packages/js/expression-evaluation/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.0.0](https://www.npmjs.com/package/@woocommerce/expression-evaluation/v/2.0.0) - 2026-06-11 

-   Major - Update @wordpress/* dependencies to WordPress 6.8 minimum. [#64114]
-   Major - Updated declared dependencies to React 18 and WordPress 6.6. [#53531]
-   Minor - Bump node version. [#45148]
-   Minor - Bump jest package dependency to 29.5.x. [#60324]
-   Minor - Monorepo: bump pnpm version to 9.15.0. [#54189]
-   Minor - Upgraded TypeScript in the monorepo to 5.7.2. [#53165]
-   Patch - Bump php version in packages/js/*/composer.json. [#42020]
-   Patch - Fix comment typos across various files. [#50047]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - CI: leverage composer packages cache in lint monorepo job. [#52054]
-   Patch - Fix pnpm version to 9.1.3 to avoid dependency installation issues. [#50828]
-   Patch - Monorepo: build RAM usage optimization. [#59001]
-   Patch - Monorepo: consolidate @babel/* dependencies versions across the monorepo. [#56575]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Monorepo: consolidate syncpack config around React 17/18 usage. [#52022]
-   Patch - Monorepo: consolidate TypeScript config files and JS test directories naming. [#52191]
-   Patch - Monorepo: drop the unused `concurrently` package from dependencies. [#58765]
-   Patch - Monorepo: refresh wireit dependencyOutputs configuration synchronization when installing dependencies. [#55095]
-   Patch - Move the CommonJS build to prepack so day-to-day development only builds the ESM output. [#64876]
-   Patch - Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking. [#65168]
-   Patch - Replaced patched `@wordpress/data` types with opt-in internal package types. [#63483]
-   Patch - Replaced wireit + tsc package build pipeline with a per-package esbuild script. [#65210]
-   Patch - Update pnpm to 9.1.0. [#47385]
-   Patch - Update wireit to 0.14.10. [#54996]
... (8 lines truncated)
</file>

<file path="packages/js/expression-evaluation/composer.json">
{
	"name": "woocommerce/expression-evaluation",
	"description": "WooCommerce expression evaluation library",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/expression-evaluation/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/expression-evaluation/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/expression-evaluation/package.json">
{
	"name": "@woocommerce/expression-evaluation",
	"version": "2.0.0",
	"description": "Library for evaluating expressions.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"keywords": [
		"wordpress",
		"woocommerce",
		"expression",
		"evaluation"
	],
	"engines": {
		"node": "^24.15.0"
	},
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/expression-evaluation/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
... (75 lines truncated)
</file>

<file path="packages/js/expression-evaluation/README.md">
# @woocommerce/expression-evaluation

Evaluation of JavaScript-like expressions in an optional context.

Examples of simple expressions:

```js
1 + 2
```

```js
foo === 'bar'
```

```js
foo ? 'bar' : 'baz'
```

Examples of complex expressions:

```js
foo.bar.baz === 'qux'
```

```js
foo.bar
  && ( foo.bar.baz === 'qux' || foo.baz === 'quux' )
```

```js
... (285 lines truncated)
</file>

<file path="packages/js/expression-evaluation/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": []
}
</file>

<file path="packages/js/extend-cart-checkout-block/changelog/.gitkeep">

</file>

<file path="packages/js/extend-cart-checkout-block/changelog/64838-dev-esbuild-package-builds">
Significance: patch
Type: dev

Removed stray wireit devDependency.
</file>

<file path="packages/js/extend-cart-checkout-block/changelog/66078-update-scaffold-flat-config">
Significance: minor
Type: update

Scaffold ESLint Flat Config (`eslint.config.mjs`) instead of `.eslintrc.js`, which recent ESLint versions no longer read.
</file>

<file path="packages/js/extend-cart-checkout-block/changelog/dev-gitignore-glob-parsing">
Significance: patch
Type: dev

Remove a stray placeholder line from the literal .gitignore (the real template lives in .gitignore.mustache) so glob-based ignore parsers no longer fail on it.
</file>

<file path="packages/js/extend-cart-checkout-block/changelog/update-php-dev-dependency-security-patches">
Significance: patch
Type: dev

Update PHP development dependencies to versions that resolve reported security advisories.
</file>

<file path="packages/js/extend-cart-checkout-block/src/css/_colors.scss.mustache">
@use "node_modules/@wordpress/base-styles/colors";

// Bright colors
$example_color: #999999;
</file>

<file path="packages/js/extend-cart-checkout-block/src/js/checkout-newsletter-subscription-block/block.js.mustache">
/**
 * External dependencies
 */
import { useEffect, useState } from '@wordpress/element';
import { CheckboxControl } from '@woocommerce/blocks-checkout';
import { getSetting } from '@woocommerce/settings';
import { useSelect, useDispatch } from '@wordpress/data';

const { optInDefaultText } = getSetting( '{{slug}}_data', '' );

const Block = ( { children, checkoutExtensionData } ) => {
	const [ checked, setChecked ] = useState( false );
	const { setExtensionData } = checkoutExtensionData;

	const { setValidationErrors, clearValidationError } = useDispatch(
		'wc/store/validation'
	);

	useEffect( () => {
		setExtensionData( '{{slug}}', 'optin', checked );
		if ( ! checked ) {
			setValidationErrors( {
				'{{slug}}': {
					message: 'Please tick the box',
					hidden: false,
				},
			} );
			return;
		}
		clearValidationError( '{{slug}}' );
... (38 lines truncated)
</file>

<file path="packages/js/extend-cart-checkout-block/src/js/checkout-newsletter-subscription-block/block.json.mustache">
{
	"apiVersion": 3,
	"name": "{{slug}}/checkout-newsletter-subscription",
	"version": "2.0.0",
	"title": "Newsletter Subscription!",
	"category": "woocommerce",
	"description": "Adds a newsletter subscription checkbox to the checkout.",
	"supports": {
		"html": false,
		"align": false,
		"multiple": false,
		"reusable": false
	},
	"parent": [
		"woocommerce/checkout-contact-information-block"
	],
	"attributes": {
		"lock": {
			"type": "object",
			"default": {
				"remove": true,
				"move": true
			}
		},
		"text": {
			"type": "string",
			"source": "html",
			"selector": ".wp-block-{{slug}}-checkout-newsletter-subscription",
			"default": ""
		}
... (5 lines truncated)
</file>

<file path="packages/js/extend-cart-checkout-block/src/js/checkout-newsletter-subscription-block/edit.js.mustache">
/**
 * External dependencies
 */
import { __ } from '@wordpress/i18n';
import {
	useBlockProps,
	RichText,
	InspectorControls,
} from '@wordpress/block-editor';
import { PanelBody } from '@wordpress/components';
import { CheckboxControl } from '@woocommerce/blocks-checkout';
import { getSetting } from '@woocommerce/settings';
/**
 * Internal dependencies
 */
import './style.scss';
const { optInDefaultText } = getSetting( '{{slug}}_data', '' );

export const Edit = ( { attributes, setAttributes } ) => {
	const { text } = attributes;
	const blockProps = useBlockProps();
	return (
		<div { ...blockProps }>
			<InspectorControls>
				<PanelBody title={ __( 'Block options', '{{slug}}' ) }>
					Options for the block go here.
				</PanelBody>
			</InspectorControls>
			<CheckboxControl
				id="newsletter-text"
... (20 lines truncated)
</file>

<file path="packages/js/extend-cart-checkout-block/src/js/checkout-newsletter-subscription-block/frontend.js.mustache">
/**
 * External dependencies
 */
import { registerCheckoutBlock } from '@woocommerce/blocks-checkout';
/**
 * Internal dependencies
 */
import Block from './block';
import metadata from './block.json';

registerCheckoutBlock( {
	metadata,
	component: Block,
} );
</file>

<file path="packages/js/extend-cart-checkout-block/src/js/checkout-newsletter-subscription-block/index.js.mustache">
/**
 * External dependencies
 */
import { SVG } from '@wordpress/components';
import { registerBlockType } from '@wordpress/blocks';

/**
 * Internal dependencies
 */
import { Edit, Save } from './edit';
import metadata from './block.json';
registerBlockType( metadata, {
	icon: {
		src: (
			<SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 16">
				<g fill="none" fillRule="evenodd">
					<path
						stroke="currentColor"
						strokeWidth="1.5"
						d="M2 .75h16c.69 0 1.25.56 1.25 1.25v12c0 .69-.56 1.25-1.25 1.25H2c-.69 0-1.25-.56-1.25-1.25V2C.75 1.31 1.31.75 2 .75z"
					/>
					<path
						fill="currentColor"
						d="M7.667 7.667A2.34 2.34 0 0010 5.333 2.34 2.34 0 007.667 3a2.34 2.34 0 00-2.334 2.333 2.34 2.34 0 002.334 2.334zM11.556 3H17v3.889h-5.444V3zm2.722 2.916l1.944-1.36v-.779L14.278 5.14l-1.945-1.362v.778l1.945 1.361zm-5.834-.583a.78.78 0 00-.777-.777.78.78 0 00-.778.777c0 .428.35.778.778.778a.78.78 0 00.777-.778zm3.89 5.904c0-1.945-3.088-2.785-4.667-2.785-1.58 0-4.667.84-4.667 2.785v1.097h9.333v-1.097zM7.666 10c-1.012 0-2.163.389-2.738.778h5.475C9.821 10.38 8.678 10 7.667 10z"
					/>
				</g>
			</SVG>
		),
		foreground: '#874FB9',
	},
... (4 lines truncated)
</file>

<file path="packages/js/extend-cart-checkout-block/src/js/checkout-newsletter-subscription-block/style.scss.mustache">
.wp-block-{{slug}}-checkout-newsletter-subscription {
	margin: 20px 0;
	padding-top: 4px;
	padding-bottom: 4px;
	display: flex;
	align-items: flex-start;

	.block-editor-rich-text__editable {
		vertical-align: middle;
		line-height: 24px;
	}

	.wc-block-components-checkbox {
		margin-right: 16px;
		margin-top: 0;
	}
}

.editor-styles-wrapper {

	.wp-block-{{slug}}-checkout-newsletter-subscription {
		.wc-block-components-checkbox {
			margin-right: 0;
			margin-top: 0;
		}
	}
}
</file>

<file path="packages/js/extend-cart-checkout-block/src/js/ExampleComponent.js.mustache">
/*
 * An example component that will be rendered at the bottom of the sidebar in
 * the Cart and Checkout blocks.
 */
export const ExampleComponent = ( { data } ) => {
	return (
		<div className="{{slug}}-example-component">
			Data passed to this component: { data['example-data'] }
		</div>
	);
};
</file>

<file path="packages/js/extend-cart-checkout-block/src/js/filters.js.mustache">
/**
 * External dependencies
 */
import { __experimentalRegisterCheckoutFilters } from '@woocommerce/blocks-checkout';
import { registerPaymentMethodExtensionCallbacks } from '@woocommerce/blocks-registry';

export const registerFilters = () => {
    __experimentalRegisterCheckoutFilters( '{{slug}}', {
        itemName: ( name ) => {
            return `${name} + extra data!`
        },
    } );

    registerPaymentMethodExtensionCallbacks( '{{slug}}',
        {
            cod: ( arg ) => arg.billingData.city !== 'Denver',
        }
    );
};
</file>

<file path="packages/js/extend-cart-checkout-block/src/js/index.js.mustache">
/**
 * External dependencies
 */
import { registerPlugin } from '@wordpress/plugins';
import { ExperimentalOrderMeta } from '@woocommerce/blocks-checkout';
import { getSetting } from '@woocommerce/settings';
/**
 * Internal dependencies
 */
import './style.scss';

import { registerFilters } from './filters';
import { ExampleComponent } from './ExampleComponent';

const exampleDataFromSettings = getSetting( '{{slug}}_data' );

const render = () => {
	return (
		<>
			<ExperimentalOrderMeta>
				<ExampleComponent data={ exampleDataFromSettings } />
			</ExperimentalOrderMeta>
		</>
	);
};

registerPlugin( '{{slug}}', {
	render,
	scope: 'woocommerce-checkout',
} );
... (3 lines truncated)
</file>

<file path="packages/js/extend-cart-checkout-block/src/js/style.scss.mustache">
.{{slug}}-example-component {
 font-size: 20px;
 color: $example_color;
}
</file>

<file path="packages/js/extend-cart-checkout-block/src/index.js.mustache">
/**
 * Internal dependencies
 */
 import './js/index';
import './js/checkout-newsletter-subscription-block';
</file>

<file path="packages/js/extend-cart-checkout-block/.editorconfig.mustache">
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/

root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 4
tab_width = 4
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true

[*.txt]
trim_trailing_whitespace = false

[*.{md,json,yml}]
trim_trailing_whitespace = false
indent_style = space
indent_size = 2

[*.json]
indent_style = tab
</file>

<file path="packages/js/extend-cart-checkout-block/.gitignore.mustache">
/nbproject/private/
node_modules
project.xml
project.properties
.DS_Store
Thumbs.db
.buildpath
.project
.settings*
.vscode
sftp-config.json
/deploy/
/wc-apidocs/
/languages/
screenshots/
.idea

# Ignore all log files except for .htaccess
/logs/*
!/logs/.htaccess

tests/e2e/config/local-*
.eslintcache

/vendor/

dist
build

{{slug}}.zip
... (1 lines truncated)
</file>

<file path="packages/js/extend-cart-checkout-block/.nvmrc.mustache">
20
</file>

<file path="packages/js/extend-cart-checkout-block/.wp-env.json.mustache">
{
	"phpVersion": null,
	"core": null,
	"plugins": [
		"https://downloads.wordpress.org/plugin/woocommerce.latest-stable.zip",
		"https://downloads.wordpress.org/plugin/woo-gutenberg-products-block.latest-stable.zip",
		"."
	],
	"config": {
		"JETPACK_AUTOLOAD_DEV": true,
		"WP_DEBUG": true,
		"SCRIPT_DEBUG": true
	}
}
</file>

<file path="packages/js/extend-cart-checkout-block/$slug-blocks-integration.php.mustache">
<?php
use Automattic\WooCommerce\Blocks\Integrations\IntegrationInterface;

define ( '{{slugPascalCase}}_VERSION', '0.1.0' );

/**
 * Class for integrating with WooCommerce Blocks
 */
class {{slugPascalCase}}_Blocks_Integration implements IntegrationInterface {

	/**
	 * The name of the integration.
	 *
	 * @return string
	 */
	public function get_name() {
		return '{{slug}}';
	}

	/**
	 * When called invokes any initialization/setup for the integration.
	 */
	public function initialize() {
		$this->register_newsletter_block_frontend_scripts();
		$this->register_newsletter_block_editor_scripts();
        $this->register_newsletter_block_editor_styles();
        $this->register_main_integration();
	}

	/**
... (149 lines truncated)
</file>

<file path="packages/js/extend-cart-checkout-block/$slug.php.mustache">
<?php
/**
 * Plugin Name:     {{title}}
{{#description}}
 * Description:     {{description}}
{{/description}}
 * Version:         {{version}}
{{#author}}
 * Author:          {{author}}
{{/author}}
{{#license}}
 * License:         {{license}}
{{/license}}
{{#licenseURI}}
 * License URI:     {{{licenseURI}}}
{{/licenseURI}}
 * Text Domain:     {{textdomain}}
 *
 * @package         {{namespace}}
 */

add_action(
	'init',
	function () {
		register_block_type_from_metadata( __DIR__ . '/build/js/checkout-newsletter-subscription-block' );
	}
);

add_action(
	'woocommerce_blocks_loaded',
... (116 lines truncated)
</file>

<file path="packages/js/extend-cart-checkout-block/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.5.1](https://www.npmjs.com/package/@woocommerce/extend-cart-checkout-block/v/1.5.1) - 2026-01-26 

-   Patch - Ensure correct files are included when building a zip using build-zip [#62910]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Update wireit to 0.14.10 [#54996]

## [1.5.0](https://www.npmjs.com/package/@woocommerce/extend-cart-checkout-block/v/1.5.0) - 2025-01-21 

-   Patch - Fix some linting issues, update .nvmrc and .eslintrc [#54414]
-   Minor - Monorepo: bump pnpm version to 9.15.0 [#54189]

## [1.4.0](https://www.npmjs.com/package/@woocommerce/extend-cart-checkout-block/v/1.4.0) - 2025-01-08 

-   Patch - Fix SASS errors when installing the template. [#54165]
-   Patch - Prevent doing_it_wrong warnings while registering the example block. [#52195]
-   Patch - CI: liverage composer packages cache in lint monorepo job [#52054]
-   Patch - Fix pnpm version to 9.1.3 to avoid dependency installation issues. [#50828]
-   Minor - Update all blocks to use API Version 3. [#48720]

## [1.3.1](https://www.npmjs.com/package/@woocommerce/extend-cart-checkout-block/v/1.3.1) - 2024-07-10 

-   Patch - Ensures the default text shows when saving the example newsletter subscription block. [#48581]

## [1.3.0](https://www.npmjs.com/package/@woocommerce/extend-cart-checkout-block/v/1.3.0) - 2024-06-14 

... (29 lines truncated)
</file>

<file path="packages/js/extend-cart-checkout-block/composer.json">
{
	"name": "woocommerce/extend-cart-checkout-block",
	"description": "A template for extending the Cart and Checkout blocks to be used with @wordpress/create-block",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"prefer-stable": true,
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
... (4 lines truncated)
</file>

<file path="packages/js/extend-cart-checkout-block/eslint.config.mjs.mustache">
import woocommerce from '@woocommerce/eslint-plugin';

export default [
	{ ignores: [ 'build/**' ] },
	...woocommerce.configs.recommended,
	{
		rules: {
			'react/react-in-jsx-scope': 'off',
			'import/no-unresolved': 'off',
			'import/no-extraneous-dependencies': 'off',
			'import/named': 'off',
			'import/default': 'off',
			'@wordpress/i18n-text-domain': [
				'error',
				{
					allowedTextDomain: [ '{{slug}}' ],
				},
			],
		},
	},
];
</file>

<file path="packages/js/extend-cart-checkout-block/index.js">

</file>

<file path="packages/js/extend-cart-checkout-block/package.json">
{
	"name": "@woocommerce/extend-cart-checkout-block",
	"version": "1.5.1",
	"description": "",
	"main": "index.js",
	"engines": {
		"node": "^24.15.0"
	},
	"repository": {
		"type": "git",
		"url": "git+https://github.com/woocommerce/woocommerce.git"
	},
	"keywords": [],
	"author": "",
	"license": "GPL-2.0-or-later",
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"scripts": {
		"changelog": "XDEBUG_MODE=off composer install --quiet && composer exec -- changelogger"
	},
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/extend-cart-checkout-block#readme"
}
</file>

<file path="packages/js/extend-cart-checkout-block/README.md">
# @woocommerce/extend-cart-checkout-block

This is a template to be used with `@wordpress/create-block` to create a WooCommerce Blocks extension starting point.

## Installation

You may need to install a node version manager, for example [`nvm`](https://github.com/nvm-sh/nvm) or [`fnm`](https://github.com/Schniz/fnm)

Before getting started, switch to Node v20.

e.g. `nvm install 20 && nvm use 20` or `fnm install 20 && fnm use 20`

From your `plugins` directory run:

```sh
npx @wordpress/create-block -t @woocommerce/extend-cart-checkout-block your_extension_name
```

When this has completed, go to your WordPress plugins page and activate the plugin.

Add some items to your cart and visit the Checkout block, notice there is additional data on the block that this template has added.

### Linting

You can lint the project according to the [WordPress coding standards](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/javascript/) by running `npm run lint:js`. The configuration is ultimately read from the [WooCommerce recommended eslint config](https://github.com/woocommerce/woocommerce/blob/trunk/packages/js/eslint-plugin/configs/recommended.js). To modify the rules edit the `eslint.config.mjs` file.

### Installing `wp-env` (optional)

`wp-env` lets you easily set up a local WordPress environment for building and testing your extension. If you want to use `wp-env`, you will need to run the following command:

... (4 lines truncated)
</file>

<file path="packages/js/extend-cart-checkout-block/README.md.mustache">
# {{name}}

A WooCommerce Blocks Extension

## Development

To get started, run the following commands:

```text
npm install
npm start
```

See [wp-scripts](https://github.com/WordPress/gutenberg/tree/master/packages/scripts) for more usage information.
</file>

<file path="packages/js/extend-cart-checkout-block/webpack.config.js.mustache">
const path = require( 'path' );
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
const WooCommerceDependencyExtractionWebpackPlugin = require( '@woocommerce/dependency-extraction-webpack-plugin' );
const MiniCssExtractPlugin = require( 'mini-css-extract-plugin' );

// Remove SASS rule from the default config so we can define our own.
const defaultRules = defaultConfig.module.rules.filter( ( rule ) => {
	return String( rule.test ) !== String( /\.(sc|sa)ss$/ );
} );

module.exports = {
	...defaultConfig,
	entry: {
		index: path.resolve(process.cwd(), 'src', 'js', 'index.js'),
		'{{slug}}-checkout-newsletter-subscription-block': path.resolve(
			process.cwd(),
			'src',
			'js',
			'checkout-newsletter-subscription-block',
			'index.js'
		),
		'{{slug}}-checkout-newsletter-subscription-block-frontend': path.resolve(
			process.cwd(),
			'src',
			'js',
			'checkout-newsletter-subscription-block',
			'frontend.js'
		),
	},
	module: {
... (55 lines truncated)
</file>

<file path="packages/js/internal-build/scripts/generate-types.mjs">
/**
 * Auto-generate ambient type declarations from node_modules.
 *
 * Transforms .d.ts files from real packages into script-mode
 * `declare module` blocks that ensure portable declaration emission
 * (no TS2742 errors from pnpm virtual store paths).
 *
 * Usage:
 *   node scripts/generate-types.mjs generate [--output=<dir>]
 *   node scripts/generate-types.mjs update-patch
 */
⋮----
/* eslint-disable no-console */
⋮----
// ---------------------------------------------------------------------------
// Configuration
// ---------------------------------------------------------------------------
⋮----
// Packages to generate ambient type declarations for.
// DT vs build-types is auto-detected from devDependencies in package.json:
// if @types/wordpress__<slug> exists → DT package (typesDir '.'),
// otherwise → the package's own build-types directory.
⋮----
function dtPackageName( packageName )
⋮----
function resolvePackageConfigs()
⋮----
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
... (169 lines truncated)
</file>

<file path="packages/js/internal-build/src/composer/index.ts">
import { spawn } from 'node:child_process';
import { createHash } from 'node:crypto';
import { existsSync } from 'node:fs';
import { copyFile, mkdir, readFile, rm } from 'node:fs/promises';
import path from 'node:path';
import chokidar from 'chokidar';
⋮----
import { log } from '../utils/logger.js';
⋮----
export interface ComposerPackageWatcherOptions {
	composerJson: string;
	ignoredPackages?: string[];
}
⋮----
interface ComposerAutoload {
	'psr-4'?: Record< string, string | string[] >;
	'psr-0'?: Record< string, string | string[] >;
	classmap?: string[];
	files?: string[];
}
⋮----
interface ComposerJson {
	name?: string;
	require?: Record< string, string >;
	'require-dev'?: Record< string, string >;
	repositories?: Array< {
		type: string;
		url?: string;
		options?: { symlink?: boolean };
	} >;
... (66 lines truncated)
</file>

<file path="packages/js/internal-build/src/esbuild/args.ts">
export interface ParsedArgs {
	watch: boolean;
	format: 'esmodules' | 'commonjs';
	debug: boolean;
}
⋮----
export function parseBuildArgs(
	argv: readonly string[] = process.argv
): ParsedArgs
</file>

<file path="packages/js/internal-build/src/esbuild/assets.ts">
import { copyFile, mkdir } from 'node:fs/promises';
import { dirname, join, relative } from 'node:path';
import { glob } from 'glob';
⋮----
export async function copyAssets(
	patterns: readonly string[],
	outdir: string
): Promise< void >
</file>

<file path="packages/js/internal-build/src/esbuild/index.ts">
import { build, context } from 'esbuild';
import type { BuildResult } from 'esbuild';
import { glob } from 'glob';
import { rm } from 'node:fs/promises';
import chokidar from 'chokidar';
⋮----
import { parseBuildArgs } from './args.js';
import {
	DEFAULT_IGNORE,
	prepareEsbuildOptions,
	type BuildOptions,
} from './options.js';
import { copyAssets } from './assets.js';
import { log, setDebugEnabled } from '../utils/logger.js';
⋮----
async function resolveEntryPoints(
	entryPoints: string | string[],
	ignore: readonly string[]
): Promise< string[] >
⋮----
function summarize( result: BuildResult ): string
⋮----
function errorMessage( error: unknown ): string
⋮----
export async function buildPackage( options: BuildOptions ): Promise< void >
⋮----
export async function watchPackage( options: BuildOptions ): Promise< void >
⋮----
const restart = ( path: string, kind: string ): void =>
⋮----
... (6 lines truncated)
</file>

<file path="packages/js/internal-build/src/esbuild/options.ts">
import type { BuildOptions as EsbuildOptions } from 'esbuild';
⋮----
export interface BuildOptions {
	entryPoints: string | string[];
	ignore?: string[];
	format?: 'esmodules' | 'commonjs';
	assets?: string[];
	esbuild?: EsbuildOptions;
}
⋮----
export function prepareEsbuildOptions(
	format: 'esmodules' | 'commonjs',
	entryPoints: string[],
	overrides: EsbuildOptions = {}
): EsbuildOptions
</file>

<file path="packages/js/internal-build/src/style-build/index.cjs">
/**
 * External dependencies
 */
⋮----
additionalData: ( content, loaderContext ) =>
⋮----
/*
									 * Skip adding additional data for @automattic/* packages to
									 * fix "SassError: @use rules must be written before any other rules."
									 * @automattic/* packages have included '@use "sass:math" and other necessary imports.
									 */
</file>

<file path="packages/js/internal-build/src/style-build/style-asset-plugin.cjs">
/**
 * Add an asset file for each entry point that contains the current version calculated for the current source code.
 *
 * This is modified from WP dependency-extraction-webpack-plugin plugin:
 * https://github.com/WordPress/gutenberg/tree/a04a8e94e8b93ba60441c6534e21f4c3c26ff1bc/packages/dependency-extraction-webpack-plugin
 *
 * We can contribute this back to the original plugin in the future and remove this file.
 */
⋮----
/**
 * External dependencies
 */
⋮----
class AssetDataPlugin
⋮----
/**
	 * @param {any} asset Asset Data
	 * @return {string} Stringified asset data suitable for output
	 */
stringify( asset )
⋮----
apply( compiler )
⋮----
/** @param {webpack.Compilation} compilation */
addAssets( compilation, createHash, RawSource )
⋮----
// Accumulate all entrypoint chunks, some of them shared
⋮----
// Process each entrypoint chunk independently
⋮----
... (13 lines truncated)
</file>

<file path="packages/js/internal-build/src/style-build/webpack-rtl-plugin.cjs">
/*
Adapted from @automattic/webpack-rtl-plugin, that was originally adapted and released by Romain Berger under the MIT License (MIT):

MIT License

Copyright (c) 2016 Romain Berger

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
⋮----
class WebpackRTLPlugin
⋮----
apply( compiler )
⋮----
// Collect all files form all chunks, and generate an array of {chunk, file} objects
⋮----
/*
								 * In-place mode rewrites the original stylesheet to
								 * RTL rather than emitting a separate `-rtl.css`
								 * sibling, so an existing (LTR) `<link>` renders RTL.
								 * Storybook uses this for its RTL preview, where the
								 * content-hashed chunk filenames can't be predicted
								 * to swap a link. Skips the sibling/caching path.
								 */
⋮----
// Compute the filename
... (3 lines truncated)
</file>

<file path="packages/js/internal-build/src/utils/logger.ts">
export type LoggerPrefix = keyof typeof PREFIXES;
⋮----
export function setDebugEnabled( enabled: boolean ): void
⋮----
function format( prefix: LoggerPrefix, message: string ): string
⋮----
info( prefix: LoggerPrefix, message: string ): void
debug( context: string, message: string ): void
warn( prefix: LoggerPrefix, message: string ): void
error( prefix: LoggerPrefix, message: string ): void
dim( message: string ): string
</file>

<file path="packages/js/internal-build/src/index.ts">

</file>

<file path="packages/js/internal-build/src/tsconfig.json">
{
	"compilerOptions": {
		"target": "es2022",
		"module": "esnext",
		"moduleResolution": "bundler",
		"lib": [ "es2022" ],
		"strict": true,
		"esModuleInterop": true,
		"skipLibCheck": true,
		"isolatedModules": true,
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "../build-types",
		"outDir": "../build-module",
		"rootDir": ".",
		"resolveJsonModule": true
	},
	"include": [ "**/*.ts" ],
	"exclude": [ "style-build/**" ]
}
</file>

<file path="packages/js/internal-build/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/internal-build/package.json">
{
	"name": "@woocommerce/internal-build",
	"version": "1.0.0",
	"description": "Shared build tooling for the WooCommerce monorepo: esbuild helpers, webpack/SCSS config, shared tsconfig, and WordPress ambient type overrides.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"private": true,
	"type": "module",
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/internal-build/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"module": "build-module/index.js",
	"types": "build-types/index.d.ts",
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js"
		},
		"./style-build": {
			"require": "./src/style-build/index.cjs"
		},
... (61 lines truncated)
</file>

<file path="packages/js/internal-js-tests/changelog/42860-update-pnpm">
Significance: patch
Type: dev
Comment: Updated PNPM
</file>

<file path="packages/js/internal-js-tests/changelog/43532-add-cli-to-ci-workflow">
Significance: patch
Type: dev
Comment: This is a CI-only change.
</file>

<file path="packages/js/internal-js-tests/changelog/43595-update-wireit-0.14.3">
Significance: patch
Type: dev
Comment: This is a developer-only build tooling related change.
</file>

<file path="packages/js/internal-js-tests/changelog/45148-poc-request-reviews">
Significance: minor
Type: update

Bump node version.
</file>

<file path="packages/js/internal-js-tests/changelog/46278-fix-43889-43901-43944">
Significance: patch
Type: dev
Comment: adds `glob`, `rimraf`, and `uuid` to Syncpack
</file>

<file path="packages/js/internal-js-tests/changelog/47156-dev-fix-build-error-build-style">
Significance: patch
Type: dev
Comment: Fix a persistent build bug where TS would try compile files outside of src and typings directories.
</file>

<file path="packages/js/internal-js-tests/changelog/47385-dev-update-pnpm9-1">
Significance: patch
Type: dev

Update pnpm to 9.1.0
</file>

<file path="packages/js/internal-js-tests/changelog/50828-dev-constrain-pnpm-version">
Significance: patch
Type: dev

Fix pnpm version to 9.1.3 to avoid dependency installation issues.
</file>

<file path="packages/js/internal-js-tests/changelog/52815-dev-lock-dependencies">
Significance: patch
Type: dev

Stabilize JS dependency updates
</file>

<file path="packages/js/internal-js-tests/changelog/53165-dev-ts-5-7-2">
Significance: minor
Type: dev

Upgraded Typescript in the monorepo to 5.7.2
</file>

<file path="packages/js/internal-js-tests/changelog/53531-dev-react-18-ghidorah">
Significance: major
Type: dev

Updated declared dependencies to React 18 and Wordpress 6.6
</file>

<file path="packages/js/internal-js-tests/changelog/53865-dev-pnpm-9-15-0">
Significance: minor
Type: dev

Monorepo: bump pnpm version to 9.15.0
</file>

<file path="packages/js/internal-js-tests/changelog/54996-chore-update-wireit">
Significance: patch
Type: dev

Update wireit to 0.14.10
</file>

<file path="packages/js/internal-js-tests/changelog/55095-dev-rewrite-wireit-deps-update">
Significance: patch
Type: dev

Monorepo: refresh wireit dependencyOutputs configuration synchronization when installing dependencies.
</file>

<file path="packages/js/internal-js-tests/changelog/56246-update-settings-router-calypso-package">
Significance: patch
Type: update

Update new Settings to use @automattic/site-admin's router instead of Gutenberg
</file>

<file path="packages/js/internal-js-tests/changelog/56575-dev-bump-babel-deps">
Significance: patch
Type: dev

Monorepo: consolidate @babel/* dependencies versions across the monorepo.
</file>

<file path="packages/js/internal-js-tests/changelog/57299-fix-wireit-in-ci">
Significance: patch
Type: dev

Bump wireit dependency version to latest.
</file>

<file path="packages/js/internal-js-tests/changelog/58941-dev-consolidate-packages-license-version">
Significance: patch
Type: dev

Monorepo: consolidate packages licenses to `GPL-2.0-or-later`.
</file>

<file path="packages/js/internal-js-tests/changelog/59001-dev-build-ram-usage-batch-3">
Significance: patch
Type: dev

Monorepo: build RAM usage optimization.
</file>

<file path="packages/js/internal-js-tests/changelog/63483-add-62921-shared-monorepo-ts-config">
Significance: patch
Type: dev

Replaced patched `@wordpress/data` types with opt-in internal package types.
</file>

<file path="packages/js/internal-js-tests/changelog/64111-dev-fix-admin-webpack-cache-misses">
Significance: patch
Type: dev

Monorepo: refresh DependencyExtractionWebpackPlugin for compatibility with filesystem cache, admin build cleanup.
</file>

<file path="packages/js/internal-js-tests/changelog/64838-dev-esbuild-package-builds">
Significance: patch
Type: dev

Replaced wireit + tsc package build pipeline with a per-package esbuild script.
</file>

<file path="packages/js/internal-js-tests/changelog/65662-dev-65627-postrelease-cleanup">
Significance: major
Type: dev

Update @wordpress/data peer dependency to ^10.19.0 to align with WordPress 6.8 minimum.
</file>

<file path="packages/js/internal-js-tests/changelog/66078-dehoist-react">
Significance: patch
Type: dev
Comment: Declare react/react-dom as devDependencies alongside the existing peerDependencies. Tooling only; no runtime change.
</file>

<file path="packages/js/internal-js-tests/changelog/add-bump-stats-error">
Significance: patch
Type: add

Add bumpStat to woocommerce-tracks mock
</file>

<file path="packages/js/internal-js-tests/changelog/add-settings-option-store">
Significance: patch
Type: dev

Improve wpModulesMapper to exclude mappings for paths with suffixes
</file>

<file path="packages/js/internal-js-tests/changelog/add-tracks-unit-tests-improvements-product-editor">
Significance: patch
Type: dev

Add tests for some product editor tracks
</file>

<file path="packages/js/internal-js-tests/changelog/dev-64837-type-check-only-on-lint">
Significance: patch
Type: dev

Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking.
</file>

<file path="packages/js/internal-js-tests/changelog/dev-babel-loader-jest-caching">
Significance: patch
Type: dev

Monorepo: enable Jest caching.
</file>

<file path="packages/js/internal-js-tests/changelog/dev-build-profiling-tweaks-take-1">
Significance: patch
Type: dev

Monorepo: consolidate TypeScript config files and JS test directories naming.
</file>

<file path="packages/js/internal-js-tests/changelog/dev-ci-lint-monorepo-job-update">
Significance: patch
Type: dev

CI: liverage composer packages cache in lint monorepo job
</file>

<file path="packages/js/internal-js-tests/changelog/dev-cjs-prepack-only">
Significance: patch
Type: dev

Move the CommonJS build to prepack and route @woocommerce/* Jest imports through package sources so tests don't depend on built artifacts.
</file>

<file path="packages/js/internal-js-tests/changelog/dev-consolidate-syncpack-config">
Significance: patch
Type: dev

Monorepo: consolidate syncpack config around React 17/18 usage.
</file>

<file path="packages/js/internal-js-tests/changelog/dev-merge-admin">
Significance: patch
Type: dev

update path to admin package
</file>

<file path="packages/js/internal-js-tests/changelog/dev-monorepo-caching-deps-per-target-package">
Significance: patch
Type: dev

CI: code style fixes to pass linting in updated CI environment.
</file>

<file path="packages/js/internal-js-tests/changelog/fix-domain-substitution">
Significance: patch
Type: fix

Add composer.json for live build
</file>

<file path="packages/js/internal-js-tests/changelog/fix-experimental_role_warning">
Significance: minor
Type: dev

Add isWpVersion mock function to the @woocommerce/settings mock.
</file>

<file path="packages/js/internal-js-tests/changelog/update-59804">
Significance: minor
Type: dev

Bump jest package dependency to 29.5.x
</file>

<file path="packages/js/internal-js-tests/changelog/update-pnpm-10-upgrade">
Significance: patch
Type: dev

Update @wordpress/* peerDependencies from dist-tags to semver ranges for pnpm 10 compatibility.
</file>

<file path="packages/js/internal-js-tests/changelog/update-settings-router-calypso-package">
Significance: patch
Type: add

Ensure test files using same wp package instances
</file>

<file path="packages/js/internal-js-tests/changelog/update-wp-68-packages">
Significance: major
Type: update

Update @wordpress/* dependencies to wp-6.8 minimum.
</file>

<file path="packages/js/internal-js-tests/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/internal-js-tests/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/internal-js-tests/src/mocks/api-request.js">

</file>

<file path="packages/js/internal-js-tests/src/mocks/static.js">

</file>

<file path="packages/js/internal-js-tests/src/mocks/style-mock.js">

</file>

<file path="packages/js/internal-js-tests/src/mocks/tinymce.js">

</file>

<file path="packages/js/internal-js-tests/src/mocks/woocommerce-settings.js">
getSetting: ( key, backup ) =>
getAdminLink: ( path ) =>
isWpVersion: ( version, operator ) =>
</file>

<file path="packages/js/internal-js-tests/src/mocks/woocommerce-tracks.js">

</file>

<file path="packages/js/internal-js-tests/src/util/index.js">
const withMarkup = ( query )
⋮----
const hasText = ( domNode )
</file>

<file path="packages/js/internal-js-tests/src/setup-globals.js">
next()
⋮----
get: () => require( `@wordpress/$
⋮----
get: () => require( `@woocommerce/$
⋮----
reducer: () =>
⋮----
createNotice: () =>
</file>

<file path="packages/js/internal-js-tests/src/setup-react-testing-library.js">

</file>

<file path="packages/js/internal-js-tests/src/setup-window-globals.js">
global.window.matchMedia = ( query ) => (
⋮----
addListener: () =>
removeListener: () =>
addEventListener: () =>
removeEventListener: () =>
dispatchEvent: ()
⋮----
getItem: ( key )
setItem: ( key, value )
</file>

<file path="packages/js/internal-js-tests/typings/monorepo-enhancements.d.ts">

</file>

<file path="packages/js/internal-js-tests/.npmrc">
package-lock=false
</file>

<file path="packages/js/internal-js-tests/babel.config.js">

</file>

<file path="packages/js/internal-js-tests/build.mjs">

</file>

<file path="packages/js/internal-js-tests/composer.json">
{
	"name": "woocommerce/internal-js-tests",
	"description": "JavaScript test tooling.",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/internal-js-tests/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/internal-js-tests/jest-preset.js">

</file>

<file path="packages/js/internal-js-tests/package.json">
{
	"name": "@woocommerce/internal-js-tests",
	"version": "1.1.0",
	"description": "JavaScript test tooling.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/internal-js-tests/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git",
		"directory": "packages/internal-js-tests"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"private": true,
	"exports": {
		".": {
			"wc-source": "./src/util/index.js",
			"types": "./build-types/util/index.d.ts",
			"import": "./build-module/util/index.js",
			"require": "./build/util/index.js"
		}
	},
	"main": "build/util/index.js",
	"module": "build-module/util/index.js",
	"types": "build-types/util/index.d.ts",
... (81 lines truncated)
</file>

<file path="packages/js/internal-js-tests/tsconfig-jest.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"module": "commonjs",
		"declaration": false,
		"declarationMap": false,
		"declarationDir": null,
		"jsx": "react-jsx"
	}
}
</file>

<file path="packages/js/internal-js-tests/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": []
}
</file>

<file path="packages/js/navigation/changelog/.gitkeep">

</file>

<file path="packages/js/navigation/changelog/65662-dev-65627-postrelease-cleanup">
Significance: minor
Type: dev

Add react-dom to peerDependencies to follow the monorepo convention of declaring react and react-dom together.
</file>

<file path="packages/js/navigation/changelog/66078-dehoist-react">
Significance: patch
Type: dev
Comment: Declare react/react-dom as devDependencies alongside the existing peerDependencies. Tooling only; no runtime change.
</file>

<file path="packages/js/navigation/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/navigation/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/navigation/src/hooks/use-confirm-unsaved-changes.ts">
import { __ } from '@wordpress/i18n';
import { Location } from 'react-router-dom';
import { useEffect, useMemo } from '@wordpress/element';
⋮----
import { getHistory } from '../history';
import { parseAdminUrl } from '../url';
⋮----
export const useConfirmUnsavedChanges = (
	hasUnsavedChanges: boolean,
	shouldConfirm?: ( path: URL, fromUrl: Location ) => boolean,
	message?: string
) =>
⋮----
function onBeforeUnload( event: BeforeUnloadEvent )
</file>

<file path="packages/js/navigation/src/filters.js">
export function getUrlKey( key, rule )
⋮----
export function flattenFilters( filters )
⋮----
export function getActiveFiltersFromQuery( query, config )
⋮----
export function getDefaultOptionValue( config, options )
⋮----
export function getQueryFromActiveFilters( activeFilters, query, config )
</file>

<file path="packages/js/navigation/src/history.ts">
import { BrowserHistory, createBrowserHistory, Location } from 'history';
import { parse } from 'qs';
⋮----
interface WooLocation extends Location {
	pathname: string;
}
⋮----
export interface WooBrowserHistory extends BrowserHistory {
	location: WooLocation;
	readonly __experimentalLocationStack: WooLocation[];
}
⋮----
function getHistory(): WooBrowserHistory
⋮----
const updateNextLocationStack = (
			action: WooBrowserHistory[ 'action' ],
			location: WooBrowserHistory[ 'location' ]
) =>
⋮----
get action()
get location()
get __experimentalLocationStack()
⋮----
listen( listener )
</file>

<file path="packages/js/navigation/src/index.js">
export const getPersistedQuery = ( query = getQuery() ) =>
⋮----
export const getQueryExcludedScreens = ()
⋮----
export const getQueryExcludedScreensUrlUpdate = ()
⋮----
export const getScreenFromPath = ( path = getPath() ) =>
⋮----
/**
 * Get an array of IDs from a comma-separated query parameter.
 *
 * @param {string} [queryString=''] string value extracted from URL.
 * @return {Set<number>} List of IDs converted to a set of integers.
 */
export function getSetOfIdsFromQuery( queryString = '' )
⋮----
return new Set( // Return only unique ids.
⋮----
/**
 * Updates the query parameters of the current page.
 *
 * @param {Object} query        object of params to be updated.
 * @param {string} path         Relative path (defaults to current path).
 * @param {Object} currentQuery object of current query params (defaults to current querystring).
 * @param {string} page         Page key (defaults to "wc-admin")
 */
export function updateQueryString(
	query,
	path = getPath(),
	currentQuery = getQuery(),
... (25 lines truncated)
</file>

<file path="packages/js/navigation/src/url.js">
export const getPath = ()
⋮----
export function getQuery()
⋮----
export function getNewPath(
	query,
	path = getPath(),
	currentQuery = getQuery(),
	page = 'wc-admin'
)
⋮----
export const parseAdminUrl = ( url ) =>
</file>

<file path="packages/js/navigation/.npmrc">
package-lock=false
</file>

<file path="packages/js/navigation/babel.config.js">

</file>

<file path="packages/js/navigation/build.mjs">

</file>

<file path="packages/js/navigation/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [9.0.0](https://www.npmjs.com/package/@woocommerce/navigation/v/9.0.0) - 2026-06-10 

-   Major - Remove deprecated Navigation SlotFill; any consumer registering or rendering into it will silently stop working. [#50190]
-   Major - Remove WooCommerce Navigation client side feature and deprecate PHP classes. [#50190]
-   Major - Update @wordpress/* dependencies to WordPress 6.8 minimum. [#64114]
-   Major - Updated declared dependencies to React 18 and WordPress 6.6. [#53531]
-   Minor - Added `getQueryExcludedScreensUrlUpdate` to exclude updating onclick handler for specific screens. [#58209]
-   Minor - Bump jest package dependency to 29.5.x. [#60324]
-   Minor - Fix typos in inline documentation. [#48640]
-   Minor - Fix typos in README.md files. [#48569]
-   Minor - Monorepo: bump pnpm version to 9.15.0. [#54189]
-   Minor - Upgraded TypeScript in the monorepo to 5.7.2. [#53165]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - CI: code style fixes to pass linting in updated CI environment. [#49020]
-   Patch - CI: leverage composer packages cache in lint monorepo job. [#52054]
-   Patch - Clean up CI job config options; remove unused cascading keys. [#55863]
-   Patch - Fix pnpm version to 9.1.3 to avoid dependency installation issues. [#50828]
-   Patch - Monorepo: address circular dependencies surfaced by SWC TDZ. [#64797]
-   Patch - Monorepo: build RAM usage optimization. [#59001]
-   Patch - Monorepo: consolidate @babel/* dependencies versions across the monorepo. [#56575]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Monorepo: consolidate syncpack config around React 17/18 usage. [#52022]
-   Patch - Monorepo: consolidate TypeScript config files and JS test directories naming. [#52191]
-   Patch - Monorepo: drop the unused `concurrently` package from dependencies. [#58765]
-   Patch - Monorepo: refresh wireit dependencyOutputs configuration synchronization when installing dependencies. [#55095]
-   Patch - Move the CommonJS build to prepack so day-to-day development only builds the ESM output. [#64876]
... (46 lines truncated)
</file>

<file path="packages/js/navigation/composer.json">
{
	"name": "woocommerce/navigation",
	"description": "WooCommerce navigation utilities.",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/navigation/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/navigation/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/navigation/package.json">
{
	"name": "@woocommerce/navigation",
	"version": "9.0.0",
	"description": "WooCommerce navigation utilities.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"keywords": [
		"wordpress",
		"woocommerce",
		"navigation"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/navigation/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.js",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
... (110 lines truncated)
</file>

<file path="packages/js/navigation/PREVIOUS_CHANGELOG.md">
# 7.0.1

-   Add missing dependencies. #8349
-   Update all js packages with minor/patch version changes. #8392

# 7.0.0

## Breaking changes

-   Update dependencies to support react 17. #8305
-   Drop support for IE11. #8305

## 6.1.0

-   Fix commonjs module build, allow package to be built in isolation. #7286
-   Add `getSetOfIdsFromQuery` util.
-   Fix `getIdsFromQuery` support for `0` as a valid id.

# 6.0.1

-   Update dependencies.

# 6.0.0

-   Moving `addHistoryListener()` to this package, which supports adding a listener that is executed for history changes.
-   Update dependencies.
-   Add management of persisted queries to navigation.
-   Add page parameter to getNewPath to override default page wc-admin #5821

## Breaking changes
... (57 lines truncated)
</file>

<file path="packages/js/navigation/README.md">
# Navigation

A collection of navigation-related functions for handling query parameter objects, serializing query parameters, updating query parameters, and triggering path changes.

## Installation

Install the module

```bash
pnpm install @woocommerce/navigation --save
```

## Usage

### getHistory

A single history object used to perform path changes. This needs to be passed into ReactRouter to use the other path functions from this library.

```jsx
import { getHistory } from '@woocommerce/navigation';

render() {
	return (
		<Router history={ getHistory() }>
			…
		</Router>
	);
}
```

... (121 lines truncated)
</file>

<file path="packages/js/navigation/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": []
}
</file>

<file path="packages/js/notices/changelog/42860-update-pnpm">
Significance: patch
Type: dev
Comment: Updated PNPM
</file>

<file path="packages/js/notices/changelog/43532-add-cli-to-ci-workflow">
Significance: patch
Type: dev
Comment: This is a CI-only change.
</file>

<file path="packages/js/notices/changelog/43595-update-wireit-0.14.3">
Significance: patch
Type: dev
Comment: This is a developer-only build tooling related change.
</file>

<file path="packages/js/notices/changelog/44566-fix-44565-fix-gutenberg-links-pointing-to-the-wrong-branch-in-the-docs">
Significance: patch
Type: dev
Comment: Fix Gutenberg links in the docs pointing to incorrect branch.
</file>

<file path="packages/js/notices/changelog/45148-poc-request-reviews">
Significance: minor
Type: update

Bump node version.
</file>

<file path="packages/js/notices/changelog/46278-fix-43889-43901-43944">
Significance: patch
Type: dev
Comment: adds `glob`, `rimraf`, and `uuid` to Syncpack
</file>

<file path="packages/js/notices/changelog/47156-dev-fix-build-error-build-style">
Significance: patch
Type: dev
Comment: Fix a persistent build bug where TS would try compile files outside of src and typings directories.
</file>

<file path="packages/js/notices/changelog/47385-dev-update-pnpm9-1">
Significance: patch
Type: dev

Update pnpm to 9.1.0
</file>

<file path="packages/js/notices/changelog/50828-dev-constrain-pnpm-version">
Significance: patch
Type: dev

Fix pnpm version to 9.1.3 to avoid dependency installation issues.
</file>

<file path="packages/js/notices/changelog/52815-dev-lock-dependencies">
Significance: patch
Type: dev

Stabilize JS dependency updates
</file>

<file path="packages/js/notices/changelog/53165-dev-ts-5-7-2">
Significance: minor
Type: dev

Upgraded Typescript in the monorepo to 5.7.2
</file>

<file path="packages/js/notices/changelog/53531-dev-react-18-ghidorah">
Significance: major
Type: dev

Updated declared dependencies to React 18 and Wordpress 6.6
</file>

<file path="packages/js/notices/changelog/53865-dev-pnpm-9-15-0">
Significance: minor
Type: dev

Monorepo: bump pnpm version to 9.15.0
</file>

<file path="packages/js/notices/changelog/54996-chore-update-wireit">
Significance: patch
Type: dev

Update wireit to 0.14.10
</file>

<file path="packages/js/notices/changelog/55095-dev-rewrite-wireit-deps-update">
Significance: patch
Type: dev

Monorepo: refresh wireit dependencyOutputs configuration synchronization when installing dependencies.
</file>

<file path="packages/js/notices/changelog/56575-dev-bump-babel-deps">
Significance: patch
Type: dev

Monorepo: consolidate @babel/* dependencies versions across the monorepo.
</file>

<file path="packages/js/notices/changelog/57299-fix-wireit-in-ci">
Significance: patch
Type: dev

Bump wireit dependency version to latest.
</file>

<file path="packages/js/notices/changelog/58765-dev-deps-cleanup-concurrently">
Significance: patch
Type: dev

Monorepo: drop the unused `concurrently` package from dependencies.
</file>

<file path="packages/js/notices/changelog/58941-dev-consolidate-packages-license-version">
Significance: patch
Type: dev

Monorepo: consolidate packages licenses to `GPL-2.0-or-later`.
</file>

<file path="packages/js/notices/changelog/59001-dev-build-ram-usage-batch-3">
Significance: patch
Type: dev

Monorepo: build RAM usage optimization.
</file>

<file path="packages/js/notices/changelog/63483-add-62921-shared-monorepo-ts-config">
Significance: patch
Type: dev

Replaced patched `@wordpress/data` types with opt-in internal package types.
</file>

<file path="packages/js/notices/changelog/64838-dev-esbuild-package-builds">
Significance: patch
Type: dev

Replaced wireit + tsc package build pipeline with a per-package esbuild script.
</file>

<file path="packages/js/notices/changelog/65662-dev-65627-postrelease-cleanup">
Significance: major
Type: dev

Update @wordpress/data peer dependency to ^10.19.0 to align with WordPress 6.8 minimum.
</file>

<file path="packages/js/notices/changelog/66078-dehoist-react">
Significance: patch
Type: dev
Comment: Declare react/react-dom as devDependencies alongside the existing peerDependencies. Tooling only; no runtime change.
</file>

<file path="packages/js/notices/changelog/dev-64837-type-check-only-on-lint">
Significance: patch
Type: dev

Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking.
</file>

<file path="packages/js/notices/changelog/dev-build-profiling-tweaks-take-1">
Significance: patch
Type: dev

Monorepo: consolidate TypeScript config files and JS test directories naming.
</file>

<file path="packages/js/notices/changelog/dev-ci-lint-monorepo-job-update">
Significance: patch
Type: dev

CI: liverage composer packages cache in lint monorepo job
</file>

<file path="packages/js/notices/changelog/dev-cjs-prepack-only">
Significance: patch
Type: dev

Move the CommonJS build to prepack so day-to-day development only builds the ESM output.
</file>

<file path="packages/js/notices/changelog/dev-consolidate-syncpack-config">
Significance: patch
Type: dev

Monorepo: consolidate syncpack config around React 17/18 usage.
</file>

<file path="packages/js/notices/changelog/dev-updates-to-packages-for-dependencies">
Significance: patch
Type: dev

Update dependencies
</file>

<file path="packages/js/notices/changelog/fix-arialive-type">
Significance: patch
Type: fix

Narrow ariaLive type to 'polite' | 'assertive' to match @wordpress/a11y speak() signature.
</file>

<file path="packages/js/notices/changelog/fix-domain-substitution">
Significance: patch
Type: fix

Add composer.json for live build
</file>

<file path="packages/js/notices/changelog/fix-misspelling-in-inline-doc-packages-js">
Significance: minor
Type: tweak

Fix typos in inline documentation
</file>

<file path="packages/js/notices/changelog/update-59804">
Significance: minor
Type: dev

Bump jest package dependency to 29.5.x
</file>

<file path="packages/js/notices/changelog/update-pnpm-10-upgrade">
Significance: patch
Type: dev

Update @wordpress/* peerDependencies from dist-tags to semver ranges for pnpm 10 compatibility.
</file>

<file path="packages/js/notices/changelog/update-wp-68-packages">
Significance: major
Type: update

Update @wordpress/* dependencies to wp-6.8 minimum.
</file>

<file path="packages/js/notices/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/notices/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/notices/src/store/utils/on-sub-key.ts">
import type { Reducer } from 'redux';
⋮----
import { State, Notices } from '../types';
import { Action } from '../actions';
⋮----
export const onSubKey =
( actionProperty: keyof Action )
</file>

<file path="packages/js/notices/src/store/actions.ts">
import { uniqueId } from 'lodash';
import type { WPNoticeAction } from '@wordpress/notices/build-types/store/actions';
⋮----
import { DEFAULT_CONTEXT, DEFAULT_STATUS } from './constants';
⋮----
export type Options = {
	id: string;
	context: string;
	isDismissible: boolean;
	type: string;
	speak: boolean;
	actions: Array< WPNoticeAction >;
	icon: null | JSX.Element;
	explicitDismiss: boolean;
	onDismiss: ( () => void ) | null;
	__unstableHTML?: boolean;
};
⋮----
export function createNotice(
	status: string = DEFAULT_STATUS,
	content: string,
	options: Partial< Options > = {}
)
⋮----
export function createSuccessNotice( content: string, options: Options )
⋮----
export function createInfoNotice( content: string, options: Options )
⋮----
export function createErrorNotice( content: string, options: Options )
⋮----
... (6 lines truncated)
</file>

<file path="packages/js/notices/src/store/constants.ts">

</file>

<file path="packages/js/notices/src/store/controls.ts">
import { speak } from '@wordpress/a11y';
⋮----
export type Action = {
	message: string;
	ariaLive?: 'polite' | 'assertive';
};
⋮----
SPEAK( action: Action )
</file>

<file path="packages/js/notices/src/store/index.ts">
import { registerStore } from '@wordpress/data';
import { SelectFromMap, DispatchFromMap } from '@woocommerce/data';
import { Reducer, AnyAction } from 'redux';
⋮----
import reducer from './reducer';
⋮----
import { State } from './types';
⋮----
function dispatch(
		key: typeof STORE_NAME
	): DispatchFromMap< typeof actions >;
function select(
		key: typeof STORE_NAME
	): SelectFromMap< typeof selectors >;
</file>

<file path="packages/js/notices/src/store/reducer.ts">
import { reject } from 'lodash';
import type { Reducer } from 'redux';
⋮----
import onSubKey from './utils/on-sub-key';
import { Action } from './actions';
import { Notices } from './types';
⋮----
const notices: Reducer< Notices, Action > = ( state = [], action ) =>
⋮----
export type State = {
	[ context: string ]: Notices;
};
</file>

<file path="packages/js/notices/src/store/selectors.ts">
import { DEFAULT_CONTEXT } from './constants';
import { State } from './reducer';
⋮----
export function getNotices( state: State, context: string = DEFAULT_CONTEXT )
</file>

<file path="packages/js/notices/src/store/types.ts">
import { createNotice } from './actions';
⋮----
export type Notices = Array< ReturnType< typeof createNotice >[ 'notice' ] >;
⋮----
export type State = {
	[ context: string ]: Notices;
};
</file>

<file path="packages/js/notices/src/index.ts">

</file>

<file path="packages/js/notices/typings/monorepo-enhancements.d.ts">

</file>

<file path="packages/js/notices/.npmrc">
package-lock=false
</file>

<file path="packages/js/notices/build.mjs">

</file>

<file path="packages/js/notices/CHANGELOG.md">
<!-- Learn how to maintain this file at https://github.com/WordPress/gutenberg/tree/trunk/packages#maintaining-changelogs. -->

# Unreleased

-   Update dependency `@wordpress/a11y` to ^3.5.0

# 4.0.1

-   Update all js packages with minor/patch version changes. #8392

# 4.0.0

## Breaking changes

-   Update dependencies to support react 17. #8305
-   Drop support for IE11. #8305

## 3.1.0

-   Fix commonjs module build, allow package to be built in isolation. #7286

## 3.0.0 (2021-06-03)

## Breaking changes

-   Move Lodash to a peer dependency.

## 2.0.0 (2020-02-10)

### Breaking Change
... (37 lines truncated)
</file>

<file path="packages/js/notices/composer.json">
{
	"name": "woocommerce/notices",
	"description": "State management for notices.",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/notices/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/notices/package.json">
{
	"name": "@woocommerce/notices",
	"version": "4.0.1",
	"description": "State management for notices.",
	"author": "The WordPress Contributors",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"keywords": [
		"wordpress",
		"gutenberg",
		"notices"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/notices/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerge.git",
		"directory": "packages/js/notices"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
... (83 lines truncated)
</file>

<file path="packages/js/notices/README.md">
# Notices

State management for notices.

NOTE: This has been copied from Gutenberg so that we can iterate on it faster
than if we were relying on Gutenberg releasing a new version with our
requirements. Once Gutenberg supports our requirements this package should be
removed.

**Update:** Changes required have been shipped in the Gutenberg package released with WP 5.7, so this package will be removed when WP 5.9 becomes available. Please use the Gutenberg version instead.

## Installation

Install the module

```bash
pnpm install @wordpress/notices
```

_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for ES2015+ such as lower versions of IE then using [core-js](https://github.com/zloirock/core-js) or [@babel/polyfill](https://babeljs.io/docs/en/next/babel-polyfill) will add support for these methods. Learn more about it in [Babel docs](https://babeljs.io/docs/en/next/caveats)._

## Usage

When imported, the notices module registers a data store on the `core/notices` namespace. In WordPress, this is accessed from `wp.data.dispatch( 'core/notices' )`.

For more information about consuming from a data store, refer to [the `@wordpress/data` documentation on _Data Access and Manipulation_](/packages/data/README.md#data-access-and-manipulation).

For a full list of actions and selectors available in the `core/notices` namespace, refer to the [_Notices Data_ Handbook page](/docs/designers-developers/developers/data/data-core-notices.md).

<br/><br/><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p>
... (1 lines truncated)
</file>

<file path="packages/js/notices/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": [
		{
			"path": "../data"
		}
	]
}
</file>

<file path="packages/js/number/changelog/.gitkeep">

</file>

<file path="packages/js/number/changelog/wooplug-2965-negative-baseline-delta">
Significance: patch
Type: fix

Fix calculateDelta returning the wrong sign when the baseline is negative by dividing by the absolute value of the baseline (#54303).
</file>

<file path="packages/js/number/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/number/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/number/src/index.ts">
import { number_format as numberFormatter } from 'locutus/php/strings/number_format';
⋮----
export type NumberConfig = {
	precision: number | string | null;
	decimalSeparator: string;
	thousandSeparator: string;
};
⋮----
export function numberFormat(
	{
		precision = null,
		decimalSeparator = '.',
		thousandSeparator = ',',
	}: Partial< NumberConfig >,
	number?: number | string
)
⋮----
/**
 * Formats a number as average or number string according to the given `type`.
 *  - `type = 'average'` returns a rounded `Number`
 *  - `type = 'number'` returns a formatted `String`
 *
 * @param {NumberConfig} numberConfig number formatting configuration object.
 * @param {string}       type         of number to format, `'average'` or `'number'`
 * @param {number}       value        to format.
 * @return {string | number | null} A formatted string.
 */
export function formatValue(
	numberConfig: NumberConfig,
	type: string,
... (14 lines truncated)
</file>

<file path="packages/js/number/typings/index.d.ts">
export function number_format(number: number | string, decimals?: number, decPoint?: string, thousandsSep?: string): string;
</file>

<file path="packages/js/number/.npmrc">
package-lock=false
</file>

<file path="packages/js/number/babel.config.js">

</file>

<file path="packages/js/number/build.mjs">

</file>

<file path="packages/js/number/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.6.0](https://www.npmjs.com/package/@woocommerce/number/v/2.6.0) - 2026-06-10 

-   Minor - Bump jest package dependency to 29.5.x. [#60324]
-   Minor - Fix typos in parse number tests. [#48644]
-   Minor - Monorepo: bump pnpm version to 9.15.0. [#54189]
-   Minor - Upgraded TypeScript in the monorepo to 5.7.2. [#53165]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - CI: leverage composer packages cache in lint monorepo job. [#52054]
-   Patch - Clean up CI job config options; remove unused cascading keys. [#55863]
-   Patch - Comment: Fix comment typos across various files. [#50047]
-   Patch - Fix pnpm version to 9.1.3 to avoid dependency installation issues. [#50828]
-   Patch - Monorepo: build RAM usage optimization. [#59001]
-   Patch - Monorepo: consolidate @babel/* dependencies versions across the monorepo. [#56575]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Monorepo: consolidate syncpack config around React 17/18 usage. [#52022]
-   Patch - Monorepo: consolidate TypeScript config files and JS test directories naming. [#52191]
-   Patch - Monorepo: drop the unused `concurrently` package from dependencies. [#58765]
-   Patch - Monorepo: refresh wireit dependencyOutputs configuration synchronization when installing dependencies. [#55095]
-   Patch - Move the CommonJS build to prepack so day-to-day development only builds the ESM output. [#64876]
-   Patch - Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking. [#65168]
-   Patch - Replaced patched `@wordpress/data` types with opt-in internal package types. [#63483]
-   Patch - Replaced wireit + tsc package build pipeline with a per-package esbuild script. [#65210]
-   Patch - Update wireit to 0.14.10. [#54996]
-   Patch - Updating dependencies. [#63992]

## [2.5.0](https://www.npmjs.com/package/@woocommerce/number/v/2.5.0) - 2024-06-11 
... (33 lines truncated)
</file>

<file path="packages/js/number/composer.json">
{
	"name": "woocommerce/number",
	"description": "Number formatting utilities for WooCommerce.",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/number/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/number/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/number/package.json">
{
	"name": "@woocommerce/number",
	"version": "2.6.0",
	"description": "Number formatting utilities for WooCommerce.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"keywords": [
		"wordpress",
		"woocommerce"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/number/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
	"main": "build/index.js",
... (92 lines truncated)
</file>

<file path="packages/js/number/PREVIOUS_CHANGELOG.md">
# 2.2.1

-   Update all js packages with minor/patch version changes. #8392

# 2.2.0

-   Fix commonjs module build, allow package to be built in isolation. #7286

# 2.1.1

-   Update dependencies.
-   Add TypeScript support.

# 2.1.0

-   Update to @wordpress/eslint coding standards.

# 2.0.0

-   Remove lodash dependency.

## Breaking Changes

-   Decouple from global wcSettings object.
-   Exported methods of the number package have been rewritten to accept a configuration object as their first parameter.

# 1.0.4

-   Update dependencies.

... (14 lines truncated)
</file>

<file path="packages/js/number/README.md">
# Number

A collection of utilities to properly localize numerical values in WooCommerce

## Installation

Install the module

```bash
pnpm install @woocommerce/number --save
```

_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for ES2015+ such as lower versions of IE then using [core-js](https://github.com/zloirock/core-js) or [@babel/polyfill](https://babeljs.io/docs/en/next/babel-polyfill) will add support for these methods. Learn more about it in [Babel docs](https://babeljs.io/docs/en/next/caveats)._

## Usage

```JS
import { numberFormat, formatValue, calculateDelta } from '@woocommerce/number';

// It's best to retrieve the site currency settings and compose them with the format functions.
import { partial } from 'lodash';
// Retrieve this from the API or a global settings object.
const siteNumberOptions = {
  precision: 2,
  decimalSeparator: '.',
  thousandSeparator: ',',
};
// Compose.
const formatStoreNumber = partial( numberFormat, siteNumberOptions );
const formatStoreValue = partial( formatValue, siteNumberOptions );
... (14 lines truncated)
</file>

<file path="packages/js/number/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": []
}
</file>

<file path="packages/js/onboarding/changelog/.gitkeep">

</file>

<file path="packages/js/onboarding/changelog/consolidate-eslint-core-modules">
Significance: patch
Type: dev
Comment: Consolidate the shared `import/core-modules` list into `@woocommerce/eslint-config`. Tooling only; no runtime change.
</file>

<file path="packages/js/onboarding/changelog/dev-eslint-no-floating-promises">
Significance: patch
Type: dev

Add void to intentionally-unawaited promises for the new no-floating-promises lint rule
</file>

<file path="packages/js/onboarding/changelog/fix-dz-states-test-fixture">
Significance: patch
Type: dev

Fix stale 'Tamanghasset' spelling and add missing DZ-49 through DZ-58 Algeria wilayas to the onboarding country/state test fixture.
</file>

<file path="packages/js/onboarding/changelog/fix-payment-methods-count-theme-colors">
Significance: patch
Type: fix

Make the payment methods "+N" badge follow the admin colour scheme on hover, match its focus ring width to the surrounding controls, and align its size with the payment method logos beside it.
</file>

<file path="packages/js/onboarding/changelog/performance-woopayments-onboarding-svg-assets">
Significance: major
Type: performance

Convert WooPayments onboarding payment method logos from inline JSX SVG components to static SVG assets, and remove the now-unused WCPayCard, WCPayAcceptedMethods, and individual icon exports.
</file>

<file path="packages/js/onboarding/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/onboarding/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/onboarding/src/components/Loader/stories/loader.story.tsx">
import { createElement } from 'react';
⋮----
import { Loader } from '../';
⋮----
export const ExampleSimpleLoader = () => (
	<Loader>
		<Loader.Layout>
			<Loader.Illustration>
				<img
					src="https://placekitten.com/200/200"
					alt="a cute kitteh"
				/>
			</Loader.Illustration>
			<Loader.Title>Very Impressive Title</Loader.Title>
			<Loader.ProgressBar progress={ 30 } />
			<Loader.Sequence interval={ 1000 }>
				<Loader.Subtext>Message 1</Loader.Subtext>
				<Loader.Subtext>Message 2</Loader.Subtext>
				<Loader.Subtext>Message 3</Loader.Subtext>
			</Loader.Sequence>
		</Loader.Layout>
	</Loader>
);
⋮----
export const ExampleNonLoopingLoader = () => (
	<Loader>
		<Loader.Layout>
			<Loader.Illustration>
				<img
					src="https://placekitten.com/200/200"
... (34 lines truncated)
</file>

<file path="packages/js/onboarding/src/components/Loader/index.ts">

</file>

<file path="packages/js/onboarding/src/components/Loader/Loader.tsx">
import clsx from 'clsx';
import {
	useState,
	useEffect,
	Children,
	createElement,
	Fragment,
} from '@wordpress/element';
import type { ReactNode } from 'react';
⋮----
import ProgressBar from './ProgressBar';
⋮----
export const Loader = ( {
	children,
	className,
}: {
	children: ReactNode;
	className?: string;
} ) =>
⋮----
<div className=
⋮----
type withClassName = {
	className?: string;
};
⋮----
type withReactChildren = {
	children: ReactNode;
};
⋮----
... (2 lines truncated)
</file>

<file path="packages/js/onboarding/src/components/Loader/ProgressBar.tsx">
import { createElement, HTMLAttributes } from 'react';
⋮----
type ProgressBarProps = {
	className?: string;
	percent?: number;
	color?: string;
	bgcolor?: string;
};
⋮----
const ProgressBar = ( {
	className = '',
	percent = 0,
	color = '#674399',
	bgcolor = 'var(--wp-admin-theme-color)',
}: ProgressBarProps ) =>
</file>

<file path="packages/js/onboarding/src/components/RecommendedRibbon/index.ts">

</file>

<file path="packages/js/onboarding/src/components/RecommendedRibbon/RecommendedRibbon.tsx">
import { __ } from '@wordpress/i18n';
import { createElement } from '@wordpress/element';
⋮----
type RecommendedRibbonProps = {
	isLocalPartner?: boolean;
};
⋮----
export const RecommendedRibbon: React.VFC< RecommendedRibbonProps > = ( {
	isLocalPartner = false,
} ) =>
</file>

<file path="packages/js/onboarding/src/components/WCPayBanner/index.ts">

</file>

<file path="packages/js/onboarding/src/components/WCPayBanner/WCPayBanner.tsx">
import {
	createElement,
	createInterpolateElement,
	Fragment,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Card, CardFooter, CardBody } from '@wordpress/components';
import { Text } from '@woocommerce/experimental';
⋮----
import { WooPaymentsMethodsLogos } from '../WooPaymentsMethodsLogos';
import { WCPayBannerImage } from './WCPayBannerImage';
⋮----
export const WCPayBanner = (
</file>

<file path="packages/js/onboarding/src/components/WCPayBanner/WCPayBannerImage.tsx">
import { createElement } from '@wordpress/element';
⋮----
export const WCPayBannerImage = () => (
	<svg
		width="294"
		height="275"
		viewBox="0 0 294 275"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<g clipPath="url(#clip0_255_63852)">
			<path
				d="M0.5 10C0.5 4.47716 4.97715 0 10.5 0H725.5C731.023 0 735.5 4.47715 735.5 10V332H0.5V10Z"
				fill="#F6F7F7"
			/>
			<circle cx="17.5" cy="14" r="5" fill="#D94F4F" />
			<circle cx="35.5" cy="14" r="5" fill="#F0B849" />
			<circle cx="53.5" cy="14" r="5" fill="#4AB866" />
			<rect x="3.5" y="28" width="287" height="304" fill="white" />
			<line x1="27.5" y1="95.5" x2="270.5" y2="95.5" stroke="#DCDCDE" />
			<line x1="49.5" y1="157.5" x2="253.5" y2="157.5" stroke="#DCDCDE" />
			<line x1="49.5" y1="198.5" x2="253.5" y2="198.5" stroke="#DCDCDE" />
			<rect
				x="28"
				y="116.5"
				width="242"
				height="127"
				rx="9.5"
				stroke="#DCDCDE"
			/>
... (110 lines truncated)
</file>

<file path="packages/js/onboarding/src/components/WCPayBanner/WCPayBannerImageCut.tsx">
import { createElement } from '@wordpress/element';
⋮----
export const WCPayBannerImageCut = () => (
	<svg
		width="310"
		height="282"
		viewBox="0 0 307 282"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<g filter="url(#filter0_d_889_14107)">
			<path
				d="M16 26C16 20.4772 20.4772 16 26 16H309V44H16V26Z"
				fill="#F2EDFF"
			/>
			<path
				d="M16 44H309V256H26C20.4771 256 16 251.523 16 246V44Z"
				fill="white"
			/>
		</g>
		<path
			d="M42.5 115C42.5 109.753 46.7533 105.5 52 105.5H308.5V232.5H52C46.7533 232.5 42.5 228.247 42.5 223V115Z"
			fill="white"
			stroke="#DCDCDE"
		/>
		<path
			d="M64.8545 130V122.954H67.6279C69.7227 122.954 70.9336 124.219 70.9336 126.426V126.436C70.9336 128.711 69.7373 130 67.6279 130H64.8545ZM66.3291 128.784H67.3936C68.6973 128.784 69.4297 127.964 69.4297 126.46V126.45C69.4297 125 68.6729 124.17 67.3936 124.17H66.3291V128.784ZM74.5566 130.112C72.9209 130.112 71.9297 129.043 71.9297 127.319V127.314C71.9297 125.605 72.9307 124.507 74.498 124.507C76.0654 124.507 77.042 125.581 77.042 127.207V127.651H73.3408C73.3555 128.535 73.8291 129.048 74.5859 129.048C75.2109 129.048 75.5576 128.716 75.6553 128.511L75.6699 128.481H76.998L76.9883 128.53C76.8223 129.204 76.1289 130.112 74.5566 130.112ZM74.5225 125.576C73.9023 125.576 73.4434 125.996 73.3555 126.758H75.6748C75.5869 125.977 75.1426 125.576 74.5225 125.576ZM78.209 131.782V124.624H79.6348V125.454H79.7227C80.001 124.878 80.5723 124.536 81.334 124.536C82.6768 124.536 83.5166 125.591 83.5166 127.305V127.314C83.5166 129.043 82.6963 130.083 81.334 130.083C80.5967 130.083 79.9961 129.727 79.7227 129.141H79.6348V131.782H78.209ZM80.8457 128.901C81.5977 128.901 82.0664 128.301 82.0664 127.314V127.305C82.0664 126.318 81.6025 125.718 80.8457 125.718C80.0938 125.718 79.6201 126.318 79.6201 127.305V127.314C79.6201 128.301 80.0986 128.901 80.8457 128.901ZM87.0713 130.112C85.416 130.112 84.4199 129.062 84.4199 127.314V127.305C84.4199 125.571 85.4307 124.507 87.0713 124.507C88.7119 124.507 89.7227 125.566 89.7227 127.305V127.314C89.7227 129.067 88.7266 130.112 87.0713 130.112ZM87.0713 128.994C87.8281 128.994 88.2627 128.374 88.2627 127.314V127.305C88.2627 126.255 87.8232 125.625 87.0713 125.625C86.3145 125.625 85.8799 126.255 85.8799 127.305V127.314C85.8799 128.374 86.3096 128.994 87.0713 128.994ZM93.0234 130.112C91.5635 130.112 90.7334 129.458 90.6309 128.535L90.626 128.516H92.0273L92.0371 128.535C92.1494 128.867 92.4766 129.106 93.0381 129.106C93.585 129.106 93.9561 128.872 93.9561 128.516V128.506C93.9561 128.218 93.7412 128.037 93.1943 127.915L92.2959 127.725C91.2705 127.505 90.7627 127.002 90.7627 126.196V126.191C90.7627 125.181 91.6611 124.507 93.0039 124.507C94.415 124.507 95.1963 125.21 95.2549 126.074V126.094H93.9316L93.9268 126.069C93.8486 125.781 93.5312 125.513 92.999 125.513C92.5059 125.513 92.1543 125.742 92.1543 126.104V126.108C92.1543 126.396 92.3545 126.562 92.9111 126.685L93.8047 126.875C94.8789 127.104 95.3818 127.554 95.3818 128.35V128.354C95.3818 129.419 94.4004 130.112 93.0234 130.112ZM97.2764 123.799C96.8369 123.799 96.4707 123.447 96.4707 123.008C96.4707 122.563 96.8369 122.212 97.2764 122.212C97.7158 122.212 98.0771 122.563 98.0771 123.008C98.0771 123.447 97.7158 123.799 97.2764 123.799ZM96.5586 130V124.624H97.9844V130H96.5586ZM101.651 130.02C100.343 130.02 99.8154 129.595 99.8154 128.55V125.698H98.9854V124.624H99.8154V123.34H101.256V124.624H102.364V125.698H101.256V128.223C101.256 128.706 101.461 128.921 101.944 128.921C102.13 128.921 102.228 128.911 102.364 128.896V129.956C102.188 129.99 101.925 130.02 101.651 130.02Z"
			fill="#2C3338"
		/>
		<path
... (103 lines truncated)
</file>

<file path="packages/js/onboarding/src/components/WCPayBenefits/icons/earn-manage.js">
export const EarnManageIcon = () => (
	<svg
		width="25"
		height="24"
		viewBox="0 0 25 24"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<mask
			id="mask0_5908_1139"
			style={ { maskType: 'luminance' } }
			maskUnits="userSpaceOnUse"
			x="3"
			y="2"
			width="19"
			height="19"
		>
			<path
				fillRule="evenodd"
				clipRule="evenodd"
				d="M20.9999 6V19C20.9999 20.104 20.1039 21 18.9999 21H4.99991C3.89591 21 2.99991 20.104 2.99991 19V6C2.99991 4.896 3.89591 4 4.99991 4H5.99991V2H7.99991V4H15.9999V2H17.9999V4H18.9999C20.1039 4 20.9999 4.896 20.9999 6ZM10.4979 18.001L6.79291 14.296L8.20791 12.881L10.5019 15.175L15.7949 9.882L17.2099 11.297L10.4979 18.001ZM4.99991 8H18.9999V19H4.99991V8Z"
				fill="white"
			/>
		</mask>
		<g mask="url(#mask0_5908_1139)">
			<rect x="-9.15527e-05" width="24" height="24" fill="#720EEC" />
		</g>
	</svg>
);
</file>

<file path="packages/js/onboarding/src/components/WCPayBenefits/icons/index.ts">

</file>

<file path="packages/js/onboarding/src/components/WCPayBenefits/icons/International-market.js">
export const InternationalMarketIcon = () => (
	<svg
		width="25"
		height="24"
		viewBox="0 0 25 24"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<mask
			id="mask0_5908_1702"
			style={ { maskType: 'luminance' } }
			maskUnits="userSpaceOnUse"
			x="2"
			y="2"
			width="21"
			height="20"
		>
			<path
				fillRule="evenodd"
				clipRule="evenodd"
				d="M1.99991 12C1.99991 6.477 6.47691 2 11.9999 2C17.5229 2 21.9999 6.477 21.9999 12C21.9999 17.523 17.5229 22 11.9999 22C6.47691 22 1.99991 17.523 1.99991 12ZM14.9999 17L13.9999 18L11.9999 20C15.2389 20 18.0289 18.061 19.2859 15.286L18.9999 15H16.9999L15.9999 14V12L17.9999 10H19.7359C19.4339 8.834 18.8819 7.767 18.1299 6.87L14.9999 10L13.9999 9V7L14.9999 6V4.589C14.0729 4.212 13.0609 4 11.9999 4C10.9389 4 9.92691 4.212 8.99991 4.589V5L9.99991 6H11.9999V8L8.99991 11H6.99991V13H4.99991L3.99991 12C3.99991 16.072 7.05991 19.436 10.9999 19.931V18L8.99991 16V13H11.9999L12.9999 14V15H14.9999V17Z"
				fill="white"
			/>
		</mask>
		<g mask="url(#mask0_5908_1702)">
			<rect x="-9.15527e-05" width="24" height="24" fill="#720EEC" />
		</g>
	</svg>
);
</file>

<file path="packages/js/onboarding/src/components/WCPayBenefits/icons/payment-card.js">
export const PaymentCardIcon = () => (
	<svg
		width="24"
		height="24"
		viewBox="0 0 24 24"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<mask
			id="mask0_5908_1374"
			style={ { maskType: 'luminance' } }
			maskUnits="userSpaceOnUse"
			x="2"
			y="4"
			width="20"
			height="16"
		>
			<path
				fillRule="evenodd"
				clipRule="evenodd"
				d="M20 4H4C2.895 4 2 4.895 2 6V18C2 19.105 2.895 20 4 20H20C21.105 20 22 19.105 22 18V6C22 4.895 21.105 4 20 4ZM20 6V8H4V6H20ZM4 12V18H20V12H4ZM6 14H13V16H6V14ZM18 14H15V16H18V14Z"
				fill="white"
			/>
		</mask>
		<g mask="url(#mask0_5908_1374)">
			<rect width="24" height="24" fill="#720EEC" />
		</g>
	</svg>
);
</file>

<file path="packages/js/onboarding/src/components/WCPayBenefits/icons/woopay.js">
export const WooPayIcon = () => (
	<svg
		width="24"
		height="24"
		viewBox="0 0 24 13"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<path
			d="M6.53076 12.9364C8.02509 12.9364 9.22424 12.2203 10.1282 10.5731L12.1391 6.9207V10.0181C12.1391 11.8443 13.3567 12.9364 15.2384 12.9364C16.7143 12.9364 17.8028 12.3098 18.8543 10.5731L23.4849 2.98183C24.4996 1.31676 23.7801 0.0634766 21.5478 0.0634766C20.3487 0.0634766 19.5738 0.43946 18.8728 1.71064L15.6812 7.52944V2.35519C15.6812 0.815444 14.9248 0.0634766 13.5227 0.0634766C12.4158 0.0634766 11.5303 0.52898 10.8477 1.81807L7.8406 7.52944V2.4089C7.8406 0.761732 7.13956 0.0634766 5.4423 0.0634766H1.97399C0.664145 0.0634766 0 0.654308 0 1.74645C0 2.83859 0.701042 3.46523 1.97399 3.46523H3.39452V10.0002C3.39452 11.8443 4.66746 12.9364 6.53076 12.9364Z"
			fill="#873EFF"
		/>
	</svg>
);
</file>

<file path="packages/js/onboarding/src/components/WCPayBenefits/index.ts">

</file>

<file path="packages/js/onboarding/src/components/WCPayBenefits/WCPayBenefits.tsx">
import { createElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Text } from '@woocommerce/experimental';
import { Flex } from '@wordpress/components';
⋮----
import {
	PaymentCardIcon,
	InternationalMarketIcon,
	EarnManageIcon,
	WooPayIcon,
} from './icons';
</file>

<file path="packages/js/onboarding/src/components/WooOnboardingTask/index.ts">

</file>

<file path="packages/js/onboarding/src/components/WooOnboardingTask/WooOnboardingTask.tsx">
import { createElement, useEffect } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
import { Slot, Fill } from '@wordpress/components';
⋮----
export const trackView = async ( taskId: string, variant?: string ) =>
⋮----
type WooOnboardingTaskProps = {
	id: string;
	children: React.ComponentProps< typeof Fill >[ 'children' ];
	variant?: string;
};
⋮----
type WooOnboardingTaskSlotProps = {
	id: string;
	fillProps: React.ComponentProps< typeof Slot >[ 'fillProps' ];
};
⋮----
const WooOnboardingTask = (
</file>

<file path="packages/js/onboarding/src/components/WooOnboardingTaskListHeader/index.ts">

</file>

<file path="packages/js/onboarding/src/components/WooOnboardingTaskListHeader/WooOnboardingTaskListHeader.tsx">
import { createElement } from '@wordpress/element';
import { Slot, Fill } from '@wordpress/components';
⋮----
type WooOnboardingTaskListHeaderProps = {
	id: string;
} & Omit< React.ComponentProps< typeof Fill >, 'name' >;
</file>

<file path="packages/js/onboarding/src/components/WooOnboardingTaskListItem/index.ts">

</file>

<file path="packages/js/onboarding/src/components/WooOnboardingTaskListItem/WooOnboardingTaskListItem.tsx">
import { createElement } from '@wordpress/element';
import { Slot, Fill } from '@wordpress/components';
⋮----
type WooOnboardingTaskListItemProps = {
	id: string;
	children: React.ComponentProps< typeof Fill >[ 'children' ];
};
</file>

<file path="packages/js/onboarding/src/components/WooOnboardingTaskReferral/index.ts">
type StoredItem< T > = {
	data: T;
	expiry: string;
};
⋮----
export function createStorageUtils< T >(
	key: string,
	durationInSeconds: number,
	type: 'session' | 'local' = 'local'
)
⋮----
export type TaskReferralRecord = {
	referrer: string;
	returnUrl: string;
};
⋮----
export const accessTaskReferralStorage = ( {
	taskId,
	referralLifetime = 60,
}: {
	taskId: string;
	referralLifetime?: number;
} )
</file>

<file path="packages/js/onboarding/src/components/WooPaymentGatewayConfigure/index.ts">

</file>

<file path="packages/js/onboarding/src/components/WooPaymentGatewayConfigure/README.md">
# WooPaymentGatewayConfigure Slot & Fill

A Slotfill component that will replace the <DynamicForm /> component involved in displaying the form while adding a gateway via the payment task.

## Usage

```jsx
<WooPaymentGatewayConfigure id={ key }>
  {({defaultForm: DefaultForm}) => {
    return <>
      <p>
        Fill Content
      </p>
      { defaultForm }
    </>;
}}
</WooPaymentGatewayConfigure>

<WooPaymentGatewayConfigure.Slot id={ key } />
```

### WooPaymentGatewayConfigure (fill)

This is the fill component. You must provide the `id` prop to identify the slot that this will occupy. If you provide a function as the child of your fill (as shown above), you will receive some helper props to assist in creating your fill:

| Name             | Type     | Description                                                                                                              |
| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `defaultForm`    | Element  | The default instance of the <DynamicForm> component. Can overwrite props using React.cloneElement(defaultForm, newProps) |
| `defaultSubmit`  | Function | The default submit handler that is provided to the <Form> component                                                      |
| `defaultFields`  | Array    | An array of the field configuration objects provided by the API                                                          |
... (11 lines truncated)
</file>

<file path="packages/js/onboarding/src/components/WooPaymentGatewayConfigure/WooPaymentGatewayConfigure.tsx">
import { createElement } from '@wordpress/element';
import { Slot, Fill } from '@wordpress/components';
⋮----
type WooPaymentGatewayConfigureProps = {
	id: string;
};
</file>

<file path="packages/js/onboarding/src/components/WooPaymentGatewaySetup/index.ts">

</file>

<file path="packages/js/onboarding/src/components/WooPaymentGatewaySetup/README.md">
# WooPaymentGatewaySetup Slot & Fill

A Slotfill component that will replace the <Stepper /> involved in the installation for a gateway via the payment task.

## Usage

```jsx
<WooPaymentGatewaySetup id={ key }>
  {({defaultStepper: DefaultStepper}) => <p>Fill Content</p>}
</WooPaymentGatewaySetup>

<WooPaymentGatewaySetup.Slot id={ key } />
```

### WooPaymentGatewaySetup (fill)

This is the fill component. You must provide the `id` prop to identify the slot that this will occupy. If you provide a function as the child of your fill (as shown above), you will receive some helper props to assist in creating your fill:

| Name                 | Type      | Description                                                                                          |
| -------------------- | --------- | ---------------------------------------------------------------------------------------------------- |
| `defaultStepper`     | Component | The default instance of the <Stepper> component. Any provided props will override the given defaults |
| `defaultInstallStep` | Object    | The object that describes the default step configuration for installation of the gateway             |
| `defaultConnectStep` | Object    | The object that describes the default step configuration for configuration of the gateway            |
| `paymentGateway`     | Object    | An object describing all of the relevant data pertaining to this payment gateway                     |

### WooPaymentGatewaySetup.Slot (slot)

This is the slot component, and will not be used as frequently. It must also receive the required `id` prop that will be identical to the fill `id`.

| Name        | Type   | Description                                                                        |
... (3 lines truncated)
</file>

<file path="packages/js/onboarding/src/components/WooPaymentGatewaySetup/WooPaymentGatewaySetup.tsx">
import { createElement } from '@wordpress/element';
import { Slot, Fill } from '@wordpress/components';
⋮----
type WooPaymentGatewaySetupProps = {
	id: string;
};
</file>

<file path="packages/js/onboarding/src/components/WooPaymentsMethodsLogos/index.tsx">
import { useState, useEffect, useRef } from 'react';
import { createElement } from '@wordpress/element';
import { Popover } from '@wordpress/components';
⋮----
import visa from '../../images/cards/visa.svg';
import mastercard from '../../images/cards/mastercard.svg';
import amex from '../../images/cards/amex.svg';
import discover from '../../images/cards/discover.svg';
import applepay from '../../images/cards/applepay.svg';
import googlepay from '../../images/cards/googlepay.svg';
import jcb from '../../images/cards/jcb.svg';
import cartebancaire from '../../images/cards/cb.svg';
import unionpay from '../../images/cards/unionpay.svg';
import diners from '../../images/cards/diners.svg';
import eftpos from '../../images/cards/eftpos.svg';
import woopay from '../../images/payment-methods/woopay.svg';
import afterpay from '../../images/payment-methods/afterpay.svg';
import affirm from '../../images/payment-methods/affirm.svg';
import klarna from '../../images/payment-methods/klarna.svg';
import ideal from '../../images/payment-methods/ideal.svg';
import bancontact from '../../images/payment-methods/bancontact.svg';
import eps from '../../images/payment-methods/eps.svg';
import becs from '../../images/payment-methods/becs.svg';
import przelewy24 from '../../images/payment-methods/przelewy24.svg';
import grabpay from '../../images/payment-methods/grabpay.svg';
⋮----
interface PaymentMethod {
	name: string;
	src: string;
	background?: string;
... (14 lines truncated)
</file>

<file path="packages/js/onboarding/src/components/SetupRequired.tsx">
import { createElement } from '@wordpress/element';
import NoticeOutlineIcon from 'gridicons/dist/notice-outline';
import { __ } from '@wordpress/i18n';
import { Text } from '@woocommerce/experimental';
</file>

<file path="packages/js/onboarding/src/utils/countries/index.ts">
import stringSimilarity from 'string-similarity';
⋮----
import { getMappingRegion } from './location-mapping';
⋮----
export type CountryStateOption = {
	key: string;
	label: string;
};
⋮----
export type Location = {
	country_short?: string;
	region?: string;
	city?: string;
};
⋮----
export const findCountryOption = (
	countryStateOptions: CountryStateOption[],
	location: Location | undefined,
	minimumSimilarity = 0.7
) =>
⋮----
/**
 * Returns just the country portion of a country:state string that is delimited with a colon.
 *
 * @param countryPossiblyWithState Country string that may or may not have a state. e.g 'US:CA', 'UG:UG312'
 * @return Just the country portion of the string, or undefined if input is undefined. e.g 'US', 'UG'
 */
export const getCountry = ( countryPossiblyWithState: string )
</file>

<file path="packages/js/onboarding/src/utils/countries/location-mapping.ts">
import { __ } from '@wordpress/i18n';
⋮----
import { Location } from '.';
⋮----
export const getMappingRegion = ( {
	country_short: countryCode,
	region = '',
	city = '',
}: Location ) =>
</file>

<file path="packages/js/onboarding/src/index.ts">

</file>

<file path="packages/js/onboarding/typings/custom.d.ts">

</file>

<file path="packages/js/onboarding/typings/global.d.ts">
import wpData from '@wordpress/data';
</file>

<file path="packages/js/onboarding/typings/index.d.ts">

</file>

<file path="packages/js/onboarding/typings/monorepo-enhancements.d.ts">

</file>

<file path="packages/js/onboarding/.npmrc">
package-lock=false
</file>

<file path="packages/js/onboarding/build.mjs">
// SVG imports are left untouched by the (non-bundling) transpile, so the
// asset files must be copied alongside the emitted modules.
</file>

<file path="packages/js/onboarding/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [4.0.0](https://www.npmjs.com/package/@woocommerce/onboarding/v/4.0.0) - 2026-06-11 

-   Major - Update @wordpress/* dependencies to WordPress 6.8 minimum. [#64114]
-   Major - Updated declared dependencies to React 18 and WordPress 6.6. [#53531]
-   Minor - Add a popover to WooPayments to present all possible payment methods. [#54404]
-   Minor - Add store location mismatch indicator to the Settings -> Payments NOX page. [#54638]
-   Minor - Branding updates to woocommerce payments welcome and payments task pages. [#54571]
-   Minor - Bump jest package dependency to 29.5.x. [#60324]
-   Minor - Fix the name of the Manawatu-Whanganui region. [#54231]
-   Minor - Improve build time for onboarding by using webpack filesystem cache. [#64082]
-   Minor - Improved the WooPaymentsMethodsLogos component to support provided breakpoints and number of methods shown for those. [#53900]
-   Minor - ISO Code update for Odisha state (India) [ISO 3166-2:IN](https://en.wikipedia.org/wiki/ISO_3166-2:IN) (23 November 2023). [#53341]
-   Minor - Monorepo: bump pnpm version to 9.15.0. [#54189]
-   Minor - Remove unused React imports. [#55554]
-   Minor - Replace Woopayments and WooPay logos with the new rebranded logos. [#54023]
-   Minor - Update storybook file format in support with Storybook 7 story indexer. [#51168]
-   Minor - Update the country Turkey to Türkiye. [#58436]
-   Minor - Update the list of supported payment methods in WooPayments to add GrabPay. [#57436]
-   Minor - Update the test step title when polling is happening to communicate progress to the merchant. [#58968]
-   Minor - Update tooltips on the Payments Settings page to work on click instead of hover. [#57856]
-   Minor - Upgraded TypeScript in the monorepo to 5.7.2. [#53165]
-   Patch - Add Escape key support to close the WooPaymentsMethodsLogos popover. [#62841]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - CI: leverage composer packages cache in lint monorepo job. [#52054]
-   Patch - Clean up CI job config options; remove unused cascading keys. [#55863]
-   Patch - Enhance Settings -> Payments NOX pages styling for mobile and tablet screens. [#54566]
... (98 lines truncated)
</file>

<file path="packages/js/onboarding/composer.json">
{
	"name": "woocommerce/onboarding",
	"description": "Onboarding utilities.",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/onboarding/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/onboarding/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/onboarding/package.json">
{
	"name": "@woocommerce/onboarding",
	"version": "4.0.0",
	"description": "Onboarding utilities.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"keywords": [
		"wordpress",
		"woocommerce",
		"onboarding"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/onboarding/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js"
		}
	},
	"module": "build-module/index.js",
... (110 lines truncated)
</file>

<file path="packages/js/onboarding/PREVIOUS_CHANGELOG.md">
# 3.0.1

-   Add missing dependency.

# 3.0.0

## Breaking changes

-   Update dependencies to support react 17. #8305
-   Drop support for IE11. #8305

# 2.2.2

-   Retry fix for missing build-module folder

# 2.2.1

-   Fix missing build-module folder

# 2.2.0

-   Update WCPayCard CSS to handle @wordpress/card updates. #7412

# 2.1.0

-   Fix commonjs module build, allow package to be built in isolation. #7286
-   Import createElement to fix build issues with SlotFill #7403

# 2.0.0

... (6 lines truncated)
</file>

<file path="packages/js/onboarding/README.md">
# Onboarding

A collection of onboarding related components and utilities.

> **Note:** This package is intended for internal WooCommerce use. It ships ESM only, and some components (e.g. the payment-method logos) import `.svg` assets, so it must be consumed through a bundler that resolves asset imports (as WooCommerce admin does via the `wc-source` export). It is not designed for plain Node consumption.

## Installation

Install the module

```bash
pnpm install @woocommerce/onboarding --save
```
</file>

<file path="packages/js/onboarding/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**",
		"**/stories/**"
	],
	"references": [
		{
			"path": "../components"
		},
		{
			"path": "../experimental"
		},
		{
... (8 lines truncated)
</file>

<file path="packages/js/onboarding/webpack.config.js">

</file>

<file path="packages/js/remote-logging/changelog/.gitkeep">

</file>

<file path="packages/js/remote-logging/changelog/consolidate-eslint-core-modules">
Significance: patch
Type: dev
Comment: Consolidate the shared `import/core-modules` list into `@woocommerce/eslint-config`. Tooling only; no runtime change.
</file>

<file path="packages/js/remote-logging/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/remote-logging/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/remote-logging/src/index.ts">

</file>

<file path="packages/js/remote-logging/src/remote-logger.ts">
import debugFactory from 'debug';
import { getSetting } from '@woocommerce/settings';
import TraceKit from 'tracekit';
import { applyFilters } from '@wordpress/hooks';
import { bumpStat } from '@woocommerce/tracks';
⋮----
import { mergeLogData, isDevelopmentEnvironment } from './utils';
import { LogData, ErrorData, RemoteLoggerConfig } from './types';
⋮----
const warnLog = ( message: string ) =>
const errorLog = ( message: string, ...args: unknown[] ) =>
⋮----
export const sanitiseRequestUriParams = ( search: string ) =>
⋮----
export class RemoteLogger
⋮----
public constructor( config: RemoteLoggerConfig )
⋮----
public async log(
		severity: Exclude< LogData[ 'severity' ], undefined >,
		message: string,
		extraData?: Partial< Exclude< LogData, 'message' | 'severity' > >
): Promise< boolean >
⋮----
public async error( error: Error, extraData?: Partial< LogData > )
⋮----
public initializeErrorHandlers(): void
⋮----
private async sendLog( logData: LogData ): Promise< boolean >
⋮----
... (43 lines truncated)
</file>

<file path="packages/js/remote-logging/src/types.ts">
export type RemoteLoggerConfig = {
	errorRateLimitMs: number;
};
⋮----
export type LogData = {
	message: string;
	feature?: string;
	severity?:
		| 'emergency'
		| 'alert'
		| 'critical'
		| 'error'
		| 'warning'
		| 'notice'
		| 'info'
		| 'debug';
	host?: string;
	extra?: unknown;
	tags?: string[];
	properties?: Record< string, unknown >;
};
⋮----
export type ErrorData = LogData & {
	trace: string;
};
</file>

<file path="packages/js/remote-logging/src/utils.ts">
import { LogData } from './types';
⋮----
export function mergeLogData( target: LogData, source: Partial< LogData > )
</file>

<file path="packages/js/remote-logging/typings/global.d.ts">
interface Window {
		wcSettings?: {
			isRemoteLoggingEnabled: boolean;
		}
	}
</file>

<file path="packages/js/remote-logging/typings/index.d.ts">
export declare function getAdminLink( path: string ): string;
export declare function getSetting< T >(
		name: string,
		fallback?: unknown,
		filter?: ( val: unknown, fb: unknown ) => unknown
	): T;
export declare function isWpVersion(
		version: string,
		operator: '>' | '>=' | '=' | '<' | '<='
	): boolean;
</file>

<file path="packages/js/remote-logging/.npmrc">
package-lock=false
</file>

<file path="packages/js/remote-logging/babel.config.js">

</file>

<file path="packages/js/remote-logging/build.mjs">

</file>

<file path="packages/js/remote-logging/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.0.0](https://www.npmjs.com/package/@woocommerce/remote-logging/v/2.0.0) - 2026-06-11 

-   Major - Update @wordpress/* dependencies to WordPress 6.8 minimum. [#64114]
-   Major - Updated declared dependencies to React 18 and WordPress 6.6. [#53531]
-   Minor - Bump jest package dependency to 29.5.x. [#60324]
-   Minor - Monorepo: bump pnpm version to 9.15.0. [#54189]
-   Minor - Upgraded TypeScript in the monorepo to 5.7.2. [#53165]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - CI: leverage composer packages cache in lint monorepo job. [#52054]
-   Patch - Clean up CI job config options; remove unused cascading keys. [#55863]
-   Patch - Monorepo: build RAM usage optimization. [#59046]
-   Patch - Monorepo: consolidate @babel/* dependencies versions across the monorepo. [#56575]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Monorepo: consolidate syncpack config around React 17/18 usage. [#52022]
-   Patch - Monorepo: consolidate TypeScript config files and JS test directories naming. [#52191]
-   Patch - Monorepo: drop the unused `concurrently` package from dependencies. [#58765]
-   Patch - Monorepo: refresh wireit dependencyOutputs configuration synchronization when installing dependencies. [#55095]
-   Patch - Move the CommonJS build to prepack so day-to-day development only builds the ESM output. [#64876]
-   Patch - Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking. [#65168]
-   Patch - Replaced patched `@wordpress/data` types with opt-in internal package types. [#63483]
-   Patch - Replaced wireit + tsc package build pipeline with a per-package esbuild script. [#65210]
-   Patch - Update wireit to 0.14.10. [#54996]

## [1.0.0](https://www.npmjs.com/package/@woocommerce/remote-logging/v/1.0.0) - 2024-09-09 

-   Patch - Fix wc asset url check [#50701]
... (12 lines truncated)
</file>

<file path="packages/js/remote-logging/composer.json">
{
	"name": "woocommerce/remote-logging",
	"description": "WooCommerce remote logger",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/remote-logging/eslint.config.mjs">
/**
 * External dependencies
 */
⋮----
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/remote-logging/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/remote-logging/package.json">
{
	"name": "@woocommerce/remote-logging",
	"version": "2.0.0",
	"description": "WooCommerce remote logging for Automattic based projects",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"keywords": [
		"wordpress",
		"woocommerce",
		"remote-logging"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/remote-logging/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
... (96 lines truncated)
</file>

<file path="packages/js/remote-logging/PREVIOUS_CHANGELOG.md">

</file>

<file path="packages/js/remote-logging/README.md">
# WooCommerce Remote Logging

A remote logging package for Automattic based projects. This package provides error tracking and logging capabilities, with support for rate limiting, stack trace formatting, and customizable error filtering.

## Installation

```bash
npm install @woocommerce/remote-logging --save
```

## Description

The WooCommerce Remote Logging package offers the following features:

- Remote error logging with stack trace analysis
- Customizable log severity levels
- Rate limiting to prevent API flooding
- Automatic capture of unhandled errors and promise rejections
- Filtering of errors based on WooCommerce asset paths
- Extensibility through WordPress filters

## Usage

1. Initialize the remote logger at the start of your application. If your plugin depends on WooCommerce plugin, the logger will be initialized in WooCommerce, so you don't need to call this function.

    ```js
    import { init } from '@woocommerce/remote-logging';

    init({
      errorRateLimitMs: 60000 // Set rate limit to 1 minute
... (169 lines truncated)
</file>

<file path="packages/js/remote-logging/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": [
		{
			"path": "../tracks"
		}
	]
}
</file>

<file path="packages/js/sanitize/changelog/.gitkeep">

</file>

<file path="packages/js/sanitize/changelog/63483-add-62921-shared-monorepo-ts-config">
Significance: patch
Type: dev

Replaced patched `@wordpress/data` types with opt-in internal package types.
</file>

<file path="packages/js/sanitize/changelog/64838-dev-esbuild-package-builds">
Significance: patch
Type: dev

Replaced wireit + tsc package build pipeline with a per-package esbuild script.
</file>

<file path="packages/js/sanitize/changelog/65662-dev-65627-postrelease-cleanup">
Significance: patch
Type: dev

Remove incorrect React peer dependencies; sanitize is a pure string sanitization utility with no React imports or JSX.
</file>

<file path="packages/js/sanitize/changelog/chore-remove-unused-wp-scripts-deps">
Significance: patch
Type: dev

Remove unused @wordpress/scripts devDependency and its dead webpack config.
</file>

<file path="packages/js/sanitize/changelog/dev-64837-type-check-only-on-lint">
Significance: patch
Type: dev

Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking.
</file>

<file path="packages/js/sanitize/changelog/dev-cjs-prepack-only">
Significance: patch
Type: dev

Move the CommonJS build to prepack so day-to-day development only builds the ESM output.
</file>

<file path="packages/js/sanitize/changelog/dev-update-dompurify-security">
Significance: patch
Type: dev

Update DOMPurify to fix reported security issues.
</file>

<file path="packages/js/sanitize/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/sanitize/src/index.ts">

</file>

<file path="packages/js/sanitize/src/noop-trusted-types-policy.ts">
import type { TrustedTypePolicy } from 'trusted-types';
⋮----
export type WooCommerceSanitizeNoopPolicyType = Pick<
	TrustedTypePolicy,
	'name' | 'createHTML'
>;
⋮----
export function getNoopTrustedTypesPolicy(): WooCommerceSanitizeNoopPolicyType | null
</file>

<file path="packages/js/sanitize/src/sanitize.ts">
import DOMPurify from 'dompurify';
⋮----
import { getNoopTrustedTypesPolicy } from './noop-trusted-types-policy';
⋮----
export type SanitizeReturnKind =
	| 'string'
	| 'HTMLBodyElement'
	| 'DocumentFragment';
⋮----
type ReturnTypeMap = {
	string: string;
	HTMLBodyElement: HTMLBodyElement;
	DocumentFragment: DocumentFragment;
};
⋮----
export type SanitizeReturnType = ReturnTypeMap[ keyof ReturnTypeMap ];
⋮----
export interface SanitizeConfig< T extends SanitizeReturnKind = 'string' > {
	tags?: readonly string[];
	attr?: readonly string[];
	returnType?: T;
}
⋮----
export function sanitizeHTML(
	html: string | null | undefined,
	config?: SanitizeConfig< 'string' >
): string;
export function sanitizeHTML(
	html: string | null | undefined,
	config: SanitizeConfig< 'HTMLBodyElement' >
... (15 lines truncated)
</file>

<file path="packages/js/sanitize/src/trusted-types-policy.ts">
import type { TrustedTypePolicy } from 'trusted-types';
⋮----
import { sanitizeHTML } from './sanitize';
⋮----
export type WooCommerceSanitizePolicyType = Pick<
	TrustedTypePolicy,
	'name' | 'createHTML'
>;
⋮----
export function getTrustedTypesPolicy(): WooCommerceSanitizePolicyType | null
</file>

<file path="packages/js/sanitize/build.mjs">

</file>

<file path="packages/js/sanitize/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.0](https://www.npmjs.com/package/@woocommerce/sanitize/v/1.0.0) - 2025-10-27 

-   Patch - prepares package for initial release
</file>

<file path="packages/js/sanitize/composer.json">
{
	"name": "woocommerce/sanitize",
	"description": "WooCommerce HTML sanitization utilities",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/sanitize/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/sanitize/package.json">
{
	"name": "@woocommerce/sanitize",
	"version": "1.0.0",
	"description": "WooCommerce HTML sanitization utilities.",
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
	"main": "build/index.js",
	"module": "build-module/index.js",
	"types": "build-types/index.d.ts",
	"files": [
		"build",
		"build-module",
		"build-style",
		"build-types"
	],
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git",
		"directory": "packages/js/sanitize"
	},
	"keywords": [
		"woocommerce",
		"sanitize",
		"dompurify",
... (91 lines truncated)
</file>

<file path="packages/js/sanitize/README.md">
# @woocommerce/sanitize

WooCommerce HTML sanitization utilities using DOMPurify with trusted types support.

## Features

- **Secure HTML Sanitization**: Uses DOMPurify to sanitize HTML content
- **Trusted Types Support**: Automatically configures trusted types policy to avoid conflicts
- **Configurable**: Supports custom allowed tags and attributes
- **TypeScript Support**: Full TypeScript definitions included

## Usage

### Basic HTML Sanitization

```typescript
import { sanitizeHTML } from '@woocommerce/sanitize';

const cleanHTML = sanitizeHTML('<p>Hello <script>alert("xss")</script> World!</p>');
// Returns: '<p>Hello World!</p>'
```

### React Integration

```javascript
import { sanitizeHTML } from '@woocommerce/sanitize';

function MyComponent( { content } ) {
  const sanitizedContent = {
    __html: sanitizeHTML( content )
... (52 lines truncated)
</file>

<file path="packages/js/sanitize/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"noCheck": false,
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": []
}
</file>

<file path="packages/js/settings-ui/changelog/add-settings-ui">
Significance: minor
Type: add

Add the settings UI package.
</file>

<file path="packages/js/settings-ui/changelog/add-shell-header-fields">
Significance: minor
Type: add

Add `subtitle` and `badges` fields to the settings UI shell, forwarded to the admin-ui Page header.
</file>

<file path="packages/js/settings-ui/changelog/add-wooprd-3595-dataform-adapter">
Significance: minor
Type: add

Add a DataForm adapter that maps the Settings UI schema to a single DataForm field list and form configuration.
</file>

<file path="packages/js/settings-ui/changelog/add-wpds-shell-components">
Significance: minor
Type: update

Render settings section cards with @wordpress/ui Card components.
</file>

<file path="packages/js/settings-ui/changelog/dev-mark-package-experimental">
Significance: patch
Type: dev

Mark the settings UI package as experimental in the README.
</file>

<file path="packages/js/settings-ui/changelog/fix-dataviews-17-wordpress-69-compatibility">
Significance: patch
Type: fix

Bundle DataForm 17.1.0 without private UI API dependencies so Settings UI loads on WordPress 6.9.
</file>

<file path="packages/js/settings-ui/changelog/fix-form-submit-navigation-guard">
Significance: patch
Type: fix

Keep Settings UI unsaved-changes protection enabled when the legacy settings form is missing.
</file>

<file path="packages/js/settings-ui/changelog/fix-preserve-download-links">
Significance: patch
Type: fix

Preserve download links when the Settings UI has unsaved changes.
</file>

<file path="packages/js/settings-ui/changelog/fix-preserve-wordpress-settings-behaviour">
Significance: patch
Type: fix

Identify current navigation links and preserve independently registered unload handlers in the Settings UI.
</file>

<file path="packages/js/settings-ui/changelog/fix-save-and-continue-navigation">
Significance: patch
Type: fix

Preserve Settings UI pending navigation after form-post saves.
</file>

<file path="packages/js/settings-ui/changelog/fix-wooprd-3593-missing-components">
Significance: patch
Type: fix

Fail closed while rendering a missing declared settings component without changing the public component resolver contract.
</file>

<file path="packages/js/settings-ui/changelog/fix-wooprd-3594-settings-value-boundary">
Significance: patch
Type: fix

Preserve legacy form names and typed visibility comparisons in the Settings UI.
</file>

<file path="packages/js/settings-ui/changelog/refactor-bounded-settings-ui-cleanup">
Significance: patch
Type: fix

Preserve unrelated settings extension registrations and disabled-field explanations, and simplify DataForm updates.
</file>

<file path="packages/js/settings-ui/changelog/refactor-settings-navigation-internals">
Significance: patch
Type: dev
Comment: Share settings navigation rendering and link inspection, and simplify storage of prebuilt DataForm group configuration.
</file>

<file path="packages/js/settings-ui/changelog/tweak-settings-ui-card-design">
Significance: patch
Type: tweak

Align Settings UI rendering with the settings card design.
</file>

<file path="packages/js/settings-ui/changelog/update-adopt-wpds-components">
Significance: minor
Type: update

Render the Settings UI shell and settings fields with WordPress Design System components.
</file>

<file path="packages/js/settings-ui/changelog/update-remove-group-actions">
Significance: minor
Type: update

Remove group header actions from the Settings UI schema.
</file>

<file path="packages/js/settings-ui/changelog/update-remove-woo-field-renderers">
Significance: minor
Type: update

Remove the Woo-owned field renderers now that Settings UI fields use DataForm controls.
</file>

<file path="packages/js/settings-ui/changelog/update-rename-settings-ui-package">
Significance: minor
Type: update

Rename the package from @woocommerce/settings-ui-sdk to @woocommerce/settings-ui.
</file>

<file path="packages/js/settings-ui/changelog/update-section-scope-semantics">
Significance: minor
Type: update

Clarify Settings UI extension section scoping so omitted sections are page-wide and empty sections target the default section.
</file>

<file path="packages/js/settings-ui/changelog/update-shell-header-top-level-pages">
Significance: minor
Type: update

Hide the shell header on top-level settings pages and render the save button at the bottom of the page. The header is opt-in via shell.header for drill-down pages.
</file>

<file path="packages/js/settings-ui/changelog/update-wooprd-3596-dataform-renderer">
Significance: minor
Type: update

Render Settings UI pages through DataForm. Registered settings components now receive the DataForm control props.
</file>

<file path="packages/js/settings-ui/changelog/update-wordpress-admin-ui">
Significance: patch
Type: dev

Update bundled WordPress admin UI dependencies for theme API compatibility.
</file>

<file path="packages/js/settings-ui/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/settings-ui/src/dataform-adapter.tsx">
import { createElement } from '@wordpress/element';
import type {
	Field,
	FieldTypeName,
	Form,
	FormField,
	Rules,
} from '@wordpress/dataviews';
⋮----
import { error } from './diagnostics';
import { createSettingsHelpElement, sanitizeSettingsHtml } from './html';
import {
	resolveFieldComponent,
	resolveFieldVisibilityPredicate,
	resolveGroupVisibilityPredicate,
} from './registry';
import type {
	SettingsFieldContext,
	SettingsUIField,
	SettingsUIGroup,
	SettingsUISchema,
	SettingsValues,
	SettingsVisibilityPredicate,
} from './types';
import { valueMatchesVisibilityRule } from './values';
⋮----
export type DataFormAdapterOptions = {
	schema: SettingsUISchema;
	context: SettingsFieldContext;
	initialValues: SettingsValues;
... (71 lines truncated)
</file>

<file path="packages/js/settings-ui/src/dataform-runtime.ts">
import type { DataForm as DataFormType } from '@wordpress/dataviews';
import { DataForm as DataFormRuntime } from '@wordpress/dataviews/wp';
</file>

<file path="packages/js/settings-ui/src/dataviews-wp.d.ts">

</file>

<file path="packages/js/settings-ui/src/diagnostics.ts">
const isDevelopment = () =>
⋮----
export const warn = ( message: string, context?: unknown ) =>
⋮----
export const error = ( message: string, context?: unknown ) =>
</file>

<file path="packages/js/settings-ui/src/hidden-inputs.tsx">
import { createElement, Fragment } from '@wordpress/element';
⋮----
import { error } from './diagnostics';
import type { SettingsUIField, SettingsValue } from './types';
import { areValuesEqual, toStoreLocalDateTime } from './values';
⋮----
type HiddenInput = {
	name: string;
	value: string;
};
⋮----
const getFieldName = ( field: SettingsUIField )
⋮----
const getArrayFieldName = ( name: string )
⋮----
const isSupportedFieldName = ( name: string, isArray: boolean ) =>
⋮----
const toRepeatedInputs = ( name: string, values: string[] ): HiddenInput[]
⋮----
const serializeCanonicalValue = (
	field: SettingsUIField,
	name: string,
	value: SettingsValue,
	serializeDateTimeAsStoreLocal: boolean
): HiddenInput[] =>
⋮----
const serializeOriginalFormValue = (
	name: string,
	value: string | string[]
): HiddenInput[]
... (22 lines truncated)
</file>

<file path="packages/js/settings-ui/src/html.ts">
import { sanitizeHTML } from '@woocommerce/sanitize';
import { createElement } from '@wordpress/element';
⋮----
export const sanitizeSettingsHtml = ( html?: string )
⋮----
export const createSettingsHelpElement = ( html?: string )
</file>

<file path="packages/js/settings-ui/src/index.ts">

</file>

<file path="packages/js/settings-ui/src/registry.ts">
import { warn } from './diagnostics';
import type {
	SettingsUIField,
	SettingsEditControl,
	SettingsExtensionRegistration,
	SettingsFieldContext,
	SettingsRegionComponent,
	SettingsSaveHandler,
	SettingsVisibilityPredicate,
} from './types';
⋮----
const isPlainRecord = ( value: unknown ): value is Record< string, unknown >
⋮----
const isValidRegistration = (
	registration: unknown
): registration is SettingsExtensionRegistration =>
⋮----
const hasSectionScope = ( scope: SettingsExtensionRegistration[ 'scope' ] )
⋮----
const scopeMatches = (
	registration: SettingsExtensionRegistration,
	context: SettingsFieldContext
) =>
⋮----
const findInMatchingRegistrations = < T >(
	context: SettingsFieldContext,
	getValue: ( registration: SettingsExtensionRegistration ) => T | undefined
): T | undefined =>
⋮----
const getScopeKey = ( scope: SettingsExtensionRegistration[ 'scope' ] )
... (34 lines truncated)
</file>

<file path="packages/js/settings-ui/src/settings-ui-page.tsx">
import { NavigableRegion } from '@wordpress/admin-ui';
import { Button, Modal, Notice } from '@wordpress/components';
import {
	Component,
	createElement,
	useCallback,
	useEffect,
	useMemo,
	useRef,
	useState,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import type { ErrorInfo, ReactNode } from 'react';
⋮----
import { createDataFormAdapter } from './dataform-adapter';
import { DataForm } from './dataform-runtime';
import { HiddenInputs } from './hidden-inputs';
import { error } from './diagnostics';
import { resolveRegionComponent, resolveSaveHandler } from './registry';
import type {
	SettingsUIField,
	SettingsUIShellBadgeIntent,
	SettingsUIShellNavigationItem,
	SettingsUISaveStrategy,
	SettingsUISchema,
	SettingsFieldContext,
	SettingsValue,
	SettingsValues,
} from './types';
import { areValuesEqual } from './values';
... (37 lines truncated)
</file>

<file path="packages/js/settings-ui/src/types.ts">
export type SettingsValue = string | number | boolean | string[] | null;
⋮----
export type SettingsValues = Record< string, SettingsValue >;
⋮----
export type SettingsUIOption = {
	label: string;
	value: string;
};
⋮----
export type SettingsUISaveAdapter =
	| 'form_post'
	| 'none'
	| ( string & NonNullable< unknown > );
⋮----
export type SettingsUISaveSchema = {
	adapter: SettingsUISaveAdapter;
	name?: string;
	initialValue?: string | string[];
};
⋮----
export type SettingsUISaveStrategy =
	| { adapter: 'form_post' }
	| { adapter: 'custom'; handler: string }
	| { adapter: 'none' }
	| { adapter: string & NonNullable< unknown >; handler?: string };
⋮----
export type SettingsUIVisibilityRule = {
	controller: string;
	value?: SettingsValue | SettingsValue[];
};
... (155 lines truncated)
</file>

<file path="packages/js/settings-ui/src/values.ts">
import { date } from '@wordpress/date';
⋮----
import type { SettingsValue } from './types';
⋮----
export const areValuesEqual = ( a: SettingsValue, b: SettingsValue ) =>
⋮----
export const valueMatchesVisibilityRule = (
	value: SettingsValue,
	expected: SettingsValue | SettingsValue[] | undefined
) =>
⋮----
export const toStoreLocalDateTime = ( value: SettingsValue ) =>
</file>

<file path="packages/js/settings-ui/build.mjs">

</file>

<file path="packages/js/settings-ui/jest.config.js">

</file>

<file path="packages/js/settings-ui/package.json">
{
	"name": "@woocommerce/settings-ui",
	"version": "0.1.0",
	"description": "React utilities for rendering extensible WooCommerce settings pages.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"keywords": [
		"wordpress",
		"woocommerce",
		"settings"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/settings-ui/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
	"main": "build/index.js",
	"module": "build-module/index.js",
	"types": "build-types/index.d.ts",
... (91 lines truncated)
</file>

<file path="packages/js/settings-ui/README.md">
# Settings UI

React utilities for WooCommerce settings pages that opt in to the settings UI renderer.

> **This package is experimental.** Until it is marked as stable, its API and the settings UI schema can change in backwards-incompatible ways in any release.

For the full integration guide, see [Settings UI](../../../docs/extensions/settings-and-config/settings-ui.md).

## Usage

PHP settings pages continue to register through `WC_Settings_Page`. A page opts in by returning a settings UI adapter from `get_settings_ui_page()`. The adapter provides the canonical schema, save adapter, and any script handles that must load before the React app mounts.

Custom JavaScript registers scoped components:

```ts
import { registerSettingsExtension } from '@woocommerce/settings-ui';
import { PaymentMethodPicker } from './payment-method-picker';

registerSettingsExtension( {
	scope: {
		page: 'my_plugin',
		section: 'payments',
	},
	components: {
		'my-plugin/payment-method-picker': PaymentMethodPicker,
	},
} );
```

Field schemas can then reference the registered component:
... (12 lines truncated)
</file>

<file path="packages/js/settings-ui/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"noCheck": false,
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": [
		{
			"path": "../sanitize"
		}
	]
}
</file>

<file path="packages/js/tracks/changelog/.gitkeep">

</file>

<file path="packages/js/tracks/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="packages/js/tracks/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev
Comment: Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="packages/js/tracks/src/index.ts">
import debug from 'debug';
⋮----
import { isDevelopmentMode } from './utils';
⋮----
export type ExtraProperties = {
	[ key: string ]: unknown;
};
⋮----
const isRecordEventArgs = (
	args: unknown[]
): args is [ string, ExtraProperties | undefined ] =>
⋮----
export function recordEvent(
	eventName: string,
	eventProperties?: ExtraProperties
)
⋮----
localStorageKey()
⋮----
clear()
⋮----
get()
⋮----
add( ...args: unknown[] )
⋮----
process()
⋮----
export function queueRecordEvent(
	eventName: string,
	eventProperties?: ExtraProperties
... (7 lines truncated)
</file>

<file path="packages/js/tracks/src/stats.ts">
import debug from 'debug';
⋮----
import { isDevelopmentMode } from './utils';
⋮----
function buildQueryParams(
	group: Record< string, string > | string,
	name: string
): URLSearchParams
⋮----
export function bumpStat(
	group: Record< string, string > | string,
	name = ''
): boolean
</file>

<file path="packages/js/tracks/src/utils.js">

</file>

<file path="packages/js/tracks/typings/global.d.ts">
interface Window {
		wcTracks: {
			isEnabled: boolean;
			validateEvent: (
				name: string,
				properties: unknown,
			) => void;
			recordEvent: (
				name: string,
				properties: unknown,
			) => void;
		};
		_tkq: {
			[key: string]: number;
		}
	}
</file>

<file path="packages/js/tracks/.npmrc">
package-lock=false
</file>

<file path="packages/js/tracks/build.mjs">

</file>

<file path="packages/js/tracks/CHANGELOG.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.5.1](https://www.npmjs.com/package/@woocommerce/tracks/v/1.5.1) - 2026-06-10 

-   Patch - Move the CommonJS build to prepack so day-to-day development only builds the ESM output. [#64876]
-   Patch - Move TypeScript type-checking from the build to a new `lint:lang:types` script. Builds now emit types and JS without type-checking. [#65168]
-   Patch - Replaced patched `@wordpress/data` types with opt-in internal package types. [#63483]
-   Patch - Replaced wireit + tsc package build pipeline with a per-package esbuild script. [#65210]

## [1.5.0](https://www.npmjs.com/package/@woocommerce/tracks/v/1.5.0) - 2026-02-23 

-   Minor - Add bumpStats and fix unit test tooling [#50155]
-   Patch - Comment: Fix some comment typos. [#50993]
-   Minor - Bump jest package dependency to 29.5.x [#60324]
-   Patch - Bump wireit dependency version to latest. [#57299]
-   Patch - CI: liverage composer packages cache in lint monorepo job [#52054]
-   Patch - Fix pnpm version to 9.1.3 to avoid dependency installation issues. [#50828]
-   Patch - Loosens the Node.js engine constraint. [#63406]
-   Patch - Monorepo: build RAM usage optimization. [#59046]
-   Minor - Monorepo: bump pnpm version to 9.15.0 [#54189]
-   Patch - Monorepo: consolidate @babel/* dependencies versions across the monorepo. [#56575]
-   Patch - Monorepo: consolidate packages licenses to `GPL-2.0-or-later`. [#58941]
-   Patch - Monorepo: consolidate syncpack config around React 17/18 usage. [#52022]
-   Patch - Monorepo: consolidate TypeScript config files and JS test directories naming. [#52191]
-   Patch - Monorepo: drop the unused `concurrently` package from dependencies. [#58765]
-   Patch - Monorepo: refresh wireit dependencyOutputs configuration synchronization when installing dependencies. [#55095]
-   Patch - Update wireit to 0.14.10 [#54996]
-   Minor - Upgraded Typescript in the monorepo to 5.7.2 [#53165]
... (30 lines truncated)
</file>

<file path="packages/js/tracks/composer.json">
{
	"name": "woocommerce/tracks",
	"description": "WooCommerce user event tracking utilities for Automattic based projects.",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
				"enhancement": "Improve existing functionality"
			},
			"changelog": "CHANGELOG.md"
		}
... (3 lines truncated)
</file>

<file path="packages/js/tracks/eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="packages/js/tracks/jest.config.json">
{
	"rootDir": "./",
	"roots": [
		"<rootDir>/src"
	],
	"preset": "./node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}
</file>

<file path="packages/js/tracks/package.json">
{
	"name": "@woocommerce/tracks",
	"version": "1.5.1",
	"description": "WooCommerce user event tracking utilities for Automattic based projects.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"keywords": [
		"wordpress",
		"woocommerce",
		"tracks"
	],
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/tracks/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"exports": {
		".": {
			"wc-source": "./src/index.ts",
			"types": "./build-types/index.d.ts",
			"import": "./build-module/index.js",
			"require": "./build/index.js"
		}
	},
... (75 lines truncated)
</file>

<file path="packages/js/tracks/PREVIOUS_CHANGELOG.md">
# 1.1.1

-   Update all js packages with minor/patch version changes. #8392

# 1.1.0

-   Fix commonjs module build, allow package to be built in isolation. #7286

# 1.0.1

-   Update dependencies.
-   Add TypeScript support.

# 1.0.0

-   Released package
</file>

<file path="packages/js/tracks/README.md">
# Tracks

WooCommerce user event tracking utilities for Automattic based projects.

## Installation

Install the module

```bash
pnpm install @woocommerce/tracks --save
```

## Usage

The store must opt-in to allow tracking via the `woocommerce_allow_tracking` setting. 
If the store is not opted-in no events be recorded when using the following functions.

### recordEvent( eventName, eventProperties )

Record a user event to Tracks.

```jsx
import { recordEvent } from '@woocommerce/tracks';

recordEvent( 'page_view', { path } )
```

| Param | Type | Description |
| --- | --- | --- |
| eventName | `String` | The name of the event to record, don't include the `wcadmin_` prefix |
... (58 lines truncated)
</file>

<file path="packages/js/tracks/tsconfig.json">
{
	"extends": "@woocommerce/internal-build/configs/tsconfig.json",
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "build-module",
		"declaration": true,
		"declarationMap": true,
		"declarationDir": "./build-types",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"typings/**/*",
		"src/**/*"
	],
	"exclude": [
		"**/test/**"
	],
	"references": []
}
</file>

<file path="packages/js/CLAUDE.md">
# Claude Code Documentation for WooCommerce JS Packages

**Location**: `packages/js/`

## Changelog Quick Reference

**Add entry for EVERY functional change to a package.**

```bash
# Quick add (interactive)
cd packages/js/[package-name]
pnpm changelog add

# Manual creation
# Create: packages/js/[package-name]/changelog/[type-brief-description]
# Format:
Significance: <patch|minor|major>
Type: <type>

<One-line description of the change>
```

**Significance (Semver):**

- `patch` → Bug fixes, no API changes (0.0.X)
- `minor` → New features, non-breaking (0.X.0)
- `major` → Breaking changes (X.0.0)

**Type:**

... (82 lines truncated)
</file>

<file path="packages/js/README.md">
# WooCommerce Packages

Currently we have a set of public-facing packages that can be downloaded from [npm](https://www.npmjs.com/org/woocommerce) and used in external applications. Here is a non-exhaustive list.

- `@woocommerce/components`: A library of components that can be used to create pages in the WooCommerce dashboard and reports pages.
- `@woocommerce/csv-export`: A set of functions to convert data into CSV values, and enable a browser download of the CSV data.
- `@woocommerce/currency`: A class to display and work with currency values.
- `@woocommerce/date`: A collection of utilities to display and work with date values.
- `@woocommerce/navigation`: A collection of navigation-related functions for handling query parameter objects, serializing query parameters, updating query parameters, and triggering path changes.
- `@woocommerce/tracks`: User event tracking utility functions for Automattic based projects.

## Working with existing packages

- You can make changes to packages files as normal, and running `pnpm start` will compile and watch both app files and packages.
- :warning: Add any dependencies to a package using `pnpm add` from the package root.
- :warning: Make sure you're not importing from any other files outside of the package (you can import from other packages, just use the `import from @woocommerce/package` syntax).
- Don't change the version in `package.json`.
- Label your PR with the `Packages` label.
- See the [Package Release Tool](https://github.com/woocommerce/woocommerce/blob/f9e7a5a3fb11cdd4dc064c02e045cf429cb6a2b6/tools/package-release/README.md) for instructions on how to release packages.

---

## Creating a new package

Most of this is pulled [from the Gutenberg workflow](https://github.com/WordPress/gutenberg/blob/trunk/CONTRIBUTING.md#creating-new-package).

To create a new package, add a new folder to `/packages`, containing…

1. `package.json` based on the template:

... (47 lines truncated)
</file>

<file path="packages/js/tsconfig-cjs.json">
{
	"extends": "./tsconfig",
	"compilerOptions": {
		"module": "commonjs",
		"declaration": false,
		"declarationMap": false,
		"declarationDir": null,
		"outDir": "build",
		"typeRoots": [ "./typings" ]
	}
}
</file>

<file path="packages/js/tsconfig.json">
{
	"compilerOptions": {
		"target": "esnext",
		"module": "esnext",
		"moduleResolution": "node",
		"allowJs": true,
		"strict": true,
		"esModuleInterop": true,
		"skipLibCheck": true,
		"jsx": "react",
		"jsxFactory": "createElement",
		"jsxFragmentFactory": "Fragment",
		"typeRoots": [ "./typings" ]
	},
	"exclude": [
		"node_modules",
		"**/stories",
		"**/build",
		"**/build-module",
		"**/build-types",
		"**/build-style",
		"**/jest.config.js",
		"**/jest-preset.js",
		"**/webpack.*.js",
		"**/babel.config.js"
	],

	"include": [ "typings/**/*", "src/**/*" ]
}
</file>

<file path="packages/php/blueprint/changelog/57219-update-remove-zip-feature-from-blueprint">
Significance: patch
Type: update

Removing blueprint ZIP export functionality and related classes.
</file>

<file path="packages/php/blueprint/changelog/57294-wooplug-2482-feature-blueprint-require-permission-based-on-the-steps">
Significance: patch
Type: enhancement

Add permission validation for import steps
</file>

<file path="packages/php/blueprint/changelog/57299-fix-wireit-in-ci">
Significance: patch
Type: dev

Bump wireit dependency version to latest.
</file>

<file path="packages/php/blueprint/changelog/57842-dev-blueprint-install-path">
Significance: patch
Type: dev

Move blueprint package to plugins/woocommerce/packages and enable core watch to sync directory changes.
</file>

<file path="packages/php/blueprint/changelog/57935-update-blueprint-docs">
Significance: patch
Type: dev

Update blueprint docs
</file>

<file path="packages/php/blueprint/changelog/58755-dev-53714">
Significance: patch
Type: dev
Comment: Bumped PHP version to 8.1
</file>

<file path="packages/php/blueprint/changelog/58792-update-blueprint-doc-exporter-ui">
Significance: patch
Type: dev

Update Blueprint doc to clarify limitations of custom exporters
</file>

<file path="packages/php/blueprint/changelog/58941-dev-consolidate-packages-license-version">
Significance: patch
Type: dev

Monorepo: consolidate packages licenses to `GPL-2.0-or-later`.
</file>

<file path="packages/php/blueprint/changelog/59411-add-57846">
Significance: minor
Type: add

Log warning when imported option value is overridden by hooks during Blueprint import
</file>

<file path="packages/php/blueprint/changelog/61753-fix-support-composer-update">
Significance: major
Type: update

Updated all PHP dependencies.
</file>

<file path="packages/php/blueprint/changelog/66097-bump-wp-env-and-playwright">
Significance: patch
Type: dev
Comment: Bump @wordpress/env to 11.9.0 and @playwright/test to 1.61.1 (dev dependencies; no merchant-facing change).
</file>

<file path="packages/php/blueprint/changelog/dev-fix-blueprint-package-setup">
Significance: patch
Type: dev

Update Blueprint package configuration and fix lint errors
</file>

<file path="packages/php/blueprint/changelog/fix-blueprint-autoload">
Significance: patch
Type: dev
Comment: Fix failed opening required `blueprint/tests/stubs/stubs.php`
</file>

<file path="packages/php/blueprint/changelog/fix-blueprint-setup-tests">
Significance: patch
Type: dev
Comment: Fix tests and use .gitattributes to prevent dev files from being included
</file>

<file path="packages/php/blueprint/changelog/fix-wooplug-6319-blueprint-import-table-prefix">
Significance: patch
Type: fix

Resolve the table prefix placeholder in runSql steps to the importing site's database prefix, so Blueprints exported from a site with a different prefix import correctly.
</file>

<file path="packages/php/blueprint/changelog/improve-blueprint-validation">
Significance: patch
Type: enhancement

Improve schema/filter validation
</file>

<file path="packages/php/blueprint/changelog/remove-unused-blueprint-steps">
Significance: patch
Type: update

Remove deactivation and deletion steps for plugins
</file>

<file path="packages/php/blueprint/changelog/resync-composer-locks">
Significance: patch
Type: dev

Update Composer dependencies and pin platform PHP to 7.4 for reproducible resolution.
</file>

<file path="packages/php/blueprint/changelog/update-blueprint-require-permission-exporters-api">
Significance: patch
Type: enhancement

Add permission validation for export steps and REST API
</file>

<file path="packages/php/blueprint/changelog/update-php-dev-dependency-security-patches">
Significance: patch
Type: dev

Update PHP development dependencies to versions that resolve reported security advisories.
</file>

<file path="packages/php/blueprint/changelog/update-wpcs-3-4-1">
Significance: patch
Type: dev

Update wp-coding-standards/wpcs to 3.4.1 (security release).
</file>

<file path="packages/php/blueprint/changelog/woo6-10-blueprints-security-audit-determine-the-scope-of-allowed-sql">
Significance: patch
Type: enhancement

Enhance SQL execution safety in ImportRunSql class
</file>

<file path="packages/php/blueprint/changelog/woo6-96-fix-restricted-options-case-bypass">
Significance: patch
Type: fix

Match Blueprint's restricted site options regardless of the casing, padding or accents used in the imported key.
</file>

<file path="packages/php/blueprint/changelog/woo6-97-update-runsql-trust-boundary-docs">
Significance: patch
Type: update

Document that the runSql step's query checks are not a security boundary, and warn WP-CLI users before a Blueprint is imported.
</file>

<file path="packages/php/blueprint/changelog/wooplug-3933-fix-blueprint-type-warnings-and-improve-error-handling">
Significance: patch
Type: fix

Fix blueprint php warnings and improve error handling
</file>

<file path="packages/php/blueprint/changelog/wooplug-3946-blueprint-centralized-audit-logging">
Significance: patch
Type: add

Implement logging functionality in ExportSchema and ImportStep classes
</file>

<file path="packages/php/blueprint/changelog/wooplug-3964-blueprint-protect-critical-options">
Significance: patch
Type: enhancement

Implement restricted options handling in ImportSetSiteOptions
</file>

<file path="packages/php/blueprint/src/Cli/ExportCli.php">
namespace Automattic\WooCommerce\Blueprint\Cli;
⋮----
use Automattic\WooCommerce\Blueprint\ExportSchema;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ExportCli {
⋮----
private string $save_to;
⋮----
public function __construct( $save_to ) {
⋮----
public function run( $args = array() ) {
⋮----
$result = $exporter->export( $args['steps'] );
⋮----
\WP_CLI::error( $result->get_error_message() );
⋮----
$is_saved = $this->wp_filesystem_put_contents( $this->save_to, wp_json_encode( $result, JSON_PRETTY_PRINT ) );
⋮----
\WP_CLI::error( "Failed to save to {$this->save_to}" );
⋮----
\WP_CLI::success( "Exported JSON to {$this->save_to}" );
</file>

<file path="packages/php/blueprint/src/Cli/ImportCli.php">
namespace Automattic\WooCommerce\Blueprint\Cli;
⋮----
use Automattic\WooCommerce\Blueprint\ImportSchema;
use Automattic\WooCommerce\Blueprint\ResultFormatters\CliResultFormatter;
⋮----
class ImportCli {
⋮----
private $schema_path;
⋮----
public function __construct( $schema_path ) {
⋮----
public function run( $optional_args ) {
⋮----
$blueprint = ImportSchema::create_from_file( $this->schema_path );
⋮----
\WP_CLI::error( $e->getMessage() );
⋮----
\WP_CLI::warning( 'A Blueprint imported with WP-CLI can change anything this command can access on the site — including data that is not described in the file. Only import files from a source you trust.' );
\WP_CLI::confirm( 'Do you want to continue?', $optional_args );
⋮----
$results = $blueprint->import();
⋮----
$is_success       = $result_formatter->is_success();
⋮----
$result_formatter->format( $optional_args['show-messages'] );
⋮----
\WP_CLI::success( "$this->schema_path imported successfully" );
⋮----
\WP_CLI::error( "Failed to import $this->schema_path. Run with --show-messages=all to debug" );
</file>

<file path="packages/php/blueprint/src/docs/json-examples/activatePlugin.json">
{
  "step": "activatePlugin",
  "pluginName": "woocommerce"
}
</file>

<file path="packages/php/blueprint/src/docs/json-examples/installPlugin.json">
{
  "step": "installPlugin",
  "pluginZipFile": {
	"resource": "wordpress.org/plugins",
	"slug": "akismet"
  },
  "options": {
	"activate": true
  }
}
</file>

<file path="packages/php/blueprint/src/docs/json-examples/installTheme.json">
{
  "step": "installTheme",
  "themeZipFile": {
	"resource": "wordpress.org/themes",
	"slug": "twentytwenty"
  },
  "options": {
	"activate": true
  }
}
</file>

<file path="packages/php/blueprint/src/docs/json-examples/setSiteOptions.json">
{
  "step": "setSiteOptions",
  "options": {
    "woocommerce_allow_tracking": true
  }
}
</file>

<file path="packages/php/blueprint/src/Exporters/ExportInstallPluginSteps.php">
namespace Automattic\WooCommerce\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\Steps\InstallPlugin;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ExportInstallPluginSteps implements StepExporter {
⋮----
private $filter_callback;
⋮----
private bool $include_private_plugins = false;
⋮----
public function include_private_plugins( bool $boolean ) {
⋮----
public function filter( callable $callback ) {
⋮----
public function export() {
$plugins = $this->sort_plugins_by_dep( $this->wp_get_plugins() );
⋮----
$info = $this->wp_plugins_api(
⋮----
public function sort_plugins_by_dep( array $plugins ) {
⋮----
// Recursive function for topological sort.
⋮----
$visit( $dependency_key );
⋮----
$visit( $plugin_key );
⋮----
public function get_step_name() {
return InstallPlugin::get_step_name();
... (3 lines truncated)
</file>

<file path="packages/php/blueprint/src/Exporters/ExportInstallThemeSteps.php">
namespace Automattic\WooCommerce\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\Steps\InstallTheme;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ExportInstallThemeSteps implements StepExporter {
⋮----
private $filter_callback;
⋮----
public function filter( callable $callback ) {
⋮----
public function export() {
⋮----
$themes = $this->wp_get_themes();
⋮----
$active_theme = $this->wp_get_theme();
⋮----
$is_active = $theme->get( 'Name' ) === $active_theme->get( 'Name' );
⋮----
$info = $this->wp_themes_api(
⋮----
public function get_step_name() {
return InstallTheme::get_step_name();
⋮----
public function check_step_capabilities(): bool {
</file>

<file path="packages/php/blueprint/src/Exporters/HasAlias.php">
namespace Automattic\WooCommerce\Blueprint\Exporters;
⋮----
interface HasAlias {
⋮----
public function get_alias();
</file>

<file path="packages/php/blueprint/src/Exporters/StepExporter.php">
namespace Automattic\WooCommerce\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\Steps\Step;
⋮----
interface StepExporter {
⋮----
public function export();
⋮----
public function get_step_name();
⋮----
public function check_step_capabilities(): bool;
</file>

<file path="packages/php/blueprint/src/Importers/ImportActivatePlugin.php">
namespace Automattic\WooCommerce\Blueprint\Importers;
⋮----
use Automattic\WooCommerce\Blueprint\StepProcessor;
use Automattic\WooCommerce\Blueprint\StepProcessorResult;
use Automattic\WooCommerce\Blueprint\Steps\ActivatePlugin;
use Automattic\WooCommerce\Blueprint\UsePluginHelpers;
⋮----
class ImportActivatePlugin implements StepProcessor {
⋮----
public function process( $schema ): StepProcessorResult {
$result = StepProcessorResult::success( ActivatePlugin::get_step_name() );
⋮----
$activate = $this->wp_activate_plugin( $plugin_path );
⋮----
if ( $this->is_wp_error( $activate ) ) {
$result->add_error( "Unable to activate {$plugin_path}." );
⋮----
$result->add_info( "Activated {$plugin_path}." );
⋮----
public function get_step_class(): string {
⋮----
public function check_step_capabilities( $schema ): bool {
</file>

<file path="packages/php/blueprint/src/Importers/ImportActivateTheme.php">
namespace Automattic\WooCommerce\Blueprint\Importers;
⋮----
use Automattic\WooCommerce\Blueprint\StepProcessor;
use Automattic\WooCommerce\Blueprint\StepProcessorResult;
use Automattic\WooCommerce\Blueprint\Steps\ActivateTheme;
use Automattic\WooCommerce\Blueprint\UsePluginHelpers;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ImportActivateTheme implements StepProcessor {
⋮----
public function process( $schema ): StepProcessorResult {
$result = StepProcessorResult::success( ActivateTheme::get_step_name() );
⋮----
$this->wp_switch_theme( $name );
⋮----
$current_theme = $this->wp_get_theme()->get_stylesheet();
⋮----
$result->add_debug( "Switched theme to '$name'." );
⋮----
public function get_step_class(): string {
⋮----
public function check_step_capabilities( $schema ): bool {
</file>

<file path="packages/php/blueprint/src/Importers/ImportInstallPlugin.php">
namespace Automattic\WooCommerce\Blueprint\Importers;
⋮----
use Automattic\WooCommerce\Blueprint\ResourceStorages;
use Automattic\WooCommerce\Blueprint\StepProcessor;
use Automattic\WooCommerce\Blueprint\StepProcessorResult;
use Automattic\WooCommerce\Blueprint\Steps\InstallPlugin;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
use Plugin_Upgrader;
⋮----
class ImportInstallPlugin implements StepProcessor {
⋮----
private ResourceStorages $storage;
⋮----
private array $installed_plugin_paths = array();
⋮----
public function __construct( ResourceStorages $storage ) {
⋮----
public function process( $schema ): StepProcessorResult {
$result = StepProcessorResult::success( InstallPlugin::get_step_name() );
⋮----
$installed_plugins = $this->get_installed_plugins_paths();
⋮----
$result->add_info( "Skipped installing a plugin. Unsupported resource type. Only 'wordpress.org/plugins' is supported at the moment." );
⋮----
$result->add_info( "Skipped installing {$plugin->slug}. It is already installed." );
⋮----
if ( $this->storage->is_supported_resource( $plugin->resource ) === false ) {
$result->add_error( "Invalid resource type for {$plugin->slug}." );
⋮----
$downloaded_path = $this->storage->download( $plugin->slug, $plugin->resource );
... (34 lines truncated)
</file>

<file path="packages/php/blueprint/src/Importers/ImportInstallTheme.php">
namespace Automattic\WooCommerce\Blueprint\Importers;
⋮----
use Automattic\WooCommerce\Blueprint\ResourceStorages;
use Automattic\WooCommerce\Blueprint\StepProcessor;
use Automattic\WooCommerce\Blueprint\StepProcessorResult;
use Automattic\WooCommerce\Blueprint\Steps\InstallTheme;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ImportInstallTheme implements StepProcessor {
⋮----
private ResourceStorages $storage;
⋮----
private StepProcessorResult $result;
⋮----
public function __construct( ResourceStorages $storage ) {
$this->result  = StepProcessorResult::success( InstallTheme::get_step_name() );
⋮----
public function process( $schema ): StepProcessorResult {
$installed_themes = $this->wp_get_themes();
⋮----
$this->result->add_info( "Skipped installing a theme. Unsupported resource type. Only 'wordpress.org/themes' is supported at the moment." );
⋮----
$schema->options = new \stdClass();
⋮----
$this->activate_theme( $schema );
$this->result->add_info( "Skipped installing {$theme->slug}. It is already installed." );
⋮----
if ( $this->storage->is_supported_resource( $theme->resource ) === false ) {
$this->result->add_error( "Invalid resource type for {$theme->slug}" );
⋮----
... (30 lines truncated)
</file>

<file path="packages/php/blueprint/src/Importers/ImportRunSql.php">
namespace Automattic\WooCommerce\Blueprint\Importers;
⋮----
use Automattic\WooCommerce\Blueprint\StepProcessor;
use Automattic\WooCommerce\Blueprint\StepProcessorResult;
use Automattic\WooCommerce\Blueprint\Steps\RunSql;
use Automattic\WooCommerce\Blueprint\UsePluginHelpers;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ImportRunSql implements StepProcessor {
⋮----
public function process( $schema ): StepProcessorResult {
⋮----
$result = StepProcessorResult::success( RunSql::get_step_name() );
⋮----
if ( ! $this->is_allowed_query_type( $sql ) ) {
$result->add_error(
⋮----
if ( $this->contains_suspicious_comments( $sql ) ) {
$result->add_error( 'SQL query contains suspicious comment patterns.' );
⋮----
if ( $this->contains_sql_injection_patterns( $sql ) ) {
$result->add_error( 'SQL query contains potential injection patterns.' );
⋮----
if ( $this->affects_protected_tables( $sql ) ) {
$result->add_error( 'Modifications to admin users or roles are not allowed.' );
⋮----
if ( $this->affects_user_capabilities( $sql ) ) {
$result->add_error( 'Modifications to user roles or capabilities are not allowed.' );
⋮----
$wpdb->suppress_errors( true );
... (26 lines truncated)
</file>

<file path="packages/php/blueprint/src/Importers/ImportSetSiteOptions.php">
namespace Automattic\WooCommerce\Blueprint\Importers;
⋮----
use Automattic\WooCommerce\Blueprint\StepProcessor;
use Automattic\WooCommerce\Blueprint\StepProcessorResult;
use Automattic\WooCommerce\Blueprint\Steps\SetSiteOptions;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ImportSetSiteOptions implements StepProcessor {
⋮----
public function process( $schema ): StepProcessorResult {
$result                  = StepProcessorResult::success( SetSiteOptions::get_step_name() );
$restricted_option_names = $this->get_restricted_option_names( array_keys( (array) $schema->options ) );
⋮----
$result->add_warn( "Cannot modify '{$key}' option: Modifying is restricted for this key." );
⋮----
$updated       = $this->wp_update_option( $key, $value );
$current_value = $this->wp_get_option( $key );
⋮----
$result->add_warn( "{$key} was intended to be set, but the stored value may have been overridden by a hook." );
⋮----
$result->add_info( "{$key} has been updated." );
⋮----
$result->add_info( "{$key} has not been updated because the current value is already up to date." );
⋮----
private function get_restricted_option_names( array $keys ): array {
⋮----
if ( in_array( self::normalize_option_name( $key ), self::RESTRICTED_OPTIONS, true ) ) {
⋮----
foreach ( $this->get_collation_restricted_option_indexes( $candidate_names ) as $candidate_index ) {
⋮----
... (10 lines truncated)
</file>

<file path="packages/php/blueprint/src/ResourceStorages/LocalPluginResourceStorage.php">
namespace Automattic\WooCommerce\Blueprint\ResourceStorages;
⋮----
class LocalPluginResourceStorage implements ResourceStorage {
⋮----
protected array $paths = array();
⋮----
protected string $suffix = 'plugins';
⋮----
public function __construct( $path ) {
⋮----
public function download( $slug ): ?string {
⋮----
public function get_supported_resource(): string {
</file>

<file path="packages/php/blueprint/src/ResourceStorages/LocalThemeResourceStorage.php">
namespace Automattic\WooCommerce\Blueprint\ResourceStorages;
⋮----
class LocalThemeResourceStorage extends LocalPluginResourceStorage {
⋮----
protected string $suffix = 'themes';
⋮----
public function get_supported_resource(): string {
</file>

<file path="packages/php/blueprint/src/ResourceStorages/OrgPluginResourceStorage.php">
namespace Automattic\WooCommerce\Blueprint\ResourceStorages;
⋮----
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class OrgPluginResourceStorage implements ResourceStorage {
⋮----
public function download( $slug ): ?string {
$download_link = $this->get_download_link( $slug );
⋮----
$result = $this->download_url( $download_link );
⋮----
protected function download_url( $url ) {
return $this->wp_download_url( $url );
⋮----
protected function get_download_link( $slug ): ?string {
$info = $this->wp_plugins_api(
⋮----
public function get_supported_resource(): string {
</file>

<file path="packages/php/blueprint/src/ResourceStorages/OrgThemeResourceStorage.php">
namespace Automattic\WooCommerce\Blueprint\ResourceStorages;
⋮----
class OrgThemeResourceStorage extends OrgPluginResourceStorage {
⋮----
protected function get_download_link( $slug ): ?string {
$info = $this->wp_themes_api(
⋮----
public function get_supported_resource(): string {
</file>

<file path="packages/php/blueprint/src/ResourceStorages/ResourceStorage.php">
namespace Automattic\WooCommerce\Blueprint\ResourceStorages;
⋮----
interface ResourceStorage {
⋮----
public function get_supported_resource(): string;
⋮----
public function download( $slug ): ?string;
</file>

<file path="packages/php/blueprint/src/ResultFormatters/CliResultFormatter.php">
namespace Automattic\WooCommerce\Blueprint\ResultFormatters;
⋮----
use Automattic\WooCommerce\Blueprint\StepProcessorResult;
use function WP_CLI\Utils\format_items;
⋮----
class CliResultFormatter {
⋮----
private array $results;
⋮----
public function __construct( array $results ) {
⋮----
public function format( $message_type = 'debug' ) {
⋮----
$step_name = $result->get_step_name();
foreach ( $result->get_messages( $message_type ) as $message ) {
⋮----
throw new \Exception( 'WP CLI Utils not found' );
⋮----
public function is_success() {
⋮----
$is_success = $result->is_success();
</file>

<file path="packages/php/blueprint/src/ResultFormatters/JsonResultFormatter.php">
namespace Automattic\WooCommerce\Blueprint\ResultFormatters;
⋮----
use Automattic\WooCommerce\Blueprint\StepProcessorResult;
⋮----
class JsonResultFormatter {
⋮----
private array $results;
⋮----
public function __construct( array $results ) {
⋮----
public function format( $message_type = 'all' ) {
⋮----
'is_success' => $this->is_success(),
⋮----
$step_name = $result->get_step_name();
foreach ( $result->get_messages( $message_type ) as $message ) {
⋮----
public function is_success() {
⋮----
$is_success = $result->is_success();
</file>

<file path="packages/php/blueprint/src/Schemas/JsonSchema.php">
namespace Automattic\WooCommerce\Blueprint\Schemas;
⋮----
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class JsonSchema {
⋮----
protected $schema;
⋮----
public function __construct( $json_path ) {
⋮----
throw new \InvalidArgumentException( 'Invalid schema path' );
⋮----
$contents = $this->wp_filesystem_get_contents( $real_path );
⋮----
throw new \RuntimeException( "Failed to read the JSON file at {$real_path}." );
⋮----
if ( ! $this->validate() ) {
throw new \InvalidArgumentException( "Invalid JSON or missing 'steps' field." );
⋮----
public function get_steps() {
⋮----
public function get_step( $name ) {
⋮----
public function validate() {
</file>

<file path="packages/php/blueprint/src/Steps/ActivatePlugin.php">
namespace Automattic\WooCommerce\Blueprint\Steps;
⋮----
class ActivatePlugin extends Step {
⋮----
private string $plugin_name;
⋮----
private string $plugin_path;
⋮----
public function __construct( $plugin_path, $plugin_name = '' ) {
⋮----
/**
	 * Returns the name of this step.
	 *
	 * @return string The step name.
	 */
public static function get_step_name(): string {
⋮----
public static function get_schema( int $version = 1 ): array {
⋮----
'enum' => array( static::get_step_name() ),
⋮----
public function prepare_json_array(): array {
⋮----
'step'       => static::get_step_name(),
</file>

<file path="packages/php/blueprint/src/Steps/ActivateTheme.php">
namespace Automattic\WooCommerce\Blueprint\Steps;
⋮----
class ActivateTheme extends Step {
⋮----
private string $theme_folder_name;
⋮----
public function __construct( $theme_folder_name ) {
⋮----
public static function get_step_name(): string {
⋮----
public static function get_schema( int $version = 1 ): array {
⋮----
'enum' => array( static::get_step_name() ),
⋮----
public function prepare_json_array(): array {
⋮----
'step'            => static::get_step_name(),
</file>

<file path="packages/php/blueprint/src/Steps/InstallPlugin.php">
namespace Automattic\WooCommerce\Blueprint\Steps;
⋮----
class InstallPlugin extends Step {
⋮----
private string $slug;
⋮----
private string $resource;
⋮----
private array $options;
⋮----
public function __construct( $slug, $resource, array $options = array() ) {
⋮----
public function prepare_json_array(): array {
⋮----
'step'       => static::get_step_name(),
⋮----
public static function get_schema( int $version = 1 ): array {
⋮----
'enum' => array( static::get_step_name() ),
⋮----
public static function get_step_name(): string {
</file>

<file path="packages/php/blueprint/src/Steps/InstallTheme.php">
namespace Automattic\WooCommerce\Blueprint\Steps;
⋮----
class InstallTheme extends Step {
⋮----
private string $slug;
⋮----
private string $resource;
⋮----
private array $options;
⋮----
public function __construct( $slug, $resource, array $options = array() ) {
⋮----
public function prepare_json_array(): array {
⋮----
'step'      => static::get_step_name(),
⋮----
public static function get_schema( int $version = 1 ): array {
⋮----
'enum' => array( static::get_step_name() ),
⋮----
public static function get_step_name(): string {
</file>

<file path="packages/php/blueprint/src/Steps/RunSql.php">
namespace Automattic\WooCommerce\Blueprint\Steps;
⋮----
use Automattic\WooCommerce\Blueprint\Util;
⋮----
class RunSql extends Step {
⋮----
protected string $sql = '';
⋮----
/**
	 * Name of the sql file.
	 *
	 * @var string
	 */
protected string $name = 'schema.sql';
⋮----
public function __construct( string $sql, $name = 'schema.sql' ) {
⋮----
public static function from_table_row( array $row, string $table, string $type = 'replace into' ): self {
return new self( (string) Util::array_to_insert_sql( $row, self::TABLE_PREFIX_PLACEHOLDER . $table, $type ) );
⋮----
public static function get_step_name(): string {
⋮----
public static function get_schema( int $version = 1 ): array {
⋮----
'enum' => array( static::get_step_name() ),
⋮----
public function prepare_json_array(): array {
⋮----
'step' => static::get_step_name(),
</file>

<file path="packages/php/blueprint/src/Steps/SetSiteOptions.php">
namespace Automattic\WooCommerce\Blueprint\Steps;
⋮----
class SetSiteOptions extends Step {
⋮----
private array $options;
⋮----
public function __construct( array $options = array() ) {
⋮----
public static function get_step_name(): string {
⋮----
public static function get_schema( int $version = 1 ): array {
⋮----
'enum' => array( static::get_step_name() ),
⋮----
public function prepare_json_array(): array {
⋮----
'step'    => static::get_step_name(),
</file>

<file path="packages/php/blueprint/src/Steps/Step.php">
namespace Automattic\WooCommerce\Blueprint\Steps;
⋮----
abstract class Step {
⋮----
protected array $meta_values = array();
⋮----
abstract public static function get_step_name(): string;
⋮----
abstract public static function get_schema( int $version = 1 ): array;
⋮----
abstract public function prepare_json_array(): array;
⋮----
public function set_meta_values( array $meta_values ) {
⋮----
public function get_json_array() {
$json_array = $this->prepare_json_array();
</file>

<file path="packages/php/blueprint/src/BuiltInExporters.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
use Automattic\WooCommerce\Blueprint\Exporters\ExportInstallPluginSteps;
use Automattic\WooCommerce\Blueprint\Exporters\ExportInstallThemeSteps;
⋮----
class BuiltInExporters {
⋮----
public function get_all() {
</file>

<file path="packages/php/blueprint/src/BuiltInStepProcessors.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
use Automattic\WooCommerce\Blueprint\Importers\ImportActivatePlugin;
use Automattic\WooCommerce\Blueprint\Importers\ImportActivateTheme;
use Automattic\WooCommerce\Blueprint\Importers\ImportInstallPlugin;
use Automattic\WooCommerce\Blueprint\Importers\ImportInstallTheme;
use Automattic\WooCommerce\Blueprint\Importers\ImportRunSql;
use Automattic\WooCommerce\Blueprint\Importers\ImportSetSiteOptions;
use Automattic\WooCommerce\Blueprint\ResourceStorages\OrgPluginResourceStorage;
use Automattic\WooCommerce\Blueprint\ResourceStorages\OrgThemeResourceStorage;
⋮----
class BuiltInStepProcessors {
⋮----
public function __construct() {
⋮----
public function get_all() {
⋮----
$this->create_install_plugins_processor(),
$this->create_install_themes_processor(),
⋮----
private function create_install_plugins_processor() {
⋮----
$storages->add_storage( new OrgPluginResourceStorage() );
⋮----
private function create_install_themes_processor() {
⋮----
$storage->add_storage( new OrgThemeResourceStorage() );
</file>

<file path="packages/php/blueprint/src/ClassExtractor.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
class ClassExtractor {
⋮----
private string $file_path;
⋮----
private bool $has_strict_types_declaration = false;
⋮----
private string $prefix = '';
⋮----
/**
	 * Replacements for class variables.
	 *
	 * @var array
	 */
private array $class_variable_replacements = array();
⋮----
/**
	 * Replacements for method variables.
	 *
	 * @var array
	 */
private array $method_variable_replacements = array();
⋮----
/**
	 * Constructor.
	 *
	 * @param string $file_path Path to the PHP file to process.
	 *
	 * @throws \InvalidArgumentException If the file does not exist.
... (63 lines truncated)
</file>

<file path="packages/php/blueprint/src/Cli.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
use Automattic\WooCommerce\Blueprint\Cli\ExportCli;
use Automattic\WooCommerce\Blueprint\Cli\ImportCli;
⋮----
class Cli {
⋮----
public static function register_commands() {
\WP_CLI::add_command(
⋮----
$import->run( $assoc_args );
⋮----
$export->run(
</file>

<file path="packages/php/blueprint/src/ExportSchema.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
use Automattic\WooCommerce\Blueprint\Exporters\StepExporter;
use Automattic\WooCommerce\Blueprint\Exporters\HasAlias;
use Automattic\WooCommerce\Blueprint\Logger;
use Automattic\WooCommerce\Blueprint\Steps\Step;
use WP_Error;
⋮----
class ExportSchema {
⋮----
protected array $exporters = array();
⋮----
public function __construct( $exporters = array() ) {
⋮----
public function export( $steps = array() ) {
$loading_page_path = $this->wp_apply_filters( 'wooblueprint_export_landingpage', '/' );
⋮----
$built_in_exporters = ( new BuiltInExporters() )->get_all();
⋮----
$exporters = $this->wp_apply_filters( 'wooblueprint_exporters', array_merge( $this->exporters, $built_in_exporters ) );
⋮----
$name  = $exporter->get_step_name();
$alias = $exporter instanceof HasAlias ? $exporter->get_alias() : $name;
⋮----
if ( ! $exporter->check_step_capabilities() ) {
return new WP_Error( 'wooblueprint_insufficient_permissions', 'Insufficient permissions to export for step: ' . $exporter->get_step_name() );
⋮----
$logger->start_export( $exporters );
⋮----
$this->publish( 'onBeforeExport', $exporter );
... (21 lines truncated)
</file>

<file path="packages/php/blueprint/src/ImportSchema.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
use Automattic\WooCommerce\Blueprint\Schemas\JsonSchema;
use Opis\JsonSchema\Errors\ErrorFormatter;
use Opis\JsonSchema\Validator;
⋮----
class ImportSchema {
⋮----
private JsonSchema $schema;
⋮----
private Validator $validator;
⋮----
public function __construct( JsonSchema $schema, ?Validator $validator = null ) {
⋮----
public function get_schema() {
⋮----
public static function create_from_file( $file ) {
return self::create_from_json( $file );
⋮----
public static function create_from_json( $json_path ) {
⋮----
public function import() {
⋮----
$result    = StepProcessorResult::success( 'ImportSchema' );
⋮----
foreach ( $this->schema->get_steps() as $step_schema ) {
⋮----
$results[]     = $step_importer->import();
</file>

<file path="packages/php/blueprint/src/ImportStep.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
use Opis\JsonSchema\Errors\ErrorFormatter;
use Opis\JsonSchema\Validator;
use Automattic\WooCommerce\Blueprint\Logger;
⋮----
class ImportStep {
⋮----
private object $step_definition;
⋮----
private Validator $validator;
⋮----
private BuiltInStepProcessors $builtin_step_processors;
⋮----
private array $importers;
⋮----
private array $indexed_importers;
⋮----
public function __construct( $step_definition, ?Validator $validator = null ) {
⋮----
$this->importers         = $this->wp_apply_filters( 'wooblueprint_importers', ( ( new BuiltInStepProcessors() )->get_all() ) );
$this->indexed_importers = Util::index_array(
⋮----
return $importer->get_step_class()::get_step_name();
⋮----
public function import() {
$result = StepProcessorResult::success( $this->step_definition->step );
⋮----
if ( ! $this->can_import( $result ) ) {
⋮----
... (34 lines truncated)
</file>

<file path="packages/php/blueprint/src/Logger.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class Logger {
⋮----
private $logger;
⋮----
public function __construct() {
⋮----
public function log( string $message, string $level = \WC_Log_Levels::DEBUG, $context = array() ) {
$this->logger->log(
⋮----
'user_id' => $this->wp_get_current_user_id(),
⋮----
public function start_export( array $exporters ) {
$export_data = $this->get_export_data( $exporters );
⋮----
$this->log(
⋮----
public function complete_export( array $exporters ) {
⋮----
private function get_export_data( array $exporters ) {
⋮----
$step_name          = method_exists( $exporter, 'get_alias' ) ? $exporter->get_alias() : $exporter->get_step_name();
⋮----
public function export_step_failed( string $step_name, \Throwable $exception ) {
⋮----
'error' => $exception->getMessage(),
⋮----
... (10 lines truncated)
</file>

<file path="packages/php/blueprint/src/ResourceStorages.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
use Automattic\WooCommerce\Blueprint\ResourceStorages\ResourceStorage;
⋮----
class ResourceStorages {
⋮----
protected array $storages = array();
⋮----
public function add_storage( ResourceStorage $downloader ) {
$supported_resource = $downloader->get_supported_resource();
⋮----
public function is_supported_resource( $resource_type ) {
⋮----
public function download( $slug, $resource_type ) {
⋮----
$found = $storage->download( $slug );
</file>

<file path="packages/php/blueprint/src/StepProcessor.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
interface StepProcessor {
⋮----
public function process( $schema ): StepProcessorResult;
⋮----
public function get_step_class(): string;
⋮----
public function check_step_capabilities( $schema ): bool;
</file>

<file path="packages/php/blueprint/src/StepProcessorResult.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
use InvalidArgumentException;
⋮----
class StepProcessorResult {
⋮----
private array $messages = array();
⋮----
private bool $success;
⋮----
private string $step_name;
⋮----
public function __construct( bool $success, string $step_name ) {
⋮----
public function set_step_name( $step_name ) {
⋮----
public static function success( string $stp_name ): self {
⋮----
public function add_message( string $message, string $type = 'error' ) {
⋮----
public function merge_messages( StepProcessorResult $other ) {
$this->messages = array_merge( $this->messages, $other->get_messages() );
⋮----
public function add_error( string $message ) {
$this->add_message( $message );
⋮----
public function add_debug( string $message ) {
$this->add_message( $message, 'debug' );
⋮----
public function add_info( string $message ) {
... (12 lines truncated)
</file>

<file path="packages/php/blueprint/src/UsePluginHelpers.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
trait UsePluginHelpers {
⋮----
public function activate_plugin_by_slug( $slug ) {
⋮----
$all_plugins = $this->wp_get_plugins();
⋮----
return $this->wp_activate_plugin( $plugin_path );
⋮----
public function is_plugin_dir( $slug ) {
⋮----
public function delete_plugin_by_slug( $slug ) {
⋮----
if ( $this->deactivate_plugin_by_slug( $slug ) ) {
⋮----
return $this->wp_delete_plugins( array( $plugin_path ) );
⋮----
public function deactivate_plugin_by_slug( $slug ) {
</file>

<file path="packages/php/blueprint/src/UsePubSub.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
trait UsePubSub {
⋮----
private array $subscribers = array();
⋮----
public function subscribe( string $event, callable $callback ): void {
⋮----
public function publish( string $event, ...$args ): void {
⋮----
public function unsubscribe( string $event, callable $callback ): void {
</file>

<file path="packages/php/blueprint/src/UseWPFunctions.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
use WP_Error;
use WP_Theme;
⋮----
trait UseWPFunctions {
⋮----
private $filesystem_initialized = false;
⋮----
public function wp_add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
⋮----
public function wp_add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
⋮----
public function wp_apply_filters( $tag, $value ) {
⋮----
public function wp_do_action( $tag, ...$args ) {
⋮----
public function wp_is_plugin_active( string $plugin ) {
⋮----
public function wp_plugins_api( $action, $args = array() ) {
⋮----
public function wp_get_plugins( string $plugin_folder = '' ) {
⋮----
public function wp_get_themes( $args = array() ) {
⋮----
public function wp_get_theme( $stylesheet = null ) {
⋮----
public function wp_themes_api( $action, $args = array() ) {
⋮----
public function wp_activate_plugin( $plugin, $redirect = '', $network_wide = false, $silent = false ) {
... (36 lines truncated)
</file>

<file path="packages/php/blueprint/src/Util.php">
namespace Automattic\WooCommerce\Blueprint;
⋮----
use RecursiveArrayIterator;
use RecursiveIteratorIterator;
⋮----
class Util {
⋮----
public static function ensure_wp_content_path( $path ) {
⋮----
throw new \InvalidArgumentException( "Invalid path: $path" );
⋮----
public static function array_to_insert_sql( $row, $table, $type = 'insert ignore' ) {
⋮----
public static function snake_to_camel( $string_to_convert ) {
⋮----
/**
	 * Flatten an array.
	 *
	 * @param array $array_to_flatten The array to be flattened.
	 *
	 * @return \RecursiveIteratorIterator
	 */
public static function array_flatten( $array_to_flatten ) {
⋮----
/**
	 * Convert a string from camelCase to snake_case.
	 *
	 * @param string $input The string to be converted.
	 *
	 * @return string
... (16 lines truncated)
</file>

<file path="packages/php/blueprint/.gitattributes">
/*.md export-ignore
/changelog export-ignore
/docs* export-ignore
/phpcs.* export-ignore
/phpunit.* export-ignore
/package.json export-ignore
/node_modules* export-ignore
/tests export-ignore
</file>

<file path="packages/php/blueprint/.wp-env.json">
{
	"phpVersion": "8.1",
	"plugins": [
	  "."
	],
	"config": {
		"JETPACK_AUTOLOAD_DEV": true,
		"WP_DEBUG_LOG": true,
		"WP_DEBUG_DISPLAY": true,
		"ALTERNATE_WP_CRON": true
	},
	"mappings": {
	},
	"env": {
		"development": {},
		"tests": {
			"port": 8087,
			"plugins": [
			  "."
			],
			"themes": [],
			"config": {
			}
		}
	}
}
</file>

<file path="packages/php/blueprint/blueprint.php">

</file>

<file path="packages/php/blueprint/composer.json">
{
	"name": "woocommerce/blueprint",
	"version": "0.0.1",
	"type": "wordpress-plugin",
	"autoload": {
		"psr-4": {
			"Automattic\\WooCommerce\\Blueprint\\": "src/"
		}
	},
	"autoload-dev": {
		"psr-4": {
			"Automattic\\WooCommerce\\Blueprint\\Tests\\": "tests/"
		}
	},
	"require": {
		"opis/json-schema": "^2.3"
	},
	"scripts": {
		"test:setup": "wp-env start",
		"test:unit": "wp-env run tests-cli --env-cwd=wp-content/plugins/blueprint ./vendor/bin/phpunit",
		"phpcs": [
			"phpcs -s -p"
		],
		"phpcbf": [
			"phpcbf -p"
		]
	},
	"require-dev": {
		"phpunit/phpunit": "^9",
		"mockery/mockery": "^1.6",
... (31 lines truncated)
</file>

<file path="packages/php/blueprint/development.md">
# Development

## Running Unit Tests

We use [wp-env](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/) to setup test environment in Docker.
Please install `wp-env` by running `npm install -g @wordpress/env` if you haven't already.

1. Run `composer run test:setup` to run wp-env.
2. Run `composer run test:unit` to run unit tests.
</file>

<file path="packages/php/blueprint/package.json">
{
	"name": "@woocommerce/blueprint",
	"description": "WooCommerce Blueprint package",
	"scripts": {
		"changelog": "XDEBUG_MODE=off composer install --quiet && composer exec -- changelogger",
		"update:php": "XDEBUG_MODE=off composer update --quiet",
		"lint": "pnpm --if-present '/^lint:lang:.*$/'",
		"lint:fix": "pnpm --if-present '/^lint:fix:lang:.*$/'",
		"lint:fix:lang:php": "composer run-script phpcbf",
		"lint:lang:php": "composer run-script phpcs",
		"postinstall": "XDEBUG_MODE=off composer install --quiet",
		"env:test": "pnpm env:dev",
		"env:dev": "pnpm wp-env start --update",
		"test:unit": "composer run-script test:unit",
		"test:php:ci": "pnpm test:unit"
	},
	"license": "GPL-2.0-or-later",
	"devDependencies": {
		"@wordpress/env": "11.9.0"
	},
	"config": {
		"ci": {
			"lint": {
				"command": "lint",
				"changes": [
					"src/**/*.php"
				]
			},
			"tests": [
				{
... (27 lines truncated)
</file>

<file path="packages/php/blueprint/phpcs.xml">
<?xml version="1.0"?>
<ruleset name="WordPress Coding Standards">
	<description>WooCommerce dev PHP_CodeSniffer ruleset.</description>
	<file>.</file>
	<exclude-pattern>*/node_modules/*</exclude-pattern>
	<exclude-pattern>*/vendor/*</exclude-pattern>
	<arg value="ps" />
	<arg name="basepath" value="./" />
	<arg name="parallel" value="8" />
	<config name="minimum_supported_wp_version" value="5.2" />
	<config name="testVersion" value="7.4-" />
	<rule ref="WooCommerce-Core" />
	<rule ref="WordPress.Files.FileName.InvalidClassFileName">
		<exclude-pattern>src/</exclude-pattern>
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="WordPress.Files.FileName.NotHyphenatedLowercase">
		<exclude-pattern>src/</exclude-pattern>
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FileComment.MissingPackageTag">
		<exclude-pattern>src/</exclude-pattern>
		<exclude-pattern>.</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FileComment.Missing">
		<exclude-pattern>src/</exclude-pattern>
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="WordPress.Security.EscapeOutput.ExceptionNotEscaped">
		<exclude-pattern>src/</exclude-pattern>
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="WordPress.PHP.DevelopmentFunctions.error_log_print_r">
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FileComment.Missing">
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FunctionCommentThrowTag.Missing">
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
</ruleset>
</file>

<file path="packages/php/blueprint/README.md">
<!-- markdownlint-disable MD029 -->
# Blueprint

This PHP Composer package facilitates exporting and importing WordPress Blueprint compatible JSON formats. It offers a solid framework for seamless integration with WordPress sites and supports extensibility, enabling plugins to customize export and import functionalities. Manage site configurations, options, and settings effortlessly with JSON files.

## Usage

Blueprint lets you export your WordPress site configuration to a JSON file and import it into another site. This can be done via WP-CLI or directly in PHP for advanced automation or integration.

### Exporting a Blueprint

You can export a site configuration using the `ExportSchema` class:

```php
use Automattic\WooCommerce\Blueprint\ExportSchema;

// Optionally pass custom exporters, or leave empty for built-in exporters.
$export_schema = new ExportSchema();

// Export all steps:
$schema = $export_schema->export();

// Export only specific steps:
// $schema = $export_schema->export(['installPlugin', 'activateTheme']);

// Save to file:
file_put_contents('blueprint.json', json_encode($schema, JSON_PRETTY_PRINT));
```

### Importing a Blueprint
... (312 lines truncated)
</file>

<file path="packages/php/email-editor/changelog/.gitkeep">

</file>

<file path="packages/php/email-editor/changelog/testops-288-email-editor-loads">
Significance: patch
Type: dev
Comment: Move the email editor feature flag, preview send and REST failure coverage below E2E; the browser spec goes from six titles to five.
</file>

<file path="packages/php/email-editor/changelog/update-wooplug-7698-rich-text-comment-styles">
Significance: patch
Type: update

Move the personalization tag chip styles to a single flattened stylesheet loaded into both the editor iframe and the admin document.
</file>

<file path="packages/php/email-editor/docs/block-registration.md">
# Block Registration for Email Editor

This guide explains how to register WordPress blocks to support email rendering in the WooCommerce Email Editor. The email editor extends WordPress Gutenberg blocks with email-specific rendering capabilities, allowing blocks to generate HTML that is compatible with email clients.

## Table of Contents

-   [Overview](#overview)
-   [Block Configuration](#block-configuration)
    -   [Email Support Property](#email-support-property)
    -   [Email Render Callback](#email-render-callback)
-   [Registering Blocks for Email Support](#registering-blocks-for-email-support)
    -   [Method 1: Using block_type_metadata_settings Filter](#method-1-using-block_type_metadata_settings-filter)
    -   [Method 2: Direct Block Registration](#method-2-direct-block-registration)
-   [Creating Email Block Renderers](#creating-email-block-renderers)
    -   [Abstract Block Renderer](#abstract-block-renderer)
    -   [Rendering Context](#rendering-context)
    -   [Table Wrapper Helper](#table-wrapper-helper)
-   [Complete Example](#complete-example)
-   [Best Practices](#best-practices)
-   [Troubleshooting](#troubleshooting)

## Overview

The WooCommerce Email Editor allows WordPress blocks to be rendered in email-compatible HTML. To make a block compatible with email rendering, you need to:

1. **Enable email support** by setting `supports.email = true` in the block configuration
2. **Provide an email render callback** that generates email-compatible HTML
3. **Implement the rendering logic** that converts block content to email-friendly markup

The email editor automatically detects blocks with email support and uses their custom render callbacks instead of the default WordPress block rendering.
... (429 lines truncated)
</file>

<file path="packages/php/email-editor/docs/personalization-tags.md">
# Personalization Tags Documentation

## Table of Contents

-   [What are Personalization Tags?](#what-are-personalization-tags)
-   [Personalization Tags and Bits](#personalization-tags-and-bits)
-   [How They Work](#how-they-work)
-   [Key Components Overview](#key-components-overview)
-   [Editor UI](#editor-ui)
-   [Format](#format)
-   [Context](#context)
-   [Rendering Context and Escaping](#rendering-context-and-escaping)
-   [Value Interceptor](#value-interceptor)
-   [Core Components](#core-components)
-   [Creating Custom Tags](#creating-custom-tags)
-   [Usage with Renderer](#usage-with-renderer)

## What are Personalization Tags?

Personalization Tags are dynamic placeholders that can be inserted into email content to automatically replace with specific values when emails are sent. They provide a way to create personalized, context-aware email content without manual intervention.

**Key Features:**

-   **Dynamic Content**: Automatically replace tags with relevant data
-   **Context-Aware**: Access to order, customer, store, and site information
-   **Extensible**: Third-party developers can create custom tags

## Personalization Tags and Bits

Personalization Tags share conceptual similarities with WordPress Bits, a proposed system for dynamic tokens in WordPress core. Both systems aim to provide dynamic content replacement capabilities, though they serve different contexts. Personalization Tags are specifically designed for email content personalization within WooCommerce, while Bits are proposed as a general-purpose solution for WordPress content.
... (383 lines truncated)
</file>

<file path="packages/php/email-editor/docs/README.md">
# Email Editor PHP Package

## Documentation

-   [Block Registration](block-registration.md) - Guide to registering WordPress blocks for email editor support, including configuration, rendering, and best practices.
-   [Email Rendering](rendering.md) - Guide to the email rendering system, including renderer classes, bootstrapping, and core blocks integration.
-   [Personalization Tags](personalization-tags.md) - Guide to the personalization tags system, including tag registration, usage, and integration with the email editor.
</file>

<file path="packages/php/email-editor/docs/rendering.md">
# Email Rendering

**The email renderer classes** are designed to render WordPress posts containing block-based content (saved in the Gutenberg editor) as HTML and plain-text suitable for email delivery. These classes provide the core functionality for converting block editor content into email-compatible formats.

The email rendering system includes **Core Blocks Integration** that provides dedicated renderers for WordPress core blocks. This integration is essential for generating email client compatible HTML output - without these block-specific renderers, the rendered HTML would not be suitable for email clients.

## Table of Contents

-   [Retrieving Services via DI Container](#retrieving-services-via-di-container)
-   [Bootstrapping](#bootstrapping)
-   [Renderer Classes](#renderer-classes)
    -   [Renderer](#renderer)
    -   [Content_Renderer](#content_renderer)
-   [Rendering Direction](#rendering-direction)
-   [Core Blocks Integration](#core-blocks-integration)
-   [Table Wrapper Helper](#table-wrapper-helper)
-   [Styles Helper](#styles-helper)
-   [Integration Example](#integration-example)

## Retrieving Services via DI Container

The easiest way to access the rendering services is via DI container. The `Automattic\WooCommerce\EmailEditor\Email_Editor_Container` class provides a dependency injection container that can be used to easily obtain renderer services.

Here's how to obtain a renderer service:

```php
use Automattic\WooCommerce\EmailEditor\Email_Editor_Container;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\Renderer;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Content_Renderer;

... (691 lines truncated)
</file>

<file path="packages/php/email-editor/docs/site-style-sync-hooks.md">
# Site Style Sync Hooks and Filters

The WooCommerce Email Editor Site Style Sync feature provides several hooks and filters that developers can use to customize the synchronization behavior.

## Filters

### `woocommerce_email_editor_synced_site_styles`

Filter the synced site style data before applying to email theme.

```php
/**
 * Filter the synced site style data
 *
 * @since 1.1.0
 * @param array $synced_data The converted email-compatible theme data
 * @param array $site_data The original site theme data
 * @return array Modified synced data
 */
apply_filters( 'woocommerce_email_editor_synced_site_styles', $synced_data, $site_data );
```

**Example Usage:**

```php
add_filter( 'woocommerce_email_editor_synced_site_styles', function( $synced_data, $site_data ) {
    // Override specific colors for emails
    if ( isset( $synced_data['styles']['color'] ) ) {
        $synced_data['styles']['color']['background'] = '#ffffff'; // Force white background
        $synced_data['styles']['color']['text'] = '#333333'; // Force dark text for readability
... (130 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Logger/class-default-email-editor-logger.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Logger;
⋮----
class Default_Email_Editor_Logger implements Email_Editor_Logger_Interface {
⋮----
private $log_file;
⋮----
public function __construct() {
⋮----
/**
	 * System is unusable.
	 *
	 * @param string $message The log message.
	 * @param array  $context The log context.
	 * @return void
	 */
public function emergency( string $message, array $context = array() ): void {
$this->log( self::EMERGENCY, $message, $context );
⋮----
/**
	 * Action must be taken immediately.
	 *
	 * @param string $message The log message.
	 * @param array  $context The log context.
	 * @return void
	 */
public function alert( string $message, array $context = array() ): void {
$this->log( self::ALERT, $message, $context );
⋮----
/**
	 * Critical conditions.
... (69 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Logger/class-email-editor-logger-interface.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Logger;
⋮----
interface Email_Editor_Logger_Interface {
⋮----
public function emergency( string $message, array $context = array() ): void;
⋮----
public function alert( string $message, array $context = array() ): void;
⋮----
public function critical( string $message, array $context = array() ): void;
⋮----
public function error( string $message, array $context = array() ): void;
⋮----
public function warning( string $message, array $context = array() ): void;
⋮----
public function notice( string $message, array $context = array() ): void;
⋮----
public function info( string $message, array $context = array() ): void;
⋮----
public function debug( string $message, array $context = array() ): void;
⋮----
public function log( string $level, string $message, array $context = array() ): void;
</file>

<file path="packages/php/email-editor/src/Engine/Logger/class-email-editor-logger.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Logger;
⋮----
class Email_Editor_Logger implements Email_Editor_Logger_Interface {
⋮----
private Email_Editor_Logger_Interface $logger;
⋮----
public function __construct( ?Email_Editor_Logger_Interface $logger = null ) {
⋮----
public function set_logger( Email_Editor_Logger_Interface $logger ): void {
⋮----
public function emergency( string $message, array $context = array() ): void {
$this->logger->emergency( $message, $context );
⋮----
public function alert( string $message, array $context = array() ): void {
$this->logger->alert( $message, $context );
⋮----
public function critical( string $message, array $context = array() ): void {
$this->logger->critical( $message, $context );
⋮----
public function error( string $message, array $context = array() ): void {
$this->logger->error( $message, $context );
⋮----
public function warning( string $message, array $context = array() ): void {
$this->logger->warning( $message, $context );
⋮----
public function notice( string $message, array $context = array() ): void {
$this->logger->notice( $message, $context );
⋮----
public function info( string $message, array $context = array() ): void {
$this->logger->info( $message, $context );
... (7 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Patterns/class-abstract-pattern.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Patterns;
⋮----
abstract class Abstract_Pattern {
⋮----
protected $name = '';
/**
	 * Namespace of the pattern.
	 *
	 * @var string $namespace
	 */
protected $namespace = '';
/**
	 * List of block types.
	 *
	 * @var array $block_types
	 */
protected $block_types = array();
/**
	 * List of template types.
	 *
	 * @var string[] $template_types
	 */
protected $template_types = array();
/**
	 * List of supported post types.
	 *
	 * @var string[] $post_types
	 */
protected $post_types = array();
/**
... (32 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Patterns/class-patterns.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Patterns;
⋮----
class Patterns {
⋮----
public function initialize(): void {
$this->register_block_pattern_categories();
⋮----
private function register_block_pattern_categories(): void {
</file>

<file path="packages/php/email-editor/src/Engine/PersonalizationTags/class-html-tag-processor.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags;
⋮----
use WP_HTML_Tag_Processor;
use WP_HTML_Text_Replacement;
⋮----
class HTML_Tag_Processor extends WP_HTML_Tag_Processor {
⋮----
private $deferred_updates = array();
⋮----
public function replace_token( string $new_content ): void {
$this->set_bookmark( 'here' );
⋮----
public function flush_updates(): void {
</file>

<file path="packages/php/email-editor/src/Engine/PersonalizationTags/class-personalization-tag.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags;
⋮----
class Personalization_Tag {
⋮----
private string $name;
⋮----
private string $token;
⋮----
private string $category;
⋮----
private $callback;
⋮----
private array $attributes;
⋮----
private string $value_to_insert;
⋮----
private array $post_types;
⋮----
private string $value_type;
⋮----
public function __construct(
⋮----
public function __unserialize( array $data ): void {
throw new \Exception( 'Deserialization of Personalization_Tag is not allowed for security reasons.' );
⋮----
public function get_name(): string {
⋮----
public function get_token(): string {
⋮----
public function get_category(): string {
... (13 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/PersonalizationTags/class-personalization-tags-registry.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger;
⋮----
class Personalization_Tags_Registry {
⋮----
private Email_Editor_Logger $logger;
⋮----
private $tags = array();
⋮----
public function __construct( Email_Editor_Logger $logger ) {
⋮----
public function initialize(): void {
$this->logger->info( 'Initializing personalization tags registry' );
⋮----
$this->logger->info( 'Personalization tags registry initialized', array( 'tags_count' => count( $this->tags ) ) );
⋮----
public function register( Personalization_Tag $tag ): void {
if ( isset( $this->tags[ $tag->get_token() ] ) ) {
$this->logger->warning(
⋮----
'token'    => $tag->get_token(),
'name'     => $tag->get_name(),
'category' => $tag->get_category(),
⋮----
$this->tags[ $tag->get_token() ] = $tag;
⋮----
$this->logger->debug(
⋮----
public function unregister( $token_or_tag ): ?Personalization_Tag {
... (7 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/Layout/class-flex-layout-renderer.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Layout;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
⋮----
class Flex_Layout_Renderer {
⋮----
public function render_inner_blocks_in_layout( array $parsed_block, Rendering_Context $rendering_context ): string {
$theme_styles    = $rendering_context->get_theme_styles();
⋮----
$flex_gap_number = Styles_Helper::parse_value( $flex_gap );
⋮----
$justify    = $rendering_context->resolve_text_align( $parsed_block['attrs']['layout']['justifyContent'] ?? null );
⋮----
list( $inner_blocks, $should_wrap ) = $this->compute_widths_for_flex_layout( $parsed_block, $flex_gap_number );
⋮----
return $this->render_wrapping_layout( $inner_blocks, $styles, $justify, $flex_gap, $rendering_context );
⋮----
return $this->render_single_row_layout( $inner_blocks, $styles, $justify, $flex_gap, $rendering_context );
⋮----
/**
	 * Render the inner blocks as a single, non-wrapping row.
	 *
	 * This is the default layout: a table row whose cells sit side by side. It's correct whenever
	 * the items are known to fit the available width (and it's what every explicitly-sized buttons
	 * block uses, since those are shrunk to fit by {@see compute_widths_for_flex_layout()}).
	 *
	 * @param array             $inner_blocks Inner blocks with computed widths.
	 * @param string            $styles Wrapper styles (already includes margin-top and text-align).
	 * @param string            $justify Resolved horizontal alignment (left/center/right).
... (57 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/Postprocessors/class-border-style-postprocessor.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Postprocessors;
⋮----
class Border_Style_Postprocessor implements Postprocessor {
⋮----
public function postprocess( string $html ): string {
$processor = new \WP_HTML_Tag_Processor( $html );
⋮----
while ( $processor->next_tag() ) {
$style = $processor->get_attribute( 'style' );
⋮----
$processed_style = $this->process_style( $style );
⋮----
$processor->set_attribute( 'style', $processed_style );
⋮----
return $processor->get_updated_html();
⋮----
private function process_style( string $style ): string {
⋮----
$border_width = $this->extract_width_from_shorthand_value( $value );
⋮----
$border_style = $this->extract_style_from_shorthand_value( $value );
⋮----
$border_widths = array_merge( $border_widths, $this->expand_shorthand_value( $value ) );
⋮----
$border_styles = array_merge( $border_styles, $this->expand_shorthand_value( $value ) );
⋮----
if ( $this->is_nonzero_width( $value ) ) {
⋮----
/**
	 * Expands shorthand border width and style values into individual properties.
... (24 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/Postprocessors/class-highlighting-postprocessor.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Postprocessors;
⋮----
class Highlighting_Postprocessor implements Postprocessor {
⋮----
public function postprocess( string $html ): string {
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/Postprocessors/class-variables-postprocessor.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Postprocessors;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Theme_Controller;
⋮----
class Variables_Postprocessor implements Postprocessor {
⋮----
private Theme_Controller $theme_controller;
⋮----
public function __construct(
⋮----
public function postprocess( string $html ): string {
$variables    = $this->theme_controller->get_variables_values_map();
⋮----
$processor = new \WP_HTML_Tag_Processor( $html );
⋮----
while ( $processor->next_tag() ) {
$style = $processor->get_attribute( 'style' );
⋮----
$processor->set_attribute( 'style', $processed_style );
⋮----
return $processor->get_updated_html();
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/Postprocessors/interface-postprocessor.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Postprocessors;
⋮----
interface Postprocessor {
⋮----
public function postprocess( string $html ): string;
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/Preprocessors/class-blocks-width-preprocessor.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preset_Variable_Resolver;
⋮----
class Blocks_Width_Preprocessor implements Preprocessor {
⋮----
public function preprocess( array $parsed_blocks, array $layout, array $styles ): array {
⋮----
return $this->calculate_widths( $parsed_blocks, $layout, $styles, $variables_map );
⋮----
private function calculate_widths( array $parsed_blocks, array $layout, array $styles, array $variables_map = array() ): array {
⋮----
$layout_width = $this->parse_number_from_string_with_pixels( $layout['contentSize'] );
⋮----
$layout_width -= $this->parse_number_from_string_with_pixels( $styles['spacing']['padding']['left'] ?? '0px' );
$layout_width -= $this->parse_number_from_string_with_pixels( $styles['spacing']['padding']['right'] ?? '0px' );
⋮----
$layout_width -= $this->parse_number_from_string_with_pixels( $block['email_attrs']['root-padding-left'] ?? '0px' );
$layout_width -= $this->parse_number_from_string_with_pixels( $block['email_attrs']['root-padding-right'] ?? '0px' );
⋮----
$layout_width -= $this->parse_number_from_string_with_pixels( Preset_Variable_Resolver::resolve( $block['email_attrs']['container-padding-left'] ?? '0px', $variables_map ) );
$layout_width -= $this->parse_number_from_string_with_pixels( Preset_Variable_Resolver::resolve( $block['email_attrs']['container-padding-right'] ?? '0px', $variables_map ) );
⋮----
$block_padding_left  = $suppress_h_padding ? '0px' : Preset_Variable_Resolver::resolve( $block['attrs']['style']['spacing']['padding']['left'] ?? '0px', $variables_map );
$block_padding_right = $suppress_h_padding ? '0px' : Preset_Variable_Resolver::resolve( $block['attrs']['style']['spacing']['padding']['right'] ?? '0px', $variables_map );
⋮----
$block_border_horizontal = $this->get_block_horizontal_border( $block );
⋮----
$width       = $this->convert_width_to_pixels( $width_input, $layout_width );
⋮----
... (45 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/Preprocessors/class-cleanup-preprocessor.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors;
⋮----
class Cleanup_Preprocessor implements Preprocessor {
⋮----
public function preprocess( array $parsed_blocks, array $layout, array $styles ): array {
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/Preprocessors/class-quote-preprocessor.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors;
⋮----
class Quote_Preprocessor implements Preprocessor {
⋮----
public function preprocess( array $parsed_blocks, array $layout, array $styles ): array {
return $this->process_blocks( $parsed_blocks, $styles );
⋮----
private function process_blocks( array $blocks, array $styles ): array {
⋮----
$block['innerBlocks'] = $this->apply_alignment_to_children( $block['innerBlocks'], $quote_align );
⋮----
$block['innerBlocks'] = $this->apply_typography_to_children( $block['innerBlocks'], $quote_typography, $styles );
⋮----
$block['innerBlocks'] = $this->process_blocks( $block['innerBlocks'], $styles );
⋮----
private function apply_alignment_to_children( array $blocks, ?string $text_align = null ): array {
⋮----
$block['innerBlocks'] = $this->apply_alignment_to_children( $block['innerBlocks'], $block['attrs']['textAlign'] ?? $block['attrs']['align'] );
⋮----
private function apply_typography_to_children( array $blocks, array $quote_typography, array $styles ): array {
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/Preprocessors/class-spacing-preprocessor.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preset_Variable_Resolver;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
⋮----
class Spacing_Preprocessor implements Context_Aware_Preprocessor {
⋮----
private ?array $post_content_block_names = null;
⋮----
public function preprocess( array $parsed_blocks, array $layout, array $styles ): array {
return $this->preprocess_with_context( $parsed_blocks, $layout, $styles );
⋮----
public function preprocess_with_context( array $parsed_blocks, array $layout, array $styles, ?Rendering_Context $rendering_context = null ): array {
$root_padding      = $this->get_root_padding( $styles );
⋮----
$gap_padding_side  = $rendering_context && $rendering_context->is_rtl() ? 'padding-right' : 'padding-left';
$parsed_blocks     = $this->add_block_gaps(
⋮----
/**
	 * Extract and validate horizontal padding from a block's style attributes.
	 *
	 * Preset variable references (e.g. "var:preset|spacing|20") are resolved
	 * to their pixel values using the variables map when provided.
	 *
	 * @param array $block The block to extract padding from.
	 * @param array $variables_map Map of CSS variable names to resolved values.
	 * @return array Padding with 'left' and 'right' keys, or empty array if invalid/absent.
	 */
private function get_block_horizontal_padding( array $block, array $variables_map = array() ): array {
⋮----
... (52 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/Preprocessors/class-typography-preprocessor.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Settings_Controller;
⋮----
class Typography_Preprocessor implements Preprocessor {
⋮----
private $settings_controller;
⋮----
public function __construct(
⋮----
public function preprocess( array $parsed_blocks, array $layout, array $styles ): array {
⋮----
$block = $this->preprocess_parent( $block );
⋮----
$block = $this->set_defaults_from_theme( $block );
⋮----
$block['innerBlocks']  = $this->copy_typography_from_parent( $block['innerBlocks'], $block );
⋮----
private function copy_typography_from_parent( array $children, array $parent_block ): array {
⋮----
$child                = $this->preprocess_parent( $child );
$child['email_attrs'] = array_merge( $this->filterStyles( $parent_block['email_attrs'] ), $child['email_attrs'] );
$child['innerBlocks'] = $this->copy_typography_from_parent( $child['innerBlocks'] ?? array(), $child );
⋮----
private function preprocess_parent( array $block ): array {
⋮----
$email_attrs['color'] = $this->settings_controller->translate_slug_to_color( $block['attrs']['textColor'] );
⋮----
$block['attrs']['style']['typography']['fontSize'] = $this->settings_controller->translate_slug_to_font_size( $block['attrs']['fontSize'] );
⋮----
... (5 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/Preprocessors/interface-context-aware-preprocessor.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
⋮----
interface Context_Aware_Preprocessor extends Preprocessor {
⋮----
public function preprocess_with_context( array $parsed_blocks, array $layout, array $styles, ?Rendering_Context $rendering_context = null ): array;
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/Preprocessors/interface-preprocessor.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors;
⋮----
interface Preprocessor {
⋮----
public function preprocess( array $parsed_blocks, array $layout, array $styles ): array;
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/class-block-renderer.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer;
⋮----
interface Block_Renderer {
⋮----
public function render( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string;
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/class-blocks-parser.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer;
⋮----
use WP_Block_Parser;
⋮----
class Blocks_Parser extends WP_Block_Parser {
⋮----
public $output;
⋮----
public function parse( $document ) {
parent::parse( $document );
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/class-content-renderer.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\Css_Inliner;
use Automattic\WooCommerce\EmailEditor\Engine\Theme_Controller;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Fallback;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Post_Content;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
use WP_Block_Template;
use WP_Block_Type_Registry;
use WP_Post;
use WP_Style_Engine;
⋮----
class Content_Renderer {
⋮----
private Process_Manager $process_manager;
⋮----
private Theme_Controller $theme_controller;
⋮----
private WP_Block_Type_Registry $block_type_registry;
⋮----
private $backup_template_content;
⋮----
private $backup_template_id;
⋮----
private $backup_post;
⋮----
private $backup_query;
⋮----
private Fallback $fallback_renderer;
... (133 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/class-preset-variable-resolver.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer;
⋮----
class Preset_Variable_Resolver {
⋮----
private static function to_css_variable_name( string $value ): string {
⋮----
/**
	 * Check if a value is a preset variable reference.
	 *
	 * @param string $value The CSS value to check.
	 * @return bool True if the value starts with "var:preset|".
	 */
public static function is_preset_reference( string $value ): bool {
⋮----
/**
	 * Resolve a preset variable reference to its actual value.
	 *
	 * Converts "var:preset|spacing|20" to the resolved pixel value (e.g. "20px")
	 * using the provided variables map. Returns the original value if not a preset
	 * reference or if the variable is not found in the map.
	 *
	 * @param string $value The CSS value, possibly a preset reference.
	 * @param array  $variables_map Map of CSS variable names to resolved values.
	 * @return string The resolved value or the original value.
	 */
public static function resolve( string $value, array $variables_map ): string {
if ( empty( $variables_map ) || ! self::is_preset_reference( $value ) ) {
⋮----
$css_var_name = self::to_css_variable_name( $value );
⋮----
... (14 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/class-process-manager.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Postprocessors\Highlighting_Postprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Postprocessors\Postprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Postprocessors\Variables_Postprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors\Blocks_Width_Preprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors\Cleanup_Preprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors\Context_Aware_Preprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors\Preprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors\Spacing_Preprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors\Typography_Preprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors\Quote_Preprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Postprocessors\Border_Style_Postprocessor;
⋮----
class Process_Manager {
⋮----
private $preprocessors = array();
⋮----
private $postprocessors = array();
⋮----
public function __construct(
⋮----
$this->register_preprocessor( $cleanup_preprocessor );
⋮----
$this->register_preprocessor( $spacing_preprocessor );
$this->register_preprocessor( $blocks_width_preprocessor );
$this->register_preprocessor( $typography_preprocessor );
$this->register_preprocessor( $quote_preprocessor );
$this->register_postprocessor( $highlighting_postprocessor );
$this->register_postprocessor( $border_style_postprocessor );
... (15 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/ContentRenderer/class-rendering-context.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer;
⋮----
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use WP_Theme_JSON;
⋮----
class Rendering_Context {
⋮----
private WP_Theme_JSON $theme_json;
⋮----
private array $email_context;
⋮----
private ?string $language;
⋮----
public function __construct( WP_Theme_JSON $theme_json, array $email_context = array(), ?string $language = null ) {
⋮----
public function get_theme_json(): WP_Theme_JSON {
⋮----
public function get_theme_styles(): array {
$theme = $this->get_theme_json();
return $theme->get_data()['styles'] ?? array();
⋮----
public function get_theme_settings() {
return $this->get_theme_json()->get_settings();
⋮----
public function get_layout_width_without_padding(): string {
$styles          = $this->get_theme_styles();
$layout_settings = $this->get_theme_settings()['layout'] ?? array();
$width           = Styles_Helper::parse_value( $layout_settings['contentSize'] ?? '0px' );
⋮----
$width          -= Styles_Helper::parse_value( $padding['left'] ?? '0px' );
... (37 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/class-html2text-exception.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer;
⋮----
class Html2Text_Exception extends \Exception {
⋮----
private string $more_info;
⋮----
public function __construct( string $message = '', string $more_info = '' ) {
parent::__construct( $message );
⋮----
public function get_more_info(): string {
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/class-html2text.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer;
⋮----
class Html2Text {
⋮----
public static function default_options(): array {
⋮----
public static function convert( string $html, $options = array() ): string {
⋮----
$options = array_merge( static::default_options(), $options );
⋮----
if ( ! in_array( $key, array_keys( static::default_options() ), true ) ) {
⋮----
error_log( 'Html2Text: Invalid option provided: ' . htmlspecialchars( (string) $key, ENT_QUOTES, 'UTF-8' ) . '. Valid options are: ' . htmlspecialchars( implode( ',', array_keys( static::default_options() ) ), ENT_QUOTES, 'UTF-8' ) );
⋮----
throw new \InvalidArgumentException( 'Invalid option provided for html2text conversion.' );
⋮----
$is_office_document = self::is_office_document( $html );
⋮----
$html = self::fix_newlines( $html );
⋮----
// Use mb_convert_encoding for legacy versions of php.
⋮----
$doc = self::get_document( $html, $options );
⋮----
$output = self::iterate_over_node( $doc, null, false, $is_office_document, $options );
⋮----
$output = self::process_whitespace_newlines( $output );
⋮----
public static function fix_newlines( string $text ): string {
⋮----
... (98 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/class-renderer.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Content_Renderer;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Process_Manager;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Engine\Templates\Templates;
use Automattic\WooCommerce\EmailEditor\Engine\Theme_Controller;
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
use WP_Style_Engine;
⋮----
class Renderer {
⋮----
private Theme_Controller $theme_controller;
⋮----
private Content_Renderer $content_renderer;
⋮----
private Templates $templates;
⋮----
private Css_Inliner $css_inliner;
⋮----
private Process_Manager $process_manager;
⋮----
private Personalization_Tags_Registry $personalization_tags_registry;
⋮----
private array $personalization_tag_placeholders = array();
⋮----
public function __construct(
⋮----
public function render( \WP_Post $post, string $subject, string $pre_header, string $language, string $meta_robots = '', string $template_slug = '' ): array {
⋮----
... (82 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/interface-css-inliner.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Renderer;
⋮----
interface Css_Inliner {
⋮----
public function from_html( string $unprocessed_html ): self;
⋮----
public function inline_css( string $css = '' ): self;
⋮----
public function render(): string;
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/readme.md">
# MailPoet Email Renderer

**The renderer is Work In Progress (WIP) and so is the API for adding support email rendering for new blocks**.

## Adding support for a core block

1. Add block into `ALLOWED_BLOCK_TYPES` in `packages/php/email-editor/src/Integrations/Core/class-initializer.php`.
2. Make sure the block is registered in the editor. Currently all core blocks are registered in the editor.
3. If necessary, add BlockRender class (e.g. Heading) into `packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/` folder.

```php
<?php declare(strict_types = 1);

namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;

use Automattic\WooCommerce\EmailEditor\Engine\Settings_Controller;

class Heading extends AbstractBlockRenderer {
  protected function renderContent($blockContent, array $parsedBlock, Settings_Controller $settingsController): string {
    return $blockContent;
  }
}

```

<!-- markdownlint-disable MD029 -->

[//]: # 'This disabled MD029/ol-prefix Ordered list item prefix [Expected: 1; Actual: 4; Style: 1/1/1]'

4. Register the renderer
... (28 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Renderer/template-canvas.php">
$language_attributes = trim( $language_attributes . ' dir="' . esc_attr( $rendering_context->get_text_direction() ) . '"' );
⋮----
<body dir="<?php echo esc_attr( $rendering_context->get_text_direction() ); ?>">
</file>

<file path="packages/php/email-editor/src/Engine/Templates/class-template.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Templates;
⋮----
class Template {
⋮----
private string $plugin_uri;
⋮----
private string $slug;
⋮----
private string $name;
⋮----
private string $title;
⋮----
private string $description;
⋮----
private string $content;
⋮----
private array $post_types;
⋮----
public function __construct(
⋮----
public function get_pluginuri(): string {
⋮----
public function get_slug(): string {
⋮----
public function get_name(): string {
⋮----
public function get_title(): string {
⋮----
public function get_description(): string {
⋮----
... (4 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Templates/class-templates-registry.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Templates;
⋮----
class Templates_Registry {
⋮----
private $templates = array();
⋮----
public function initialize(): void {
⋮----
public function register( Template $template ): void {
if ( ! \WP_Block_Templates_Registry::get_instance()->is_registered( $template->get_name() ) ) {
⋮----
$template->get_name(),
⋮----
'title'       => $template->get_title(),
'description' => $template->get_description(),
'content'     => $template->get_content(),
'post_types'  => $template->get_post_types(),
⋮----
$this->templates[ $template->get_name() ] = $template;
⋮----
public function get_by_name( string $name ): ?Template {
⋮----
public function get_by_slug( string $slug ): ?Template {
⋮----
if ( $template->get_slug() === $slug ) {
⋮----
public function get_all() {
</file>

<file path="packages/php/email-editor/src/Engine/Templates/class-templates.php">
namespace Automattic\WooCommerce\EmailEditor\Engine\Templates;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Builder;
use WP_Block_Template;
⋮----
class Templates {
⋮----
private string $template_prefix = 'woocommerce';
⋮----
private array $post_types = array();
⋮----
private string $template_directory = __DIR__ . DIRECTORY_SEPARATOR;
⋮----
private Templates_Registry $templates_registry;
⋮----
public function __construct( Templates_Registry $templates_registry ) {
⋮----
public function initialize( array $post_types ): void {
⋮----
$this->templates_registry->initialize();
$this->register_post_types_to_api();
⋮----
public function get_block_template( $template_slug ) {
⋮----
public function register_templates( Templates_Registry $templates_registry ): Templates_Registry {
⋮----
$templates_registry->register( $general_email );
⋮----
public function register_post_types_to_api(): void {
$controller = new \WP_REST_Templates_Controller( 'wp_template' );
... (15 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/Templates/email-general.html">
<div class="wp-block-group">
</div>
</file>

<file path="packages/php/email-editor/src/Engine/Templates/single-email-post-template.php">

</file>

<file path="packages/php/email-editor/src/Engine/class-assets-manager.php">
namespace Automattic\WooCommerce\EmailEditor\Engine;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger;
⋮----
class Assets_Manager {
⋮----
private Settings_Controller $settings_controller;
⋮----
private Theme_Controller $theme_controller;
⋮----
private User_Theme $user_theme;
⋮----
private string $assets_path = '';
⋮----
/**
	 * Email editor assets URL.
	 *
	 * @var string
	 */
private string $assets_url = '';
⋮----
/**
	 * Logger instance.
	 *
	 * @var Email_Editor_Logger
	 */
private Email_Editor_Logger $logger;
⋮----
/**
	 * Whether the email editor HTML has been rendered.
... (68 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/class-dependency-check.php">
namespace Automattic\WooCommerce\EmailEditor\Engine;
⋮----
class Dependency_Check {
⋮----
public function are_dependencies_met(): bool {
if ( ! $this->is_wp_version_compatible() ) {
⋮----
private function is_wp_version_compatible(): bool {
</file>

<file path="packages/php/email-editor/src/Engine/class-email-api-controller.php">
namespace Automattic\WooCommerce\EmailEditor\Engine;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tag;
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
use Automattic\WooCommerce\EmailEditor\Validator\Builder;
use WP_Post;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Email_Api_Controller {
⋮----
private Personalization_Tags_Registry $personalization_tags_registry;
⋮----
public function __construct( Personalization_Tags_Registry $personalization_tags_registry ) {
⋮----
public function get_email_data(): array {
⋮----
public function save_email_data( array $data, WP_Post $email_post ): void {
⋮----
public function send_preview_email_data( WP_REST_Request $request ): WP_REST_Response {
⋮----
$data = $request->get_params();
⋮----
return new WP_REST_Response( array( 'error' => $exception->getMessage() ), 400 );
⋮----
public function get_personalization_tags(): WP_REST_Response {
$tags = $this->personalization_tags_registry->get_all();
⋮----
'name'          => $tag->get_name(),
'token'         => $tag->get_token(),
... (11 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/class-email-editor.php">
namespace Automattic\WooCommerce\EmailEditor\Engine;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Patterns\Patterns;
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
use Automattic\WooCommerce\EmailEditor\Engine\Templates\Templates;
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger;
use WP_Post;
use WP_REST_Request;
use WP_Theme_JSON;
⋮----
class Email_Editor {
⋮----
private Email_Api_Controller $email_api_controller;
⋮----
private Templates $templates;
⋮----
private Patterns $patterns;
⋮----
private Send_Preview_Email $send_preview_email;
⋮----
private Personalization_Tags_Registry $personalization_tags_registry;
⋮----
private Email_Editor_Logger $logger;
⋮----
private Assets_Manager $assets_manager;
⋮----
public function __construct(
⋮----
public function initialize(): void {
$this->logger->info( 'Initializing email editor' );
... (63 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/class-email-styles-schema.php">
namespace Automattic\WooCommerce\EmailEditor\Engine;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Builder;
⋮----
class Email_Styles_Schema {
⋮----
public function get_schema(): array {
$typography_props = Builder::object(
⋮----
'fontFamily'     => Builder::string()->nullable(),
'fontSize'       => Builder::string()->nullable(),
'fontStyle'      => Builder::string()->nullable(),
'fontWeight'     => Builder::string()->nullable(),
'letterSpacing'  => Builder::string()->nullable(),
'lineHeight'     => Builder::string()->nullable(),
'textTransform'  => Builder::string()->nullable(),
'textDecoration' => Builder::string()->nullable(),
⋮----
)->nullable();
return Builder::object(
⋮----
'version' => Builder::integer(),
'styles'  => Builder::object(
⋮----
'spacing'    => Builder::object(
⋮----
'padding'  => Builder::object(
⋮----
'top'    => Builder::string(),
'right'  => Builder::string(),
... (33 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/class-personalizer.php">
namespace Automattic\WooCommerce\EmailEditor\Engine;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\HTML_Tag_Processor;
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tag;
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
⋮----
class Personalizer {
⋮----
private Personalization_Tags_Registry $tags_registry;
⋮----
private array $context;
⋮----
private $value_interceptor = null;
⋮----
public function __construct( Personalization_Tags_Registry $tags_registry ) {
⋮----
public function set_context( array $context ) {
⋮----
public function get_context(): array {
⋮----
public function set_value_interceptor( ?callable $interceptor ): ?callable {
⋮----
private function intercept_value( string $value, string $source, string $rendering_context ): string {
⋮----
public function personalize_content( string $content, string $rendering_context = self::RENDERING_CONTEXT_HTML ): string {
⋮----
while ( $content_processor->next_token() ) {
if ( $content_processor->get_token_type() === '#comment' ) {
$modifiable_text = $content_processor->get_modifiable_text();
$token           = $this->parse_token( $modifiable_text );
... (75 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/class-send-preview-email.php">
namespace Automattic\WooCommerce\EmailEditor\Engine;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\Renderer;
⋮----
class Send_Preview_Email {
⋮----
private Renderer $renderer;
⋮----
private Personalizer $personalizer;
⋮----
public function __construct(
⋮----
public function send_preview_email( $data ): bool {
⋮----
$this->validate_data( $data );
⋮----
$post    = $this->fetch_post( $post_id );
$subject = $this->get_preview_email_subject( $post );
⋮----
$email_html_content = $this->render_html( $post );
⋮----
return $this->send_email( $email, $subject, $email_html_content );
⋮----
public function render_html( $post ): string {
$subject  = $this->get_preview_email_subject( $post );
⋮----
$rendered_data = $this->renderer->render(
⋮----
return $this->set_personalize_content( $rendered_data['html'] );
⋮----
... (24 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/class-settings-controller.php">
namespace Automattic\WooCommerce\EmailEditor\Engine;
⋮----
class Settings_Controller {
⋮----
private Theme_Controller $theme_controller;
⋮----
private array $allowed_iframe_style_handles = array();
⋮----
private array $iframe_assets = array();
⋮----
public function __construct(
⋮----
public function get_settings(): array {
$this->init_iframe_assets();
⋮----
$core_default_settings = \get_default_block_editor_settings();
$theme_settings        = $this->theme_controller->get_settings();
⋮----
public function get_layout(): array {
$layout_settings = $this->theme_controller->get_layout_settings();
⋮----
public function get_email_styles(): array {
$theme = $this->get_theme();
return $theme->get_data()['styles'];
⋮----
public function get_layout_width_without_padding(): string {
$styles = $this->get_email_styles();
$layout = $this->get_layout();
$width  = $this->parse_number_from_string_with_pixels( $layout['contentSize'] );
$width -= $this->parse_number_from_string_with_pixels( $styles['spacing']['padding']['left'] );
... (46 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/class-site-style-sync-controller.php">
namespace Automattic\WooCommerce\EmailEditor\Engine;
⋮----
use WP_Theme_JSON;
use WP_Theme_JSON_Resolver;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
⋮----
class Site_Style_Sync_Controller {
⋮----
private ?WP_Theme_JSON $site_theme = null;
⋮----
private ?array $base_theme_data = null;
⋮----
private $email_safe_fonts = array();
⋮----
public function __construct() {
⋮----
public function initialize(): void {
⋮----
public function sync_site_styles( ?WP_Theme_JSON $base_theme = null ): array {
⋮----
$this->base_theme_data = $base_theme ? $base_theme->get_data() : null;
⋮----
$site_theme = $this->get_site_theme();
$site_data  = $site_theme->get_data();
⋮----
'settings' => $this->sync_settings_data( $site_data['settings'] ?? array() ),
'styles'   => $this->sync_styles_data( $site_data['styles'] ?? array() ),
⋮----
public function get_theme( ?WP_Theme_JSON $base_theme = null ): ?WP_Theme_JSON {
if ( ! $this->is_sync_enabled() ) {
... (100 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/class-theme-controller.php">
namespace Automattic\WooCommerce\EmailEditor\Engine;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preset_Variable_Resolver;
use WP_Block_Template;
use WP_Post;
use WP_Theme_JSON;
use WP_Theme_JSON_Resolver;
⋮----
class Theme_Controller {
⋮----
private WP_Theme_JSON $core_theme;
⋮----
private WP_Theme_JSON $base_theme;
⋮----
private User_Theme $user_theme;
⋮----
private Site_Style_Sync_Controller $site_style_sync_controller;
⋮----
public function __construct() {
$this->core_theme                 = WP_Theme_JSON_Resolver::get_core_data();
⋮----
public function get_theme(): WP_Theme_JSON {
$theme = $this->get_base_theme();
$theme->merge( $this->user_theme->get_theme() );
⋮----
public function get_base_theme(): WP_Theme_JSON {
⋮----
$theme->merge( $this->core_theme );
$theme->merge( $this->base_theme );
⋮----
... (61 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/class-user-theme.php">
namespace Automattic\WooCommerce\EmailEditor\Engine;
⋮----
use WP_Post;
use WP_Theme_JSON;
⋮----
class User_Theme {
⋮----
private ?WP_Post $user_theme_post = null;
⋮----
public function get_theme(): WP_Theme_JSON {
$post       = $this->get_user_theme_post();
⋮----
public function get_user_theme_post(): WP_Post {
$this->ensure_theme_post();
⋮----
throw new \Exception( 'Error creating user theme post' );
⋮----
private function ensure_theme_post(): void {
⋮----
throw new \Exception( 'Error creating user theme post: ' . esc_html( $post_id->get_error_message() ) );
</file>

<file path="packages/php/email-editor/src/Engine/theme.json">
{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3,
  "settings": {
    "color": {
      "customGradient": false,
      "defaultGradients": false,
      "gradients": [],
      "background": true,
      "text": true,
      "link": true,
      "customDuotone": false,
      "defaultDuotone": false
    },
    "layout": {
      "contentSize": "660px",
      "allowEditing": false,
      "allowCustomContentAndWideSize": false
    },
    "background": {
      "backgroundImage": true
    },
    "spacing": {
      "units": ["px"],
      "blockGap": false,
      "padding": true,
      "margin": false,
      "spacingSizes": [
        {
          "name": "1",
... (277 lines truncated)
</file>

<file path="packages/php/email-editor/src/Engine/theme.md">
# Theme.json for the email editor

We use theme.json to define settings and styles for the email editor and we reuse the definitions also in the rendering engine.
The theme is used in combination with the [core's theme.json](https://github.com/WordPress/WordPress/blob/master/wp-includes/theme.json). We load the core's theme.json first and then we merge the email editor's theme.json on top of it.

In this file we want to document settings and styles that are specific to the email editor.

## Settings

- **color**: We disable gradients, because they are not supported in many email clients. We may add the support later.
- **layout**: We set content width to 660px, because it's the most common width for emails. This is meant as a default value.
- **spacing**: We allow only px units, because they are the most reliable in email clients. We may add the support for other units later with some sort of conversion to px. We also disable margins because they are not supported in our renderer (margin collapsing might be tricky).
- **border**: We want to allow all types of borders and border styles.
- **typography**: We enable fontWeight, fontStyle, and letterSpacing because they are supported by our renderer. We disable the dropCap appearance setting because it is not supported. We also define a set of basic font families that are safe to use with emails. The list was copied from the battle-tested legacy editor.

## Styles

- **spacing**: We define default padding for the emails.
- **color**: We define default colors for text and background of the emails.
- **typography**: We define default font family and font size for the emails.
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-abstract-block-renderer.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Block_Renderer;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
use WP_Style_Engine;
⋮----
abstract class Abstract_Block_Renderer implements Block_Renderer {
⋮----
protected ?Rendering_Context $current_rendering_context = null;
⋮----
protected function get_styles_from_block( array $block_styles, $skip_convert_vars = false ) {
return Styles_Helper::get_styles_from_block( $block_styles, $skip_convert_vars );
⋮----
protected function compile_css( ...$styles ): string {
return WP_Style_Engine::compile_css( array_merge( ...$styles ), '' );
⋮----
/**
	 * Extract inner content from a wrapper element.
	 *
	 * Removes the outer wrapper element (e.g., div) and returns only the inner HTML content.
	 * This is useful when you need to strip the wrapper and use only the inner content.
	 *
	 * @param string $block_content Block content with wrapper element.
	 * @param string $tag_name      Tag name of the wrapper element (default: 'div').
	 * @return string Inner content without the wrapper element, or original content if wrapper not found.
	 */
protected function get_inner_content( string $block_content, string $tag_name = 'div' ): string {
... (23 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-audio.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
⋮----
public function render( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
// If we have a valid source, proceed with normal rendering.
$rendered_content = $this->render_content( $block_content, $parsed_block, $rendering_context );
⋮----
// If render_content returns empty (e.g., invalid URL), return empty string.
⋮----
return $this->add_spacer_with_context( $rendered_content, $parsed_block['email_attrs'] ?? array(), $rendering_context );
⋮----
$url    = \wp_get_attachment_url( $attr['id'] );
$meta   = \get_post_meta( $attr['id'], '_wp_attachment_metadata', true );
⋮----
// Audio file from external URL.
⋮----
// Validate URL with proper ordering and comprehensive checks.
⋮----
// Validate URL type and format.
⋮----
// For HTTPS URLs, validate with wp_http_validate_url.
⋮----
// Get spacing from email_attrs for better consistency with core blocks.
⋮----
$table_margin_style = \WP_Style_Engine::compile_css( array_intersect_key( $email_attrs, array_flip( array( 'margin' ) ) ), '' );
⋮----
$icon_image = $this->get_audio_icon_url();
... (18 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-button.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
⋮----
class Button extends Abstract_Block_Renderer {
⋮----
private function get_wrapper_styles( array $block_attributes, Rendering_Context $rendering_context ) {
$block_styles = Styles_Helper::get_block_styles( $block_attributes, $rendering_context, array( 'border', 'background-color', 'color', 'typography', 'spacing' ) );
⋮----
return Styles_Helper::extend_block_styles(
⋮----
private function get_link_styles( array $block_attributes, Rendering_Context $rendering_context ) {
$block_styles = Styles_Helper::get_block_styles( $block_attributes, $rendering_context, array( 'color', 'typography' ) );
⋮----
public function render( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
return $this->render_content( $block_content, $parsed_block, $rendering_context );
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$block_classname = $dom_helper->get_attribute_value_by_tag_name( 'div', 'class' ) ?? '';
$button_link     = $dom_helper->find_element( 'a' );
⋮----
$button_text    = $dom_helper->get_element_inner_html( $button_link ) ? $dom_helper->get_element_inner_html( $button_link ) : '';
$button_url     = $button_link->getAttribute( 'href' ) ? $button_link->getAttribute( 'href' ) : '#';
$data_link_href = $button_link->getAttribute( 'data-link-href' );
⋮----
$wrapper_styles = $this->get_wrapper_styles( $block_attributes, $rendering_context );
... (4 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-buttons.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Layout\Flex_Layout_Renderer;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
⋮----
class Buttons extends Abstract_Block_Renderer {
⋮----
private $flex_layout_renderer;
⋮----
public function __construct(
⋮----
public function render( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
$content     = $this->render_content( $block_content, $parsed_block, $rendering_context );
⋮----
return $this->add_spacer_with_context( $content, $email_attrs, $rendering_context );
⋮----
protected function render_content( $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
return $this->flex_layout_renderer->render_inner_blocks_in_layout( $parsed_block, $rendering_context );
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-column.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
⋮----
class Column extends Abstract_Block_Renderer {
⋮----
protected function add_spacer( $content, $email_attrs ): string {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$this->get_inner_content( $block_content ),
$this->get_block_wrapper( $block_content, $parsed_block, $rendering_context )
⋮----
private function get_block_wrapper( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
$original_wrapper_classname = ( new Dom_Document_Helper( $block_content ) )->get_attribute_value_by_tag_name( 'div', 'class' ) ?? '';
⋮----
'width'             => $rendering_context->get_layout_width_without_padding(),
⋮----
$padding_styles = Styles_Helper::get_block_styles( $block_attributes, $rendering_context, array( 'padding' ) );
$padding_styles = Styles_Helper::extend_block_styles( $padding_styles, array( 'text-align' => $rendering_context->get_default_text_align() ) );
⋮----
$cell_styles = Styles_Helper::get_block_styles( $block_attributes, $rendering_context, array( 'border', 'background', 'background-color', 'color' ) );
$cell_styles = Styles_Helper::extend_block_styles(
⋮----
$wrapper_styles    = Styles_Helper::extend_block_styles(
⋮----
$content_styles    = Styles_Helper::extend_block_styles( Styles_Helper::$empty_block_styles, array( 'vertical-align' => 'top' ) );
... (20 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-columns.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
⋮----
class Columns extends Abstract_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$this->get_inner_content( $block_content ),
$this->getBlockWrapper( $block_content, $parsed_block, $rendering_context )
⋮----
private function getBlockWrapper( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
$original_wrapper_classname = ( new Dom_Document_Helper( $block_content ) )->get_attribute_value_by_tag_name( 'div', 'class' ) ?? '';
⋮----
'width' => $rendering_context->get_layout_width_without_padding(),
⋮----
$columns_styles = Styles_Helper::get_block_styles( $block_attributes, $rendering_context, array( 'padding', 'border', 'background', 'background-color', 'color' ) );
$columns_styles = Styles_Helper::extend_block_styles(
⋮----
'text-align'      => $rendering_context->get_default_text_align(),
⋮----
$columns_content = Table_Wrapper_Helper::render_table_wrapper( '{columns_content}', $columns_table_attrs, array(), array(), false );
⋮----
$margin_wrapper_styles       = Styles_Helper::get_block_styles( $magin_to_padding_attributes, $rendering_context, array( 'padding' ) );
$margin_wrapper_styles       = Styles_Helper::extend_block_styles(
⋮----
return Table_Wrapper_Helper::render_table_wrapper( $columns_content, $wrapper_table_attrs );
... (1 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-cover.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Html_Processing_Helper;
⋮----
class Cover extends Abstract_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
// If we don't have inner content, return empty.
⋮----
// Build the email-friendly layout.
$background_image = $this->extract_background_image( $block_attrs, $parsed_block['innerHTML'] ?? $block_content );
return $this->build_email_layout( $inner_content, $block_attrs, $block_content, $background_image, $rendering_context );
⋮----
private function build_email_layout( string $inner_content, array $block_attrs, string $block_content, string $background_image, Rendering_Context $rendering_context ): string {
⋮----
$original_wrapper_classname = ( new Dom_Document_Helper( $block_content ) )->get_attribute_value_by_tag_name( 'div', 'class' ) ?? '';
⋮----
// Get background color information.
$background_color = $this->get_background_color( $block_attrs, $rendering_context );
⋮----
// Get block styles using the Styles_Helper.
$block_styles   = Styles_Helper::get_block_styles( $block_attrs, $rendering_context, array( 'padding', 'border', 'background-color' ) );
⋮----
$min_height                   = $this->get_minimum_height( $block_attrs );
⋮----
... (71 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-embed.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Audio;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Video;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Html_Processing_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
⋮----
class Embed extends Abstract_Block_Renderer {
⋮----
private int $embed_fetch_count = 0;
⋮----
private function may_attempt_embed_fetch(): bool {
⋮----
private function get_all_supported_providers(): array {
⋮----
private function get_all_provider_configs(): array {
⋮----
private function detect_provider_from_domains( string $content ): string {
$all_providers = $this->get_all_provider_configs();
⋮----
/**
	 * Validate URL using both filter_var and wp_http_validate_url.
	 *
	 * @param string $url URL to validate.
	 * @return bool True if URL is valid.
	 */
private function is_valid_url( string $url ): bool {
⋮----
... (312 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-fallback.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
⋮----
class Fallback extends Abstract_Block_Renderer {
⋮----
protected function render_content( $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$align = $rendering_context->sanitize_text_align( $block_attrs['textAlign'] ?? null )
?? $rendering_context->sanitize_text_align( $block_attrs['align'] ?? null )
?? $rendering_context->get_default_text_align();
⋮----
return Table_Wrapper_Helper::render_table_wrapper( $block_content, $table_attrs, $cell_attrs );
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-gallery.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Html_Processing_Helper;
⋮----
class Gallery extends Abstract_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$columns      = $this->get_columns_from_attributes( $parsed_block['attrs'] ?? array() );
$layout_width = (int) Styles_Helper::parse_value( $rendering_context->get_layout_width_without_padding() );
⋮----
$gallery_images = $this->extract_images_from_gallery_content( $block_content, $parsed_block, $columns, $layout_width );
⋮----
// Build the email-friendly layout.
return $this->build_email_layout( $gallery_images, $parsed_block, $block_content, $rendering_context );
⋮----
/**
	 * Estimate the rendered width (in px) of the gallery cell that holds a given image.
	 *
	 * The gallery packs images into rows of `$columns`. A complete row splits the layout width
	 * evenly, but an incomplete final row is distributed across only its remaining images — a lone
	 * trailing image spans the full width (see {@see build_gallery_row_table()}). Sizing the crop to
	 * the actual cell keeps an image CDN from serving an undersized file for such images.
	 *
	 * @param int $index Zero-based index of the image among the rendered images.
	 * @param int $image_count Total number of rendered images.
... (172 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-group.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
⋮----
class Group extends Abstract_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$this->get_inner_content( $block_content ),
$this->get_block_wrapper( $block_content, $parsed_block, $rendering_context )
⋮----
private function get_block_wrapper( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
$original_classname = ( new Dom_Document_Helper( $block_content ) )->get_attribute_value_by_tag_name( 'div', 'class' ) ?? '';
⋮----
$table_styles = Styles_Helper::get_block_styles( $block_attributes, $rendering_context, array( 'border', 'background', 'background-color', 'color', 'text-align' ) );
$table_styles = Styles_Helper::extend_block_styles(
⋮----
$cell_styles = Styles_Helper::get_block_styles( $block_attributes, $rendering_context, array( 'padding' ) );
⋮----
$cell_styles = $this->remove_horizontal_padding( $cell_styles );
⋮----
return Table_Wrapper_Helper::render_table_wrapper( '{group_content}', $table_attrs, $cell_attrs );
⋮----
private function remove_horizontal_padding( array $cell_styles ): array {
⋮----
return Styles_Helper::extend_block_styles( $cell_styles, array() );
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-image.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
⋮----
class Image extends Abstract_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
$parsed_html = $this->parse_block_content( $block_content );
⋮----
$parsed_block = $this->add_image_size_when_missing( $parsed_block, $image_url );
$image        = $this->add_image_dimensions( $image, $parsed_block );
⋮----
$this->get_block_wrapper( $parsed_block, $rendering_context, $caption, $anchor_tag_href, $anchor_data_link_href )
⋮----
$image_with_wrapper = $this->apply_rounded_style( $image_with_wrapper, $parsed_block );
$image_with_wrapper = $this->apply_image_border_style( $image_with_wrapper, $parsed_block, $class );
⋮----
private function apply_rounded_style( string $block_content, array $parsed_block ): string {
⋮----
$block_content = $this->remove_style_attribute_from_element(
⋮----
$block_content = $this->add_style_to_element(
⋮----
$block_content = $this->remove_style_attribute_from_element( $block_content, array( 'tag_name' => 'img' ), 'border-radius' );
$block_content = $this->add_style_to_element( $block_content, array( 'tag_name' => 'img' ), 'border-radius: 9999px;' );
⋮----
private function add_image_size_when_missing( array $parsed_block, string $image_url ): array {
... (160 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-list-block.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
⋮----
class List_Block extends Abstract_Block_Renderer {
⋮----
public function render( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
$content     = $this->render_content( $block_content, $parsed_block, $rendering_context );
⋮----
return $this->add_spacer_with_context( $content, $email_attrs, $rendering_context );
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
$html     = new \WP_HTML_Tag_Processor( $block_content );
⋮----
if ( $html->next_tag( array( 'tag_name' => $tag_name ) ) ) {
⋮----
$styles = $html->get_attribute( 'style' ) ?? '';
$styles = Styles_Helper::parse_styles_to_array( $styles );
⋮----
// Font size.
⋮----
$theme_data          = $rendering_context->get_theme_json()->get_data();
⋮----
$html->set_attribute( 'style', esc_attr( \WP_Style_Engine::compile_css( $styles, '' ) ) );
$block_content = $html->get_updated_html();
⋮----
$wrapper_style = \WP_Style_Engine::compile_css(
⋮----
// \WP_HTML_Tag_Processor escapes the content, so we have to replace it back
... (1 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-list-item.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
⋮----
class List_Item extends Abstract_Block_Renderer {
⋮----
protected function add_spacer( $content, $email_attrs ): string {
⋮----
protected function render_content( $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-media-text.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
⋮----
class Media_Text extends Abstract_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$media_content = $this->extract_media_from_html( $parsed_block['innerHTML'] ?? $block_content );
⋮----
// If we don't have both media and text content, return empty.
⋮----
// Build the email-friendly layout.
return $this->build_email_layout( $media_content, $text_content, $block_attrs, $block_content, $rendering_context );
⋮----
/**
	 * Extract media content from the HTML block content.
	 *
	 * @param string $block_content Raw block content.
	 * @return string Media HTML content or empty string if not found.
	 */
private function extract_media_from_html( string $block_content ): string {
// Extract inner content from figure element (removing figure wrapper for email compatibility).
⋮----
private function build_email_layout( string $media_content, string $text_content, array $block_attrs, string $block_content, Rendering_Context $rendering_context ): string {
⋮----
$original_wrapper_classname = ( new Dom_Document_Helper( $block_content ) )->get_attribute_value_by_tag_name( 'div', 'class' ) ?? '';
... (24 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-post-content.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
class Post_Content {
⋮----
public function render_stateless( $attributes, $content, $block ): string {
⋮----
// Backup global state.
⋮----
// Set up global state for block rendering.
// This ensures that blocks which depend on global $post work correctly.
$post = $email_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
// Create a query specifically for this post to ensure proper context.
// A synthetic post (ID 0) would make the query fetch latest posts, so
// populate an empty query manually instead.
⋮----
$wp_query = new \WP_Query( array( 'p' => $email_post->ID ) );
⋮----
$wp_query              = new \WP_Query();
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-post-template.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Html_Processing_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
⋮----
class Post_Template extends Abstract_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$list_element = $this->find_post_template_list( $dom );
⋮----
// If we can't find the post-template list, leave the original content untouched so we never
⋮----
$items = $this->extract_list_items( $dom, $list_element );
⋮----
$columns = $this->get_column_count( $parsed_block, $dom, $list_element );
⋮----
$layout_width = (int) Styles_Helper::parse_value( $rendering_context->get_layout_width_without_padding() );
⋮----
return $this->build_grid_table( $items, $columns, $dom, $list_element, $layout_width );
⋮----
private function find_post_template_list( Dom_Document_Helper $dom ): ?\DOMElement {
foreach ( $dom->find_elements( 'ul' ) as $list_element ) {
⋮----
$classes = preg_split( '/\s+/', trim( $dom->get_attribute_value( $list_element, 'class' ) ) );
⋮----
private function extract_list_items( Dom_Document_Helper $dom, \DOMElement $list_element ): array {
... (154 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-quote.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
⋮----
class Quote extends Abstract_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$cite_element     = $dom_helper->find_element( 'cite' );
⋮----
$citation_content = $this->get_citation_wrapper(
$dom_helper->get_element_inner_html( $cite_element ),
⋮----
$cite_element->parentNode->removeChild( $cite_element );
⋮----
$blockquote_element = $dom_helper->find_element( 'blockquote' );
⋮----
? $dom_helper->get_element_inner_html( $blockquote_element )
⋮----
$this->get_block_wrapper( $block_content, $parsed_block, $rendering_context )
⋮----
private function get_citation_wrapper( string $citation_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
// The HTML cite tag should use block gap as margin-top.
$theme_styles    = $rendering_context->get_theme_styles();
⋮----
$citation_styles = Styles_Helper::get_block_styles( $parsed_block['attrs'], $rendering_context, array( 'text-align' ) );
... (24 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-social-link.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
⋮----
class Social_Link extends Abstract_Block_Renderer {
⋮----
protected function render_content( $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-social-links.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Html_Processing_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Social_Links_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
⋮----
class Social_Links extends Abstract_Block_Renderer {
⋮----
private $core_social_link_services_cache = array();
⋮----
private $supported_image_types = array( 'white', 'brand' );
⋮----
protected function render_content( $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$social_link_content = $this->generate_social_link_content(
⋮----
$rendering_context->get_start_side()
⋮----
$this->get_block_wrapper( $block_content, $parsed_block, $rendering_context )
⋮----
/**
	 * Generates the social link content.
	 *
	 * @param array  $block The block data.
	 * @param array  $parent_block_attrs The parent block attributes.
	 * @param bool   $render_gap Whether to render a gap before the item.
	 * @param string $gap_side The physical side used for the horizontal gap.
	 * @return string The generated content.
	 */
... (108 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-table.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Html_Processing_Helper;
⋮----
class Table extends Abstract_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$extracted_data = $this->extract_table_and_caption_from_figure( $block_content );
⋮----
if ( ! $this->is_valid_table_content( $table_content ) ) {
⋮----
// Check for empty table structures - tables with no th or td elements.
⋮----
$html    = new \WP_HTML_Tag_Processor( $table_content );
⋮----
if ( $html->next_tag() ) {
$block_classes = (string) ( $html->get_attribute( 'class' ) ?? '' );
⋮----
// Clean classes for table element.
$block_classes = Html_Processing_Helper::clean_css_classes( $block_classes );
$html->set_attribute( 'class', $block_classes );
$table_content = $html->get_updated_html();
⋮----
$classes = Html_Processing_Helper::clean_css_classes( $classes );
⋮----
... (147 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-text.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Html_Processing_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
⋮----
class Text extends Abstract_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$block_content        = $this->adjustStyleAttribute( $block_content );
⋮----
$html                 = new \WP_HTML_Tag_Processor( $block_content );
⋮----
if ( $html->next_tag() ) {
⋮----
$block_classes = $html->get_attribute( 'class' ) ?? '';
⋮----
// Extract text alignment from has-text-align-* classes before they're potentially modified.
⋮----
Html_Processing_Helper::remove_wrapper_handled_classes( $html );
$block_content = $html->get_updated_html();
⋮----
$block_styles      = Styles_Helper::get_block_styles( $block_attributes, $rendering_context, array( 'spacing', 'border', 'background-color', 'color', 'typography' ) );
⋮----
$email_styles               = $rendering_context->get_theme_styles();
⋮----
$additional_styles['text-align'] = $rendering_context->get_default_text_align();
⋮----
... (26 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/Renderer/Blocks/class-video.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Html_Processing_Helper;
⋮----
class Video extends Cover {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$poster_url = $this->extract_poster_url( $block_attrs, $block_content );
⋮----
// Transform video block into cover block structure and delegate to parent.
$cover_block = $this->transform_to_cover_block( $parsed_block, $poster_url );
return parent::render_content( $block_content, $cover_block, $rendering_context );
⋮----
/**
	 * Extract poster URL from block attributes.
	 * Returns raw URL - escaping should happen at the final output context.
	 *
	 * @param array  $block_attrs Block attributes.
	 * @param string $block_content Original block content (unused, kept for consistency).
	 * @return string Poster URL or empty string.
	 */
private function extract_poster_url( array $block_attrs, string $block_content ): string {
// Check for poster attribute.
// Use esc_url_raw() to sanitize without HTML entity encoding.
// Final escaping happens in Cover block based on output context.
⋮----
/**
... (53 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/class-initializer.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Core;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Layout\Flex_Layout_Renderer;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Abstract_Block_Renderer;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Audio;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Button;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Buttons;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Column;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Columns;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Cover;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Embed;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Fallback;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Gallery;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Group;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Image;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\List_Block;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\List_Item;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Media_Text;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Post_Content;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Post_Template;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Quote;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Video;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Social_Link;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Social_Links;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Table;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Text;
⋮----
class Initializer {
⋮----
... (23 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Core/theme.json">
{
	"$schema": "https://schemas.wp.org/trunk/theme.json",
	"version": 3,
	"styles": {
		"blocks": {
			"core/button": {
				"variations": {}
			},
			"core/quote": {
				"border": {
					"style": "solid",
					"width": "0 0 0 1px",
					"color": "currentColor"
				},
				"spacing": {
					"margin": {
						"right": "0",
						"left": "0"
					},
					"padding": {
						"top": "20px",
						"right": "20px",
						"bottom": "20px",
						"left": "20px"
					}
				},
				"typography": {
					"fontSize": "20px"
				},
				"elements": {
... (33 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Utils/class-dom-document-helper.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Utils;
⋮----
class Dom_Document_Helper {
⋮----
private \DOMDocument $dom;
⋮----
public function __construct( string $html_content ) {
$this->load_html( $html_content );
⋮----
private function load_html( string $html_content ): void {
⋮----
$this->dom = new \DOMDocument();
⋮----
$this->dom->loadHTML( '<?xml encoding="UTF-8">' . $html_content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
⋮----
public function find_element( string $tag_name ): ?\DOMElement {
$elements = $this->dom->getElementsByTagName( $tag_name );
return $elements->item( 0 ) ? $elements->item( 0 ) : null;
⋮----
public function find_elements( string $tag_name ): array {
⋮----
foreach ( $this->dom->getElementsByTagName( $tag_name ) as $element ) {
⋮----
public function get_attribute_value( \DOMElement $element, string $attribute ): string {
return $element->hasAttribute( $attribute ) ? $element->getAttribute( $attribute ) : '';
⋮----
/**
	 * Searches for the first appearance of the given tag name and returns the value of specified attribute.
	 *
	 * @param string $tag_name The tag name to search for.
... (56 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Utils/class-html-processing-helper.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Utils;
⋮----
class Html_Processing_Helper {
⋮----
public static function clean_css_classes( string $classes ): string {
⋮----
// Remove border classes.
⋮----
// Clean up multiple spaces.
⋮----
/**
	 * Remove from an element the class names whose styles the renderer applies to the wrapping table cell.
	 *
	 * Background and border classes are resolved by the CSS inliner wherever they appear. The wrapping
	 * cell keeps the block's original class list *and* receives the same styles inline, so leaving these
	 * classes on the inner element paints them a second time. For an opaque color that is invisible, but
	 * a translucent palette color composites over itself and renders as a visibly darker band inside the
	 * cell's padding.
	 *
	 * @param \WP_HTML_Tag_Processor $html Tag processor positioned on the element to clean.
	 */
public static function remove_wrapper_handled_classes( \WP_HTML_Tag_Processor $html ): void {
$class_attribute = $html->get_attribute( 'class' );
⋮----
if ( '' !== $class_name && self::is_wrapper_handled_class( $class_name ) ) {
$html->remove_class( $class_name );
⋮----
/**
	 * Whether a single class name applies a background or border that the wrapping table cell already renders.
	 *
... (144 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Utils/class-social-links-helper.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Utils;
⋮----
class Social_Links_Helper {
⋮----
public static function detect_whiteish_color( $input_color ) {
⋮----
public static function get_service_brand_color( $service_name ) {
⋮----
/**
	 * Gets the default social link size.
	 *
	 * @return string The default social link size.
	 */
public static function get_default_social_link_size() {
⋮----
public static function get_social_link_size_option_value( $size ) {
</file>

<file path="packages/php/email-editor/src/Integrations/Utils/class-styles-helper.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Utils;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use WP_Style_Engine;
⋮----
class Styles_Helper {
⋮----
public static $empty_block_styles = array(
⋮----
/**
	 * Parse number value from a string.
	 *
	 * @param string|float|int $value String with value and unit or integer value.
	 * @return float
	 */
public static function parse_value( $value ): float {
// Handle numeric values.
⋮----
// Handle string values.
⋮----
/**
	 * Parse styles string to array.
	 *
	 * @param string $styles Styles string.
	 * @return array
	 */
public static function parse_styles_to_array( string $styles ): array {
⋮----
/**
	 * Get normalized block styles by translating color slugs to actual color values.
... (68 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/Utils/class-table-wrapper-helper.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\Utils;
⋮----
class Table_Wrapper_Helper {
⋮----
public static function render_table_cell(
⋮----
$cell_attr_string = self::build_attributes_string( $cell_attrs );
⋮----
/**
	 * Render an Outlook-specific table cell using conditional comments.
	 *
	 * @param string $content The content to wrap.
	 * @param array  $cell_attrs Cell attributes.
	 * @return string The generated table cell HTML with Outlook conditionals.
	 */
public static function render_outlook_table_cell(
⋮----
return '<!--[if mso | IE]>' . self::render_table_cell( $content_with_outlook_conditional, $cell_attrs ) . '<![endif]-->';
⋮----
/**
	 * Render a table wrapper for email blocks.
	 *
	 * @param string $content The content to wrap (e.g., '{block_content}').
	 * @param array  $table_attrs Table attributes to merge with defaults.
	 * @param array  $cell_attrs Cell attributes.
	 * @param array  $row_attrs Row attributes.
	 * @param bool   $render_cell Whether to render the td wrapper (default true).
	 * @return string The generated table wrapper HTML.
	 */
public static function render_table_wrapper(
... (28 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/WooCommerce/Renderer/Blocks/class-abstract-product-block-renderer.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Block_Renderer;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Abstract_Block_Renderer;
⋮----
abstract class Abstract_Product_Block_Renderer extends Abstract_Block_Renderer implements Block_Renderer {
⋮----
protected function get_product_from_context( array $parsed_block ): ?\WC_Product {
⋮----
$post_id = $product->get_id();
</file>

<file path="packages/php/email-editor/src/Integrations/WooCommerce/Renderer/Blocks/class-coupon-code.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Abstract_Block_Renderer;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
⋮----
class Coupon_Code extends Abstract_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
'style' => \WP_Style_Engine::compile_css(
⋮----
return Table_Wrapper_Helper::render_table_wrapper( $block_content, $table_attrs, $cell_attrs );
</file>

<file path="packages/php/email-editor/src/Integrations/WooCommerce/Renderer/Blocks/class-product-button.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
⋮----
class Product_Button extends Abstract_Product_Block_Renderer {
⋮----
private function get_wrapper_styles( array $block_attributes, Rendering_Context $rendering_context ): array {
$block_styles = Styles_Helper::get_block_styles( $block_attributes, $rendering_context, array( 'border', 'background-color', 'color', 'typography', 'spacing' ) );
⋮----
return Styles_Helper::extend_block_styles(
⋮----
private function get_button_styles( array $block_attributes, Rendering_Context $rendering_context ): array {
$block_styles = Styles_Helper::get_block_styles( $block_attributes, $rendering_context, array( 'color', 'typography' ) );
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
$product = $this->get_product_from_context( $parsed_block );
⋮----
// Check if this is a cart-contents collection to customize button text and link.
⋮----
$button_text = $product->add_to_cart_text() ? $product->add_to_cart_text() : __( 'Add to cart', 'woocommerce' );
⋮----
if ( $product->is_type( 'external' ) && $product instanceof \WC_Product_External ) {
$external_url = $product->get_product_url();
$button_url   = $external_url ? $external_url : $product->get_permalink();
⋮----
$button_url = $product->get_permalink();
⋮----
'textAlign'       => $rendering_context->get_default_text_align(),
... (9 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/WooCommerce/Renderer/Blocks/class-product-collection.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use WP_Query;
⋮----
class Product_Collection extends Abstract_Product_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$query = $this->prepare_and_execute_query( $parsed_block, $rendering_context );
⋮----
// Get column count from display layout attributes.
⋮----
$content .= $this->render_product_template( $inner_block, $query, $collection_type, $columns, $rendering_context );
⋮----
private function render_product_template( array $inner_block, \WP_Query $query, string $collection_type, int $columns, Rendering_Context $rendering_context ): string {
if ( ! $query->have_posts() ) {
return $this->render_no_results_message();
⋮----
$posts       = $query->get_posts();
⋮----
return $this->render_product_grid( $products, $inner_block, $collection_type, $columns, $rendering_context );
⋮----
private function render_product_grid( array $products, array $inner_block, string $collection_type, int $columns, Rendering_Context $rendering_context ): string {
⋮----
$theme_styles = $rendering_context->get_theme_styles();
⋮----
// For the first product, use the original email_attrs.
// For subsequent products, add margin-top for spacing between items.
⋮----
... (102 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/WooCommerce/Renderer/Blocks/class-product-image.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Dom_Document_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
⋮----
class Product_Image extends Abstract_Product_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
$product = $this->get_product_from_context( $parsed_block );
⋮----
$attributes = $this->parse_attributes( $parsed_block['attrs'] ?? array() );
⋮----
$image_data = $this->get_product_image_data( $product, $attributes );
⋮----
$parsed_block = $this->add_image_size_when_missing( $parsed_block, $rendering_context );
$attributes   = $this->parse_attributes( $parsed_block['attrs'] ?? array() );
⋮----
$image_html = $this->build_image_html( $image_data, $attributes, $rendering_context );
⋮----
$inner_blocks = $this->process_inner_blocks( $parsed_block, $product, $rendering_context );
⋮----
$combined_content = $this->create_overlay_structure(
⋮----
return $this->apply_email_wrapper( $combined_content, $parsed_block, $rendering_context );
⋮----
private function process_inner_blocks( array $parsed_block, \WC_Product $product, Rendering_Context $rendering_context ): array {
⋮----
$badge_alignment = $rendering_context->get_default_text_align();
... (104 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/WooCommerce/Renderer/Blocks/class-product-price.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
⋮----
class Product_Price extends Abstract_Product_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
$product = $this->get_product_from_context( $parsed_block );
⋮----
$price_content = $this->generate_price_html( $product, $attributes, $rendering_context );
⋮----
return $this->apply_email_wrapper( $price_content, $parsed_block, $rendering_context );
⋮----
private function generate_price_html( \WC_Product $product, array $attributes, Rendering_Context $rendering_context ): string {
$price_html = $this->build_price_from_scratch( $product );
⋮----
$custom_styles = Styles_Helper::get_block_styles( $attributes, $rendering_context, array( 'border', 'background-color', 'color', 'typography', 'spacing' ) );
⋮----
$style_attr = \WP_Style_Engine::compile_css( $price_styles, '' );
⋮----
/**
	 * Build price HTML completely from scratch based on product type.
	 *
	 * @param \WC_Product $product Product object.
	 * @return string
	 */
private function build_price_from_scratch( \WC_Product $product ): string {
$product_type = $product->get_type();
... (32 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/WooCommerce/Renderer/Blocks/class-product-sale-badge.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
⋮----
class Product_Sale_Badge extends Abstract_Product_Block_Renderer {
⋮----
protected function render_content( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
$product = $this->get_product_from_context( $parsed_block );
⋮----
if ( ! $product->is_on_sale() ) {
⋮----
$badge_html = $this->build_badge_html( $sale_text, $attributes, $rendering_context );
return $this->apply_email_wrapper( $badge_html, $parsed_block, $rendering_context );
⋮----
private function build_badge_html( string $sale_text, array $attributes, Rendering_Context $rendering_context ): string {
$align = $rendering_context->resolve_text_align( $attributes['align'] ?? null );
⋮----
$position_style = $this->get_position_style( $align );
⋮----
$custom_styles = Styles_Helper::get_block_styles(
⋮----
$style_attr = \WP_Style_Engine::compile_css(
⋮----
/**
	 * Get positioning styles based on alignment.
	 *
	 * @param string $align Alignment value.
	 * @return array
... (12 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/WooCommerce/class-coupon-code-generator.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks\Coupon_Code;
⋮----
class Coupon_Code_Generator {
⋮----
public function init(): void {
⋮----
public function generate_coupon( string $coupon_code, array $attrs, Rendering_Context $rendering_context ): string {
⋮----
if ( $rendering_context->get( 'is_user_preview' ) ) {
⋮----
$coupon = new \WC_Coupon();
$coupon->set_code( $this->generate_unique_code() );
⋮----
$discount_type = $this->validate_discount_type( $attrs['discountType'] ?? 'percent' );
$coupon->set_discount_type( $discount_type );
⋮----
$coupon->set_amount( (float) $attrs['amount'] );
⋮----
$coupon->set_date_expires( $expiration );
⋮----
$coupon->set_free_shipping( ! empty( $attrs['freeShipping'] ) );
⋮----
$coupon->set_minimum_amount( (float) ( $attrs['minimumAmount'] ?? 0 ) );
$coupon->set_maximum_amount( (float) ( $attrs['maximumAmount'] ?? 0 ) );
$coupon->set_individual_use( ! empty( $attrs['individualUse'] ) );
$coupon->set_exclude_sale_items( ! empty( $attrs['excludeSaleItems'] ) );
⋮----
... (49 lines truncated)
</file>

<file path="packages/php/email-editor/src/Integrations/WooCommerce/class-initializer.php">
namespace Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Abstract_Block_Renderer;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Renderer\Blocks\Fallback;
use Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks\Coupon_Code;
use Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks\Product_Button;
use Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks\Product_Collection;
use Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks\Product_Image;
use Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks\Product_Price;
use Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Renderer\Blocks\Product_Sale_Badge;
⋮----
class Initializer {
⋮----
private array $renderers = array();
⋮----
public function update_block_settings( array $settings ): array {
⋮----
public function render_block( string $block_content, array $parsed_block, Rendering_Context $rendering_context ): string {
⋮----
$block_renderer = $this->get_block_renderer( $parsed_block['blockName'] );
return $block_renderer->render( $block_content, $parsed_block, $rendering_context );
⋮----
private function get_block_renderer( string $block_name ): Abstract_Block_Renderer {
</file>

<file path="packages/php/email-editor/src/Validator/Schema/class-any-of-schema.php">
namespace Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
class Any_Of_Schema extends Schema {
⋮----
protected $schema = array(
⋮----
public function __construct(
⋮----
$this->schema['anyOf'][] = $schema->to_array();
⋮----
public function nullable(): self {
⋮----
return $this->update_schema_property( 'anyOf', $value );
⋮----
public function non_nullable(): self {
⋮----
return $this->update_schema_property( 'any_of', $value );
</file>

<file path="packages/php/email-editor/src/Validator/Schema/class-array-schema.php">
namespace Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
class Array_Schema extends Schema {
⋮----
protected $schema = array(
⋮----
public function items( Schema $schema ): self {
return $this->update_schema_property( 'items', $schema->to_array() );
⋮----
public function minItems( int $value ): self {
return $this->update_schema_property( 'minItems', $value );
⋮----
public function maxItems( int $value ): self {
return $this->update_schema_property( 'maxItems', $value );
⋮----
public function uniqueItems(): self {
return $this->update_schema_property( 'uniqueItems', true );
</file>

<file path="packages/php/email-editor/src/Validator/Schema/class-boolean-schema.php">
namespace Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
class Boolean_Schema extends Schema {
⋮----
protected $schema = array(
</file>

<file path="packages/php/email-editor/src/Validator/Schema/class-integer-schema.php">
namespace Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
class Integer_Schema extends Schema {
⋮----
protected $schema = array(
⋮----
public function minimum( int $value ): self {
return $this->update_schema_property( 'minimum', $value )
->unset_schema_property( 'exclusiveMinimum' );
⋮----
public function exclusiveMinimum( int $value ): self {
⋮----
->update_schema_property( 'exclusiveMinimum', true );
⋮----
public function maximum( int $value ): self {
return $this->update_schema_property( 'maximum', $value )
->unset_schema_property( 'exclusiveMaximum' );
⋮----
public function exclusiveMaximum( int $value ): self {
⋮----
->update_schema_property( 'exclusiveMaximum', true );
⋮----
public function multipleOf( int $value ): self {
return $this->update_schema_property( 'multipleOf', $value );
</file>

<file path="packages/php/email-editor/src/Validator/Schema/class-null-schema.php">
namespace Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
class Null_Schema extends Schema {
⋮----
protected $schema = array(
</file>

<file path="packages/php/email-editor/src/Validator/Schema/class-number-schema.php">
namespace Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
class Number_Schema extends Schema {
⋮----
protected $schema = array(
⋮----
public function minimum( float $value ): self {
return $this->update_schema_property( 'minimum', $value )
->unset_schema_property( 'exclusiveMinimum' );
⋮----
public function exclusiveMinimum( float $value ): self {
⋮----
->update_schema_property( 'exclusiveMinimum', true );
⋮----
public function maximum( float $value ): self {
return $this->update_schema_property( 'maximum', $value )
->unset_schema_property( 'exclusiveMaximum' );
⋮----
public function exclusiveMaximum( float $value ): self {
⋮----
->update_schema_property( 'exclusiveMaximum', true );
⋮----
public function multipleOf( float $value ): self {
return $this->update_schema_property( 'multipleOf', $value );
</file>

<file path="packages/php/email-editor/src/Validator/Schema/class-object-schema.php">
namespace Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
class Object_Schema extends Schema {
⋮----
protected $schema = array(
⋮----
public function properties( array $properties ): self {
return $this->update_schema_property(
⋮----
return $property->to_array();
⋮----
public function additionalProperties( Schema $schema ): self {
return $this->update_schema_property( 'additionalProperties', $schema->to_array() );
⋮----
public function disableAdditionalProperties(): self {
return $this->update_schema_property( 'additionalProperties', false );
⋮----
public function patternProperties( array $properties ): self {
⋮----
$this->validate_pattern( $key );
$pattern_properties[ $key ] = $value->to_array();
⋮----
return $this->update_schema_property( 'patternProperties', $pattern_properties );
⋮----
public function minProperties( int $value ): self {
return $this->update_schema_property( 'minProperties', $value );
⋮----
public function maxProperties( int $value ): self {
... (2 lines truncated)
</file>

<file path="packages/php/email-editor/src/Validator/Schema/class-one-of-schema.php">
namespace Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
class One_Of_Schema extends Schema {
⋮----
protected $schema = array(
⋮----
public function __construct(
⋮----
$this->schema['oneOf'][] = $schema->to_array();
⋮----
public function nullable(): self {
⋮----
return $this->update_schema_property( 'oneOf', $value );
⋮----
public function non_nullable(): self {
⋮----
return $this->update_schema_property( 'one_of', $value );
</file>

<file path="packages/php/email-editor/src/Validator/Schema/class-string-schema.php">
namespace Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Schema;
⋮----
class String_Schema extends Schema {
⋮----
protected $schema = array(
⋮----
public function minLength( int $value ): self {
return $this->update_schema_property( 'minLength', $value );
⋮----
public function maxLength( int $value ): self {
return $this->update_schema_property( 'maxLength', $value );
⋮----
public function pattern( string $pattern ): self {
$this->validate_pattern( $pattern );
return $this->update_schema_property( 'pattern', $pattern );
⋮----
public function formatDateTime(): self {
return $this->update_schema_property( 'format', 'date-time' );
⋮----
public function formatEmail(): self {
return $this->update_schema_property( 'format', 'email' );
⋮----
public function formatHexColor(): self {
return $this->update_schema_property( 'format', 'hex-color' );
⋮----
public function formatIp(): self {
return $this->update_schema_property( 'format', 'ip' );
⋮----
... (6 lines truncated)
</file>

<file path="packages/php/email-editor/src/Validator/class-builder.php">
namespace Automattic\WooCommerce\EmailEditor\Validator;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Schema\Any_Of_Schema;
use Automattic\WooCommerce\EmailEditor\Validator\Schema\Array_Schema;
use Automattic\WooCommerce\EmailEditor\Validator\Schema\Boolean_Schema;
use Automattic\WooCommerce\EmailEditor\Validator\Schema\Integer_Schema;
use Automattic\WooCommerce\EmailEditor\Validator\Schema\Null_Schema;
use Automattic\WooCommerce\EmailEditor\Validator\Schema\Number_Schema;
use Automattic\WooCommerce\EmailEditor\Validator\Schema\Object_Schema;
use Automattic\WooCommerce\EmailEditor\Validator\Schema\One_Of_Schema;
use Automattic\WooCommerce\EmailEditor\Validator\Schema\String_Schema;
⋮----
class Builder {
⋮----
public static function string(): String_Schema {
⋮----
public static function number(): Number_Schema {
⋮----
public static function integer(): Integer_Schema {
⋮----
public static function boolean(): Boolean_Schema {
⋮----
public static function null(): Null_Schema {
⋮----
public static function array( ?Schema $items = null ): Array_Schema {
⋮----
return $items ? $array->items( $items ) : $array;
⋮----
public static function object( ?array $properties = null ): Object_Schema {
⋮----
... (6 lines truncated)
</file>

<file path="packages/php/email-editor/src/Validator/class-schema.php">
namespace Automattic\WooCommerce\EmailEditor\Validator;
⋮----
use function wp_json_encode;
use function rest_get_allowed_schema_keywords;
⋮----
abstract class Schema {
⋮----
protected $schema = array();
⋮----
public function nullable() {
⋮----
return $this->update_schema_property( 'type', is_array( $type ) ? $type : array( $type, 'null' ) );
⋮----
public function non_nullable() {
⋮----
? $this->unset_schema_property( 'type' )
: $this->update_schema_property( 'type', is_array( $type ) ? $type[0] : $type );
⋮----
public function required() {
return $this->update_schema_property( 'required', true );
⋮----
public function optional() {
return $this->unset_schema_property( 'required' );
⋮----
public function title( string $title ) {
return $this->update_schema_property( 'title', $title );
⋮----
public function description( string $description ) {
return $this->update_schema_property( 'description', $description );
⋮----
... (26 lines truncated)
</file>

<file path="packages/php/email-editor/src/Validator/class-validation-exception.php">
namespace Automattic\WooCommerce\EmailEditor\Validator;
⋮----
use Automattic\WooCommerce\EmailEditor\UnexpectedValueException;
use WP_Error;
⋮----
class Validation_Exception extends UnexpectedValueException {
⋮----
protected $wp_error;
⋮----
public static function create_from_wp_error( WP_Error $wp_error ): self {
$exception           = self::create()
->withMessage( $wp_error->get_error_message() );
⋮----
public function get_wp_error(): WP_Error {
</file>

<file path="packages/php/email-editor/src/Validator/class-validator.php">
namespace Automattic\WooCommerce\EmailEditor\Validator;
⋮----
use JsonSerializable;
use stdClass;
use WP_Error;
⋮----
class Validator {
⋮----
public function validate( Schema $schema, $value, string $param_name = 'value' ) {
return $this->validate_schema_array( $schema->to_array(), $value, $param_name );
⋮----
public function validate_schema_array( array $schema, $value, string $param_name = 'value' ) {
$result = $this->validate_and_sanitize_value_from_schema( $value, $schema, $param_name );
⋮----
throw Validation_Exception::create_from_wp_error( $result );
⋮----
private function validate_and_sanitize_value_from_schema( $value, array $schema, string $param_name ) {
⋮----
return $this->validate_and_sanitize_any_of( $value, $schema, $param_name );
⋮----
return $this->validate_and_sanitize_one_of( $value, $schema, $param_name );
⋮----
return $this->get_type_error( $param_name, $full_type );
⋮----
$result = $this->validate_and_sanitize_value_from_schema( $v, $schema['items'], $param_name . '[' . $i . ']' );
⋮----
$value = (array) ( $value instanceof JsonSerializable ? $value->jsonSerialize() : $value );
⋮----
$result = $this->validate_and_sanitize_value_from_schema( $v, $schema['properties'][ $k ], $param_name . '[' . $k . ']' );
⋮----
... (10 lines truncated)
</file>

<file path="packages/php/email-editor/src/class-bootstrap.php">
namespace Automattic\WooCommerce\EmailEditor;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Email_Editor;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Initializer as CoreEmailEditorIntegration;
use Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Coupon_Code_Generator;
use Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Initializer as WooCommerceEmailEditorIntegration;
⋮----
class Bootstrap {
⋮----
private $email_editor;
⋮----
private $core_email_editor_integration;
⋮----
private $woocommerce_email_editor_integration;
⋮----
public function __construct(
⋮----
public function init(): void {
⋮----
$coupon_generator->init();
⋮----
public function initialize(): void {
$this->email_editor->initialize();
⋮----
public function setup_email_editor_integrations(): bool {
$this->core_email_editor_integration->initialize();
</file>

<file path="packages/php/email-editor/src/class-container.php">
namespace Automattic\WooCommerce\EmailEditor;
⋮----
class Container {
⋮----
protected array $services = array();
⋮----
protected array $instances = array();
⋮----
public function __unserialize( array $data ): void {
throw new \Exception( 'Deserialization of Container is not allowed for security reasons.' );
⋮----
public function set( string $name, callable $callback ): void {
⋮----
public function get( string $name ): object {
⋮----
throw new \Exception( esc_html( "Service not found: $name" ) );
</file>

<file path="packages/php/email-editor/src/class-email-css-inliner.php">
namespace Automattic\WooCommerce\EmailEditor;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\Css_Inliner;
⋮----
class Email_Css_Inliner implements Css_Inliner {
⋮----
private $inliner;
⋮----
public function from_html( string $unprocessed_html ): self {
$inliner_class = $this->get_inliner_class();
⋮----
$that->inliner = $inliner_class::fromHtml( $unprocessed_html );
⋮----
public function inline_css( string $css = '' ): self {
⋮----
throw new \LogicException( 'You must call from_html before calling inline_css' );
⋮----
$this->inliner->inlineCss( $css );
⋮----
public function render(): string {
⋮----
throw new \LogicException( 'You must call from_html before calling render' );
⋮----
return $this->inliner->render();
⋮----
private function get_inliner_class(): string {
⋮----
throw new \Exception( 'CssInliner class not found' );
</file>

<file path="packages/php/email-editor/src/class-email-editor-container.php">
namespace Automattic\WooCommerce\EmailEditor;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Assets_Manager;
use Automattic\WooCommerce\EmailEditor\Engine\Dependency_Check;
use Automattic\WooCommerce\EmailEditor\Engine\Email_Api_Controller;
use Automattic\WooCommerce\EmailEditor\Engine\Email_Editor;
use Automattic\WooCommerce\EmailEditor\Engine\Patterns\Patterns;
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
use Automattic\WooCommerce\EmailEditor\Engine\Personalizer;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Content_Renderer;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Postprocessors\Highlighting_Postprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Postprocessors\Variables_Postprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors\Blocks_Width_Preprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors\Cleanup_Preprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors\Spacing_Preprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors\Typography_Preprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Preprocessors\Quote_Preprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Postprocessors\Border_Style_Postprocessor;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Process_Manager;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\Renderer;
use Automattic\WooCommerce\EmailEditor\Engine\Send_Preview_Email;
use Automattic\WooCommerce\EmailEditor\Engine\Settings_Controller;
use Automattic\WooCommerce\EmailEditor\Engine\Templates\Templates;
use Automattic\WooCommerce\EmailEditor\Engine\Templates\Templates_Registry;
use Automattic\WooCommerce\EmailEditor\Engine\Theme_Controller;
use Automattic\WooCommerce\EmailEditor\Engine\User_Theme;
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger;
use Automattic\WooCommerce\EmailEditor\Engine\Site_Style_Sync_Controller;
use Automattic\WooCommerce\EmailEditor\Integrations\Core\Initializer as CoreInitializer;
use Automattic\WooCommerce\EmailEditor\Integrations\WooCommerce\Initializer as WooCommerceInitializer;
... (54 lines truncated)
</file>

<file path="packages/php/email-editor/src/class-package.php">
namespace Automattic\WooCommerce\EmailEditor;
⋮----
class Package {
⋮----
public static function init() {
Email_Editor_Container::init();
⋮----
public static function get_version() {
⋮----
public static function get_path() {
</file>

<file path="packages/php/email-editor/src/exceptions.php">
namespace Automattic\WooCommerce\EmailEditor;
⋮----
interface HttpAwareException {
public function getHttpStatusCode(): int;
⋮----
abstract class Exception extends \Exception {
⋮----
private $errors = [];
⋮----
final public function __construct(string $message = '', int $code = 0, ?\Throwable $previous = null) {
parent::__construct($message, $code, $previous);
⋮----
/** @return static */
public static function create(?\Throwable $previous = null) {
⋮----
public function withMessage(string $message) {
⋮----
public function withCode(int $code) {
⋮----
/**
   * @param string[] $errors
   * @return static
   */
public function withErrors(array $errors) {
⋮----
public function withError(string $id, string $error) {
⋮----
/**
   * @return string[]
   */
... (33 lines truncated)
</file>

<file path="packages/php/email-editor/tasks/phpstan/composer.json">
{
	"name": "woocommerce/email-editor-phpstan",
	"description": "PHPStan analysis tasks for WooCommerce Email Editor",
	"type": "project",
	"require": {
		"php": ">=7.4"
	},
	"require-dev": {
		"phpstan/phpstan": "^2.1",
		"phpstan/phpstan-phpunit": "^2.0",
		"php-stubs/woocommerce-stubs": "^9.8",
		"php-stubs/wordpress-tests-stubs": "^6.8",
		"szepeviktor/phpstan-wordpress": "^2.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	}
}
</file>

<file path="packages/php/email-editor/tasks/phpstan/phpstan-7.neon">
# Use the main phpstan config
includes:
	- phpstan.neon

# Rewrite tested PHP version
parameters:
	phpVersion: 70400

	# Ignore specific errors
	ignoreErrors:
		- # str_starts_with is not available in PHP 7.4. but polyfilled in core.
			message: '#^Function str_starts_with not found\.$#'
		- # str_ends_with is not available in PHP 7.4. but polyfilled in core.
			message: '#^Function str_ends_with not found\.$#'
</file>

<file path="packages/php/email-editor/tasks/phpstan/phpstan.neon">
parameters:
	level: 9
	phpVersion: 80400
	tmpDir: temp
	bootstrapFiles:
		- ../../vendor/autoload.php
		- vendor/autoload.php
		- ../../tests/unit/stubs.php # The stubs file contains mocks for some WP classes.
		- vendor/php-stubs/woocommerce-stubs/woocommerce-stubs.php
		- vendor/php-stubs/woocommerce-stubs/woocommerce-packages-stubs.php
		- vendor/php-stubs/wordpress-tests-stubs/wordpress-tests-stubs.php

	paths:
		- ../../src
		- ../../tests

	# Treat PHPDoc types as certain
	treatPhpDocTypesAsCertain: false

	# Ignore specific errors
	ignoreErrors:
		- # There is incorrect type hint for WP_HTML_Tag_Processor in the WP Stubs
			message: '#^Parameter \#1 \$query of method WP_HTML_Tag_Processor::next_tag\(\) expects array{tag_name\?: string\|null, match_offset\?: int\|null, class_name\?: string\|null, tag_closers\?: string\|null\}\|null, string given\.$#'
			path: ../../tests/integration/Engine/Renderer/ContentRenderer/Content_Renderer_Test.php
			count: 1
		- # We would need to specify all arrays. This matches now more than 100 errors.
			identifier: missingType.iterableValue

	excludePaths:
		analyseAndScan:
... (8 lines truncated)
</file>

<file path="packages/php/email-editor/tasks/phpstan/run-phpstan.sh">
set -e
cd "$(dirname "$0")"  # Ensure we're in the script directory
# Ensure composer is installed
if ! command -v composer >/dev/null 2>&1; then
  echo "❌ Composer is not installed. Please install Composer first."
  exit 1
fi
# Determine which PHPStan config file to use
CONFIG_FILE="phpstan.neon"
for arg in "$@"; do
  if [ "$arg" = "php7" ]; then
    CONFIG_FILE="phpstan-7.neon"
    break
  fi
done
if ! ./vendor/bin/phpstan --version >/dev/null 2>&1; then
  echo "🔧 PHPStan not found. Installing dependencies..."
  composer install --quiet
fi
echo "▶️ Running PHPStan with config: $CONFIG_FILE"
vendor/bin/phpstan analyse -c "$CONFIG_FILE" --memory-limit=2G
CLEANUP=true
for arg in "$@"; do
  if [ "$arg" = "--skip-cleanup" ]; then
    CLEANUP=false
    break
  fi
done
if [ "$CLEANUP" = true ]; then
  echo "🧹 Cleaning up PHPStan directories."
... (4 lines truncated)
</file>

<file path="packages/php/email-editor/tasks/build-package.sh">
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PACKAGE_DIR="$(dirname "$SCRIPT_DIR")"
BUILD_DIR="$PACKAGE_DIR/build"
echo "🚀 Preparing email-editor package for Packagist.org publishing..."
if [ -d "$BUILD_DIR" ]; then
    echo "🧹 Cleaning up existing build directory..."
    rm -rf "$BUILD_DIR"
fi
echo "📁 Creating build directory structure..."
mkdir -p "$BUILD_DIR/woocommerce/email-editor"
echo "📝 Creating mirrors.txt file..."
echo "woocommerce/email-editor" > "$BUILD_DIR/mirrors.txt"
echo "📋 Copying package files..."
rsync -avhW --quiet \
    "$PACKAGE_DIR/src" \
    "$PACKAGE_DIR/composer.json" \
    "$PACKAGE_DIR/composer.lock" \
    "$PACKAGE_DIR/changelog.md" \
    "$PACKAGE_DIR/license.txt" \
    "$PACKAGE_DIR/SECURITY.md" \
    "$BUILD_DIR/woocommerce/email-editor/"
echo "📋 Copying vendor-prefixed directory..."
mkdir -p "$BUILD_DIR/woocommerce/email-editor/vendor-prefixed"
rsync -avhW --quiet \
    "$PACKAGE_DIR/vendor-prefixed/classes" \
    "$PACKAGE_DIR/vendor-prefixed/packages" \
    "$PACKAGE_DIR/vendor-prefixed/LICENSE" \
    "$BUILD_DIR/woocommerce/email-editor/vendor-prefixed/"
echo "📝 Copying mirror-readme.md as README.md..."
... (3 lines truncated)
</file>

<file path="packages/php/email-editor/tasks/mirror-readme.md">
# WooCommerce Email Editor

This package covers functionality for bootstrapping the email editor JS application and code for rendering emails from Gutenberg blocks.

Note: This repository is a mirror used only for releasing the package. The package is developed in [the WooCommerce monorepo](https://github.com/woocommerce/woocommerce/tree/trunk/packages/php/email-editor).
</file>

<file path="packages/php/email-editor/.lintstagedrc.json">
{
	"*.php": [
		"../../../mailpoet/tools/vendor/composer.phar code-style-fix",
		"../../../mailpoet/tools/vendor/composer.phar phpstan"
	],
	"*": "../../../mailpoet/tools/vendor/composer.phar code-style"
}
</file>

<file path="packages/php/email-editor/.wp-env.json">
{
	"phpVersion": "8.1",
	"plugins": [
		"."
	],
	"config": {
		"JETPACK_AUTOLOAD_DEV": true,
		"WP_DEBUG_LOG": true,
		"WP_DEBUG_DISPLAY": true,
		"ALTERNATE_WP_CRON": true
	},
	"mappings": {
	},
	"env": {
		"development": {
			"port": 8887
		},
		"tests": {
			"port": 8087,
			"plugins": [
				"."
			],
			"themes": [],
			"config": {
			}
		}
	}
}
</file>

<file path="packages/php/email-editor/changelog.md">
# Changelog 

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.17.2](https://github.com/woocommerce/email-editor/releases/tag/2.17.2) - 2026-09-09 

-   Patch - Keep Media & Text blocks in normal document flow so a button placed after one no longer paints its background across it. The wrapper table's align="left" rendered as a float in email clients, pulling the block out of flow so the following block failed to clear it. Alignment is preserved via the existing text-align CSS. [#68443]

## [2.17.1](https://github.com/woocommerce/email-editor/releases/tag/2.17.1) - 2026-09-07 

-   Patch - Restrict the send preview email endpoint to posts of registered email post types. [#68414]

## [2.17.0](https://github.com/woocommerce/email-editor/releases/tag/2.17.0) - 2026-09-03 

-   Patch - Ensure pill-shaped social link padding uses locale-independent decimal formatting in rendered emails. [#67790]
-   Patch - Guard against non-array return values from the woocommerce_email_editor_preload_rest_api_routes filter. [#68021]
-   Patch - Preload the recent emails used by the template selection modal, and add the woocommerce_email_editor_preload_rest_api_routes filter. [#67911]
-   Patch - Render spacing between Social Links icons in emails and match pill-shape icon padding with the editor. [#67642]
-   Patch - Render the email editor HTML only once per request — a plugin calling WP_Screen::get() from admin_enqueue_scripts (e.g. Yoast SEO Premium) re-fires the replace_editor filter mid-render and echoed a second editor container that broke the editor [#68150]
-   Minor - Add a value-interception extension point to the Personalizer. [#66874]

## [2.16.1](https://github.com/woocommerce/email-editor/releases/tag/2.16.1) - 2026-08-14 

-   Patch - Render a block's background color once instead of twice, which made a translucent palette color appear darker than intended. [#67673]

## [2.16.0](https://github.com/woocommerce/email-editor/releases/tag/2.16.0) - 2026-08-12 

-   Patch - Center table header cells in rendered emails when no alignment is set, so they match the editor canvas instead of falling back to left. [#67443]
-   Patch - Prevent inline button wrapper tables from leaving extra baseline space below buttons in rendered block emails. [#67466]
-   Patch - Prevent long unbreakable words in paragraph, heading, and site title blocks from expanding the wrapping table and breaking the rendered email layout. [#67519]
... (249 lines truncated)
</file>

<file path="packages/php/email-editor/composer.json">
{
	"name": "woocommerce/email-editor",
	"description": "Email editor based on WordPress Gutenberg package.",
	"type": "wordpress-plugin",
	"license": "GPL-2.0-or-later",
	"prefer-stable": true,
	"minimum-stability": "dev",
	"version": "2.17.2",
	"autoload": {
		"classmap": [
			"src/",
			"vendor-prefixed/"
		]
	},
	"autoload-dev": {
		"classmap": [
			"tests/unit/"
		]
	},
	"require": {
		"php": ">=7.4"
	},
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0",
		"phpunit/phpunit": "^9.6",
		"woocommerce/woocommerce-sniffs": "1.0.0",
		"yoast/phpunit-polyfills": "^4.0"
	},
	"config": {
		"platform": {
... (40 lines truncated)
</file>

<file path="packages/php/email-editor/development.md">
# Development

## Local Development

There are two ways to develop this package as a part of the WooCommerce plugin:

### 1. Using wp-env Mappings

You can extend your `.wp-env.override.json` file to map this package directly to have your changes up to date:

```json
{
  ...
  "env": {
    "development": {
      "mappings": {
        ...
        "wp-content/plugins/woocommerce/packages/email-editor": "../../packages/php/email-editor"
      }
    }
  }
}
```

### 2. Using Build and Watch Commands

Alternatively, you can use the watch command within the WooCommerce plugin to keep your changes synchronized during development:

Run the following command. It will watch for changes, rebuild assets if necessary, and sync the package files automatically:

... (22 lines truncated)
</file>

<file path="packages/php/email-editor/email-editor.php">

</file>

<file path="packages/php/email-editor/license.txt">
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

This program incorporates work covered by the following copyright and
permission notices:

  html2text is Copyright (c) 2019 Jevon Wright
  https://github.com/soundasleep/html2text

  html2text is released under the MIT License
  https://github.com/soundasleep/html2text/blob/83502b6f8f1aaef8e2e238897199d64f284b4af3/LICENSE.md

===================================


GNU GENERAL PUBLIC LICENSE
   Version 2, June 1991

Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
... (336 lines truncated)
</file>

<file path="packages/php/email-editor/package.json">
{
	"name": "@woocommerce/email-editor-config",
	"description": "Email editor based on WordPress Gutenberg package.",
	"scripts": {
		"changelog": "XDEBUG_MODE=off composer install --quiet && composer exec -- changelogger",
		"update:php": "XDEBUG_MODE=off composer update --quiet",
		"lint": "pnpm --if-present '/^lint:lang:.*$/'",
		"lint:fix": "pnpm --if-present '/^lint:fix:lang:.*$/'",
		"lint:fix:lang:php": "composer run-script phpcbf",
		"lint:lang:php": "composer run-script phpcs",
		"phpstan": "cd tasks/phpstan && ./run-phpstan.sh",
		"phpstan:php8": "cd tasks/phpstan && ./run-phpstan.sh",
		"phpstan:php7": "cd tasks/phpstan && ./run-phpstan.sh php7",
		"postinstall": "sh vendor-prefixed/setup.sh && XDEBUG_MODE=off composer install --quiet",
		"env:test": "pnpm env:dev",
		"env:dev": "pnpm wp-env start --update",
		"env:dev:stop": "pnpm wp-env stop",
		"test:unit": "composer run-script test:unit",
		"test:php:ci": "pnpm test:unit && pnpm test:integration",
		"test:integration": "composer run-script test:integration",
		"build:composer-package": "bash tasks/build-package.sh"
	},
	"license": "GPL-2.0-or-later",
	"devDependencies": {
		"@wordpress/env": "11.9.0",
		"rimraf": "5.0.5"
	},
	"config": {
		"ci": {
			"lint": {
... (58 lines truncated)
</file>

<file path="packages/php/email-editor/phpcs.xml">
<?xml version="1.0"?>
<ruleset name="Custom WordPress Standards">
	<rule ref="WordPress"/>
	<file>.</file>
	<rule ref="WordPress.Files.FileName">
		<exclude-pattern>tests/*</exclude-pattern>
	</rule>
	<rule ref="WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents">
		<exclude-pattern>src</exclude-pattern>
	</rule>
	<rule ref="Universal.Files.SeparateFunctionsFromOO.Mixed">
		<exclude-pattern>tests/unit/_bootstrap.php</exclude-pattern>
	</rule>
	<rule ref="PSR2.Methods.MethodDeclaration.Underscore">
		<exclude-pattern>tests/integration</exclude-pattern>
		<exclude-pattern>tests/unit</exclude-pattern>
	</rule>
	<exclude-pattern>vendor/*</exclude-pattern>
	<exclude-pattern>node_modules/*</exclude-pattern>
	<exclude-pattern>tasks/phpstan/temp/*</exclude-pattern>
	<exclude-pattern>vendor-prefixed/*</exclude-pattern>
	<exclude-pattern>build/*</exclude-pattern>
</ruleset>
</file>

<file path="packages/php/email-editor/README.md">
# WooCommerce Email Editor

This folder contains the code for the WooCommerce Email Editor PHP Package.

This package covers functionality for bootstrapping the email editor JS application and code for rendering emails from Gutenberg blocks.

You can locate the JS package in [`packages/js/email-editor`](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/email-editor)

## Workflow Commands

Note: The package is developed in [the WooCommerce monorepo](https://github.com/woocommerce/woocommerce/tree/trunk/packages/php/email-editor).

We use `composer` run scripts to run the commands. You can run them using `composer run <command>`.
If you don't have `composer` installed globally, you need to install it globally. [Please check how to install it](https://getcomposer.org/doc/00-intro.md).

```bash
composer run env:start                             # start testing environment
composer run env:stop                              # stop testing environment
composer run test:unit                             # runs all the unit tests
composer run test:unit -- [path_to_tests]          # runs a single unit test or a directory of tests
composer run test:integration                      # runs all the integrations tests
composer run test:integration -- [path_to_tests]   # run a single integration test or a directory of tests
composer code-style                                # checks the code style
```

## PHPStan Commands

The following commands are available via pnpm for running PHP static analysis:

```bash
... (146 lines truncated)
</file>

<file path="packages/php/email-editor/SECURITY.md">
# Security Policy

Full details of the Automattic Security Policy can be found on [automattic.com/security](https://automattic.com/security/).

## Reporting a Vulnerability

**For responsible disclosure of security issues and to be eligible for our bug bounty program, please submit your report based on instructions found on [automattic.com/security](https://automattic.com/security).**

## Guidelines

We're committed to working with security researchers to resolve the vulnerabilities they discover. You can help us by following these guidelines:

*   Follow [HackerOne's disclosure guidelines](https://www.hackerone.com/disclosure-guidelines).
*   Pen-testing Production:
    *   Please **setup a local environment** instead whenever possible. Most of our code is open source (see above).
    *   If that's not possible, **limit any data access/modification** to the bare minimum necessary to reproduce a PoC.
    *   **Don't automate form submissions!** That's very annoying for us, because it adds extra work for the volunteers who manage those systems, and reduces the signal/noise ratio in our communication channels.
    *   To be eligible for a bounty, please follow all of these guidelines.
*   Be Patient - Give us a reasonable time to correct the issue before you disclose the vulnerability.

We also expect you to comply with all applicable laws. You're responsible to pay any taxes associated with your bounties.
</file>

<file path="packages/php/email-editor/writing-tests.md">
# Writing Tests for WooCommerce Email Editor PHP Library

## Table of Contents

1. [Prerequisites](#prerequisites)
2. [Test Structure](#test-structure)
3. [Unit Tests](#unit-tests)
4. [Integration Tests](#integration-tests)
5. [Best Practices](#best-practices)
6. [Debugging Tests](#debugging-tests)

## Prerequisites

1. **Environment Setup**:

   ```bash
   # Install wp-env
   npm install
   
   # Start test environment
   composer run env:start
   ```

2. **Required Dependencies**:
   - Node
   - PNPM
   - Docker (for wp-env)
   - Composer

## Test Structure
... (205 lines truncated)
</file>

<file path="packages/php/monorepo-plugin/src/JetpackManifestEditor.php">
namespace Automattic\WooCommerce\Monorepo\Composer;
⋮----
use Composer\Composer;
use Composer\IO\IOInterface;
use Composer\Package\RootPackageInterface;
use Composer\Util\Filesystem;
use RuntimeException;
⋮----
class JetpackManifestEditor {
⋮----
private $composer;
⋮----
private $io;
⋮----
private $filesystem;
⋮----
public function __construct( Composer $composer, IOInterface $io ) {
⋮----
public function update_autoload_manifests( RootPackageInterface $root_package ) {
⋮----
$manifest_dir = $this->composer->getConfig()->get( 'vendor-dir' ) . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR;
⋮----
$new_version = $root_package->getVersion();
⋮----
if ( $root_package->getVersion() === $new_version ) {
⋮----
$this->io->write( "<info>Updating Merged Feature Plugin Autoloads ($manifest_dir)</info>" );
⋮----
$this->update_manifest_versions( $manifest_dir, 'jetpack_autoload_classmap.php', $new_version );
$this->update_manifest_versions( $manifest_dir, 'jetpack_autoload_psr4.php', $new_version );
... (6 lines truncated)
</file>

<file path="packages/php/monorepo-plugin/src/Plugin.php">
namespace Automattic\WooCommerce\Monorepo\Composer;
⋮----
use Composer\Composer;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;
use Composer\Script\Event;
use Composer\Script\ScriptEvents;
⋮----
class Plugin implements PluginInterface, EventSubscriberInterface {
⋮----
private $composer;
⋮----
private $io;
⋮----
public function activate( Composer $composer, IOInterface $io ) {
⋮----
public function deactivate( Composer $composer, IOInterface $io ) { }
⋮----
public function uninstall( Composer $composer, IOInterface $io ) { }
⋮----
public static function getSubscribedEvents() {
⋮----
public function onPostAutoloadDump( Event $event ) {
$root_package = $this->composer->getPackage();
⋮----
$manifest_editor->update_autoload_manifests( $root_package );
⋮----
public function onPreAutoloadDump( Event $event ) {
⋮----
... (4 lines truncated)
</file>

<file path="packages/php/monorepo-plugin/autoload-dev.php">
$reference_point = ( new \ReflectionClass( \Automattic\WooCommerce\Autoloader::class ) )->getFileName();
</file>

<file path="packages/php/monorepo-plugin/composer.json">
{
    "name": "woocommerce/monorepo-plugin",
    "type": "composer-plugin",
    "require": {
        "composer-plugin-api": "^2.0"
    },
    "require-dev": {
        "composer/composer": "^2.0",
        "wp-coding-standards/wpcs": "^3.0"
    },
    "autoload": {
        "psr-4": {
            "Automattic\\WooCommerce\\Monorepo\\Composer\\": "src/"
        }
    },
    "extra": {
        "class": "Automattic\\WooCommerce\\Monorepo\\Composer\\Plugin"
    },
    "config": {
        "platform": {
            "php": "7.4"
        },
        "allow-plugins": {
            "dealerdirect/phpcodesniffer-composer-installer": true
        }
    }
}
</file>

<file path="packages/php/monorepo-plugin/phpcs.xml">
<?xml version="1.0"?>
<ruleset name="WordPress Coding Standards">
	<file>src/</file>
	<arg value="ps" />
	<arg name="parallel" value="8" />
	<rule ref="WordPress-Core" />
	<rule ref="WordPress.Files.FileName.NotHyphenatedLowercase">
		<exclude-pattern>src/</exclude-pattern>
	</rule>
    <rule ref="WordPress.Files.FileName.InvalidClassFileName">
		<exclude-pattern>src/</exclude-pattern>
	</rule>
</ruleset>
</file>

<file path="packages/php/remote-specs-validation/changelog/.gitkeep">

</file>

<file path="packages/php/remote-specs-validation/changelog/56384-fix-total-payments-volume-processor">
Significance: patch
Type: fix

Fix Total Payments Volume Processor validation logic and improved schema definitions
</file>

<file path="packages/php/remote-specs-validation/changelog/58941-dev-consolidate-packages-license-version">
Significance: patch
Type: dev

Monorepo: consolidate packages licenses to `GPL-2.0-or-later`.
</file>

<file path="packages/php/remote-specs-validation/changelog/dev-ci-lint-monorepo-job-update">
Significance: patch
Type: dev

CI: liverage composer packages cache in lint monorepo job
</file>

<file path="packages/php/remote-specs-validation/changelog/remove-sendcloud-shipping-partner">
Significance: patch
Type: dev

Remove Sendcloud from test mock data since we don't support it anymore
</file>

<file path="packages/php/remote-specs-validation/changelog/resync-composer-locks">
Significance: patch
Type: dev

Update Composer dependencies and pin platform PHP to 7.4 for reproducible resolution.
</file>

<file path="packages/php/remote-specs-validation/changelog/woo6-108-resolve-high-npm-alerts">
Significance: patch
Type: dev

Update npm dependencies that resolve high-severity security advisories.
</file>

<file path="packages/php/remote-specs-validation/src/.gitkeep">

</file>

<file path="packages/php/remote-specs-validation/src/RemoteSpecValidationResult.php">
namespace Automattic\WooCommerce\RemoteSpecsValidation;
⋮----
use Opis\JsonSchema\Errors\ErrorFormatter;
use Opis\JsonSchema\ValidationResult;
⋮----
class RemoteSpecValidationResult {
⋮----
private $result;
⋮----
public function __construct(ValidationResult $result) {
⋮----
public function is_valid() {
return $this->result->isValid();
⋮----
public function get_result() {
⋮----
public function get_errors($formatter = null) {
if ( !$this->result->isValid() ) {
⋮----
return $formatter->format( $this->result->error() );
⋮----
return ( new ErrorFormatter() )->format( $this->result->error() );
</file>

<file path="packages/php/remote-specs-validation/src/RemoteSpecValidator.php">
namespace Automattic\WooCommerce\RemoteSpecsValidation;
⋮----
use Opis\JsonSchema\Validator;
⋮----
class RemoteSpecValidator {
⋮----
private $schema;
⋮----
private static $supported_bundles = [
⋮----
public function __construct( $json_schema_string ) {
⋮----
public static function create_from_file( $json_schema_path ) {
⋮----
public static function create_from_bundle( $bundle ) {
return new self( static::get_bundle_json( $bundle ) );
⋮----
public static function get_bundle_json( $bundle) {
⋮----
throw new \InvalidArgumentException( "Unsupported bundle: $bundle. ".
⋮----
public function validate( $spec ) {
⋮----
return new RemoteSpecValidationResult( $validator->validate( $spec, $this->schema ) );
</file>

<file path="packages/php/remote-specs-validation/changelog.md">
# Changelog

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.2](https://packagist.org/packages/woocommerce/remote-specs-validation#1.0.2) - 2024-04-12 

* Fix - Fix base_location_state and base_location_country value type [#51169]
* Update - Bump all remote spec endpoints to version `2.0`. [#45298]
* Update - Remove ToS acceptance where unnecessary [#46003]
* Update - Update Woo.com references to WooCommerce.com. [#46259]
* Dev - Fix whitespace in package.json [#44902]
* Tweak - Fix typos. [#49207]
* Tweak - Rename Google Listings and Ads with Google for WooCommerce #### Comment <!-- If the changes in this pull request don't warrant a changelog entry, you can alternatively supply a comment here. Note that comments are only accepted with a significance of "Patch" --> [#47614]
* Tweak - Rename Google Listings and Ads with Google for WooCommerce [#47614]


## [1.0.1](https://packagist.org/packages/woocommerce/remote-specs-validation#1.0.1) - 2024-02-28 

* Update - Accept JSON schema string as constructor argument instead of file path -- this is more fleixble. [#45151]

## [1.0.0](https://packagist.org/packages/woocommerce/remote-specs-validation#1.0.0) - 2024-02-21 

* Add - Add JSON Schema files [#44484]
* Add - Add project scaffolding [#44419]
* Add - Support range operator in Remote Inbox Notification [#45201]
* Add - Updated shipstation copy [#48549]
</file>

<file path="packages/php/remote-specs-validation/composer.json">
{
	"name": "woocommerce/remote-specs-validation",
	"version": "1.0.2",
	"description": "Remote specs testing suite",
	"type": "library",
	"license": "GPL-2.0-or-later",
	"autoload": {
		"psr-4": {
			"Automattic\\WooCommerce\\RemoteSpecsValidation\\": "src/"
		}
	},
	"autoload-dev": {
		"psr-4": {
			"Automattic\\WooCommerce\\RemoteSpecsValidation\\Tests\\": "tests/"
		}
	},
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0",
		"phpunit/phpunit": "^9"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"formatter": {
				"filename": "../../../tools/changelogger/class-legacy-core-formatter.php"
			},
... (17 lines truncated)
</file>

<file path="packages/php/remote-specs-validation/package.json">
{
	"name": "@woocommerce/remote-specs-validation",
	"description": "Remote specs testing suite",
	"main": "index.js",
	"scripts": {
		"changelog": "XDEBUG_MODE=off composer install --quiet && composer exec -- changelogger"
	},
	"license": "GPL-2.0-or-later",
	"dependencies": {
		"js-yaml": "^4.3.1",
		"json-refs": "^3.0.15",
		"commander": "^5.1.0"
	}
}
</file>

<file path="packages/php/remote-specs-validation/phpunit.xml">
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false" backupStaticAttributes="false" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
  <coverage>
    <include>
      <directory suffix=".php">src/</directory>
    </include>
  </coverage>
  <testsuites>
    <testsuite name="Project Test Suite">
      <directory>tests</directory>
    </testsuite>
  </testsuites>
  <php>
    <env name="APP_ENV" value="testing"/>
  </php>
</phpunit>
</file>

<file path="packages/php/remote-specs-validation/README.md">
# Remote Specification Validation

## Installation

```php
composer require woocommerce/remote-specs-validation
```

## Available Schemas

| Filename                          | Endpoint                                                                                               | Bundle                       |
| --------------------------------- | ------------------------------------------------------------------------------------------------------ | ---------------------------- |
| remote-inbox-notification.json    | <https://woocommerce.com/wp-json/wccom/inbox-notifications/2.0/notifications.json>                     | remote-inbox-notification    |
| payment-gateway-suggestions.json  | <https://woocommerce.com/wp-json/wccom/payment-gateway-suggestions/2.0/suggestions.json>               | payment-gateway-suggestions  |
| obw-free-extensions.json          | <https://woocommerce.com/wp-json/wccom/obw-free-extensions/4.0/extensions.json>                        | obw-free-extensions          |
| wc-pay-promotions.json            | <https://woocommerce.com/wp-json/wccom/payment-gateway-suggestions/2.0/payment-method/promotions.json> | wc-pay-promotions            |
| shipping-partner-suggestions.json | <https://woocommerce.com/wp-json/wccom/shipping-partner-suggestions/2.0/suggestions.json>              | shipping-partner-suggestions |

## Working with Schema

If it's your first time working with JSON Schema, we highly recommend reading <https://json-schema.org/learn/getting-started-step-by-step> first.

1. Open a schema file from `schemas` directory.
2. Make changes.
3. Run `./bin/build schemas/:name-of-schema-file`
4. Bundled schema file will be saved in `bundles` directory.

## Validation Examples

```php
... (14 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/changelog/.gitkeep">

</file>

<file path="packages/php/woocommerce-analytics/changelog/fix-dotcom-18362-search-event-name">
Significance: patch
Type: fixed

Rename the store search event so Tracks ingest stops rejecting it.
</file>

<file path="packages/php/woocommerce-analytics/changelog/wooa7s-1803-tracking-proxy-hardening">
Significance: minor
Type: security

Stop the tracking proxy endpoint from accepting client-supplied values for server-derived event properties, and register it only on sites with proxy tracking enabled. Adds `WC_Analytics_Tracking::record_client_event()` and a third `$is_client_supplied` argument to the `jetpack_woocommerce_analytics_event_props` filter.
</file>

<file path="packages/php/woocommerce-analytics/changelog/wooa7s-2042-config-global-hardening">
Significance: patch
Type: security

Always initialize the front-end `window.wcAnalytics` object from scratch and only accept a string as the webpack public path.
</file>

<file path="packages/php/woocommerce-analytics/changelog/wooa7s-client-input-bounds">
Significance: minor
Type: security

Bound what the unauthenticated tracking proxy endpoint accepts: events per request, properties per event, array members, value and name lengths, an encoded payload budget per event, and a ceiling on the pixel URL that is fired.
</file>

<file path="packages/php/woocommerce-analytics/changelog/wooa7s-proxy-route-lifecycle">
Significance: minor
Type: security

Keep the tracking proxy route registered once a site has used proxy tracking and answer 403 while the feature is off, so events from pages still held in a cache fail visibly instead of disappearing into a 404. Mirrors the speed module's authorization into an option it can read before plugins load, and has an unauthorized module fall through to the REST route rather than refuse on its own.
</file>

<file path="packages/php/woocommerce-analytics/src/API/class-wc-analytics-tracking-proxy.php">
namespace Automattic\Woocommerce_Analytics;
⋮----
class WC_Analytics_Tracking_Proxy extends \WC_REST_Controller {
⋮----
protected $namespace = 'woocommerce-analytics/v1';
⋮----
protected $rest_base = 'track';
⋮----
public function register_routes() {
⋮----
public function track_events( $request ) {
⋮----
if ( ! Features::is_proxy_tracking_enabled() ) {
return new \WP_Error(
⋮----
if ( ! Consent_Manager::has_analytics_consent() ) {
return new \WP_REST_Response(
⋮----
$events = $request->get_json_params();
⋮----
$result = WC_Analytics_Tracking::record_client_event( $event_name, $properties );
⋮----
'error'   => $result->get_error_message(),
⋮----
return new \WP_REST_Response( $response_data, $has_errors ? 207 : 200 );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="packages/php/woocommerce-analytics/src/client/listeners/account.ts">
import type { RecordEventFunction } from '../types/shared';
⋮----
export function initListeners( recordEvent: RecordEventFunction ): void
</file>

<file path="packages/php/woocommerce-analytics/src/client/types/global.d.ts">
interface Window {
		wcAnalytics?: {
			trackEndpoint: string;
			eventQueue: Array< { eventName: string; props?: Record< string, unknown > } >;
			commonProps: Record< string, unknown >;
			features: Record< string, boolean >;
			pages: Record< string, boolean >;
			breadcrumbs?: string[];
			assets_url: string;
		};
		_wca?: {
			push: ( props: Record< string, unknown > ) => void;
		};
		wp_has_consent?: ( type: string ) => boolean;
	}
</file>

<file path="packages/php/woocommerce-analytics/src/client/types/shared.ts">
export interface SessionCookieData {
	session_id: string;
	landing_page: string;
	expires: string;
	is_engaged?: boolean;
}
⋮----
export interface AnalyticsConfig {
	eventQueue: Array< { eventName: string; props?: Record< string, unknown > } >;
	commonProps: Record< string, unknown >;
	features: Record< string, boolean >;
	pages: Record< string, boolean >;
}
⋮----
export type RecordEventFunction = ( event: string, properties?: Record< string, unknown > ) => void;
⋮----
export interface QueuedEvent {
	eventName: string;
	props?: Record< string, unknown >;
}
⋮----
export interface ApiEvent {
	event_name: string;
	properties: Record< string, unknown >;
}
⋮----
export interface ApiFetchResponse {
	success: boolean;
	results: Array< { success: boolean; error?: string } >;
}
... (1 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/src/client/analytics.ts">
import debugFactory from 'debug';
⋮----
import { ApiClient } from './api-client';
import { consentManager } from './consent';
import { EVENT_NAME_REGEX, EVENT_PREFIX } from './constants';
import SessionManager from './session-manager';
import { getCookie, generateRandomToken } from './utils';
import type { AnalyticsConfig } from './types/shared';
⋮----
export class Analytics
⋮----
constructor(
		sessionManager: SessionManager,
		{ eventQueue = [], commonProps = {}, features = {}, pages = {} }: AnalyticsConfig
)
⋮----
private maybeSetAnonId()
</file>

<file path="packages/php/woocommerce-analytics/src/client/api-client.ts">
import debugFactory from 'debug';
⋮----
import { BATCH_SIZE, DEBOUNCE_DELAY } from './constants';
import type { ApiEvent, ApiFetchResponse } from './types/shared';
⋮----
export class ApiClient
</file>

<file path="packages/php/woocommerce-analytics/src/client/consent.ts">
import debugFactory from 'debug';
⋮----
export class ConsentManager
⋮----
isWpConsentApiAvailable(): boolean
⋮----
hasAnalyticsConsent(): boolean
⋮----
addConsentChangeListener( callback: ( hasConsent: boolean ) => void ): void
⋮----
private initializeConsentListener(): void
⋮----
private notifyListeners( hasConsent: boolean ): void
</file>

<file path="packages/php/woocommerce-analytics/src/client/constants.ts">

</file>

<file path="packages/php/woocommerce-analytics/src/client/index.ts">
import { consentManager } from './consent';
</file>

<file path="packages/php/woocommerce-analytics/src/client/init.ts">
import { Analytics } from './analytics';
import SessionManager from './session-manager';
⋮----
function initAnalytics()
</file>

<file path="packages/php/woocommerce-analytics/src/client/public-path.ts">

</file>

<file path="packages/php/woocommerce-analytics/src/client/session-manager.ts">
import { COOKIE_NAME } from './constants';
import { getCookie } from './utils';
import type { SessionCookieData } from './types/shared';
⋮----
export default class SessionManager
⋮----
loadOrCreateSession()
⋮----
createNewSession()
⋮----
getSessionCookie(): SessionCookieData | null
⋮----
setSessionCookie( sessionData: SessionCookieData ): boolean
⋮----
getSessionExpirationTime(): string
⋮----
generateRandomUuid(): string
⋮----
// Fallback for older browsers (Math.random - less secure)
⋮----
setEngaged()
⋮----
clearSession()
</file>

<file path="packages/php/woocommerce-analytics/src/client/utils.ts">
export function getCookie( name: string ): string | null
⋮----
export function generateRandomToken( randomBytesLength: number ): string
</file>

<file path="packages/php/woocommerce-analytics/src/mu-plugin/woocommerce-analytics-proxy-speed-module-template.php">
class WooCommerceAnalyticsProxySpeed {
⋮----
public function init() {
⋮----
if ( ! $this->is_proxy_request() ) {
⋮----
if ( ! $this->load_autoloader() ) {
⋮----
if ( ! $this->is_authorized() ) {
⋮----
$this->handle_proxy_request();
⋮----
private function is_proxy_request() {
if ( 'POST' !== $this->get_request_method() ) {
⋮----
$path = $this->get_request_path();
⋮----
/**
	 * Load the autoloader.
	 *
	 * At MU-plugin stage, plugins haven't loaded yet, so we bootstrap
	 * the autoloader directly using the path injected during installation.
	 *
	 * @return bool True if autoloader loaded and classes are available.
	 */
private function load_autoloader() {
⋮----
error_log( 'WooCommerce Analytics Proxy Speed Module: Failed to load autoloader: ' . $e->getMessage() );
⋮----
private function is_authorized() {
... (34 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/src/class-consent-manager.php">
namespace Automattic\Woocommerce_Analytics;
⋮----
class Consent_Manager {
⋮----
public static function has_analytics_consent() {
⋮----
return \wp_has_consent( self::WP_CONSENT_API_STATISTICS_TYPE );
</file>

<file path="packages/php/woocommerce-analytics/src/class-features.php">
namespace Automattic\Woocommerce_Analytics;
⋮----
class Features {
⋮----
public static function is_proxy_tracking_enabled() {
⋮----
public static function is_clickhouse_enabled() {
⋮----
public static function is_proxy_speed_module_enabled() {
</file>

<file path="packages/php/woocommerce-analytics/src/class-my-account.php">
namespace Automattic\Woocommerce_Analytics;
⋮----
class My_Account {
⋮----
public function init_hooks() {
⋮----
public function track_tabs() {
⋮----
$core_endpoints = WC()->query->get_query_vars();
⋮----
$this->enqueue_event( 'my_account_order_number_click' );
⋮----
$this->enqueue_event( 'my_account_order_action_click', array( 'action' => 'view' ) );
⋮----
$this->enqueue_event( 'my_account_address_click', array( 'address' => $value ) );
⋮----
$this->enqueue_event( 'my_account_payment_add' );
⋮----
$this->enqueue_event( 'my_account_page_view', array( 'tab' => $key ) );
⋮----
public function track_save_address( $customer_id, $load_address ) {
WC_Analytics_Tracking::record_event( 'my_account_address_save', array( 'address' => $load_address ) );
⋮----
public function track_add_payment_method() {
⋮----
$nonce_value = wc_get_var( $_REQUEST['woocommerce-add-payment-method-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash
⋮----
WC_Analytics_Tracking::record_event( 'my_account_payment_save' );
⋮----
public function track_delete_payment_method() {
... (20 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/src/class-pixel-builder.php">
namespace Automattic\Woocommerce_Analytics;
⋮----
use WP_Error;
⋮----
class Pixel_Builder {
⋮----
public static function build_timestamp() {
⋮----
/**
	 * Add request timestamp and nocache parameter to pixel URL.
	 * Should be called just before the HTTP request.
	 *
	 * @param string $pixel Pixel URL.
	 * @return string Pixel URL with request timestamp and URL terminator.
	 */
public static function add_request_timestamp_and_nocache( $pixel ) {
return $pixel . '&_rt=' . self::build_timestamp() . '&_=_';
⋮----
public static function build_tracks_url( $properties ) {
$validated = self::validate_and_sanitize( $properties );
⋮----
public static function build_ch_url( $properties ) {
⋮----
public static function validate_and_sanitize( $properties ) {
⋮----
if ( ! self::event_name_is_valid( $properties['_en'] ) ) {
⋮----
$properties['_ts'] = self::build_timestamp();
⋮----
if ( ! self::prop_name_is_valid( $key ) ) {
... (54 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/src/class-universal.php">
namespace Automattic\Woocommerce_Analytics;
⋮----
use Automattic\Jetpack\Constants;
use WC_Order;
use WC_Product;
⋮----
class Universal {
⋮----
public function init_hooks() {
$this->find_cart_checkout_content_sources();
$this->additional_blocks_on_cart_page     = $this->get_additional_blocks_on_page( 'cart' );
$this->additional_blocks_on_checkout_page = $this->get_additional_blocks_on_page( 'checkout' );
⋮----
public function inject_analytics_data() {
$is_clickhouse_enabled     = Features::is_clickhouse_enabled();
$is_proxy_tracking_enabled = Features::is_proxy_tracking_enabled();
⋮----
$common_properties = $is_proxy_tracking_enabled ? array() : $this->get_page_common_properties();
⋮----
wcAnalytics.eventQueue = <?php echo wp_json_encode( WC_Analytics_Tracking::get_event_queue(), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>;
⋮----
wcAnalytics.breadcrumbs = <?php echo wp_json_encode( $this->get_breadcrumb_titles(), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>;
⋮----
public function capture_remove_from_cart( $cart_item_key, $cart ) {
⋮----
WC_Analytics_Tracking::record_event(
⋮----
$this->get_cart_checkout_event_properties(
⋮----
public function capture_cart_quantity_update( $cart_item_key, $quantity, $old_quantity, $cart ) {
... (129 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/src/class-wc-analytics-tracking.php">
namespace Automattic\Woocommerce_Analytics;
⋮----
use Automattic\Jetpack\Device_Detection;
use Automattic\Jetpack\Device_Detection\User_Agent_Info;
use WP_Error;
⋮----
class WC_Analytics_Tracking {
⋮----
protected static $event_queue = array();
⋮----
private static $pixel_batch_queue = array();
⋮----
private static $shutdown_hook_registered = false;
⋮----
private static $cached_ip = null;
⋮----
private static $cached_visitor_id = null;
⋮----
private static $reserved_property_names = null;
⋮----
public static function record_event( $event_name, $event_properties = array(), $is_client_supplied = false ) {
⋮----
if ( ! Consent_Manager::has_analytics_consent() ) {
⋮----
if ( User_Agent_Info::is_bot() ) {
⋮----
if ( empty( self::get_visitor_id() ) ) {
⋮----
if ( ! self::is_valid_client_name( $event_name ) ) {
⋮----
... (267 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/src/class-woo-analytics-trait.php">
namespace Automattic\Woocommerce_Analytics;
⋮----
use Automattic\Block_Scanner;
use Automattic\Jetpack\Connection\Manager as Jetpack_Connection;
use WC_Order_Item;
use WC_Order_Item_Product;
use WC_Payment_Gateway;
use WC_Product;
⋮----
trait Woo_Analytics_Trait {
⋮----
protected $cart_checkout_templates_in_use;
⋮----
protected $cart_content_source = '';
⋮----
/**
	 * The content of the checkout page or where the cart page is ultimately derived from if using a template.
	 *
	 * @var string
	 */
protected $checkout_content_source = '';
⋮----
/**
	 * Tracks any additional blocks loaded on the Cart page.
	 *
	 * @var array
	 */
protected $additional_blocks_on_cart_page;
⋮----
/**
... (161 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/src/class-woocommerce-analytics.php">
namespace Automattic;
⋮----
use Automattic\Jetpack\Assets;
use Automattic\Jetpack\Connection\Manager as Jetpack_Connection;
use Automattic\Woocommerce_Analytics\My_Account;
use Automattic\Woocommerce_Analytics\Universal;
use Automattic\Woocommerce_Analytics\WC_Analytics_Tracking_Proxy;
use Composer\InstalledVersions;
⋮----
class Woocommerce_Analytics {
⋮----
public static function init() {
if ( ! self::should_track_store() || did_action( 'woocommerce_analytics_init' ) ) {
⋮----
public static function should_track_store() {
⋮----
if ( ! ( new Jetpack_Connection() )->is_connected() ) {
⋮----
public static function wp_head_top() {
⋮----
public static function enqueue_tracking_script() {
⋮----
public static function enqueue_client_script() {
Assets::register_script(
⋮----
public static function register_rest_routes() {
⋮----
$controller->register_routes();
⋮----
public static function sync_proxy_tracking_state() {
... (64 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/tasks/mirror-github/workflows/autotagger.yml">
name: Auto-tagger
on:
    push:
        branches:
            - trunk
            - prerelease
            - '*/branch-*'
    workflow_dispatch:
permissions: {}
jobs:
    tag:
        name: Tag
        runs-on: ubuntu-latest
        steps:
            - name: Check that the secret is set
              env:
                  TOKEN: ${{ secrets.API_TOKEN_GITHUB }}
              run: |
                  if [[ -z "$TOKEN" ]]; then
                    echo '::error::The secret API_TOKEN_GITHUB must be set.'
                    exit 1
                  fi
            - uses: actions/checkout@v6
              with:
                  token: ${{ secrets.API_TOKEN_GITHUB }}
            - name: Check branch
              id: check-branch
              run: |
                  PREFIXES=
                  if [[ -e composer.json ]]; then
... (72 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/tasks/mirror-github/workflows/readonly.yml">
name: Enforce read-only repo status
on:
    issues:
        types: opened
    pull_request_target:
        types: opened
permissions:
    issues: write
    pull-requests: write
jobs:
    lockdown:
        runs-on: ubuntu-latest
        steps:
            - uses: dessant/repo-lockdown@17c2cc64a91eff426f242b05dd523c6f098889b6
              with:
                  github-token: ${{ github.token }}
                  issue-comment: |
                      Thank you for your interest!
                      Issues should be filed at https://github.com/woocommerce/woocommerce/issues. Be sure to mention the `woocommerce-analytics` package.
                  skip-closed-issue-comment: true
                  pr-comment: |
                      Thank you for your interest!
                      Pull requests should be made against the monorepo at https://github.com/woocommerce/woocommerce.
                  skip-closed-pr-comment: true
</file>

<file path="packages/php/woocommerce-analytics/tasks/build-package.sh">
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PACKAGE_DIR="$(dirname "$SCRIPT_DIR")"
BUILD_DIR="$PACKAGE_DIR/build"
DIST_DIR="$BUILD_DIR/Automattic/woocommerce-analytics"
echo "Preparing woocommerce-analytics package for Packagist.org publishing..."
if [ -d "$BUILD_DIR" ]; then
    echo "Cleaning up existing build directory..."
    rm -rf "$BUILD_DIR"
fi
echo "Installing JS dependencies..."
pnpm install --filter "@automattic/woocommerce-analytics" --frozen-lockfile
echo "Building JS assets..."
pnpm run build-production
echo "Creating build directory structure..."
mkdir -p "$DIST_DIR"
echo "Creating mirrors.txt file..."
echo "Automattic/woocommerce-analytics" > "$BUILD_DIR/mirrors.txt"
echo "Copying PHP source files..."
rsync -avhW --quiet \
    "$PACKAGE_DIR/src/" \
    "$DIST_DIR/src/" \
    --exclude="client/"
echo "Copying built JS assets..."
mkdir -p "$DIST_DIR/build"
rsync -avhW --quiet \
    --include="*.js" \
    --include="*.asset.php" \
    --exclude="*" \
    "$PACKAGE_DIR/build/" \
... (14 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/.gitattributes">
# Files not needed to be distributed in the package.
.gitattributes    export-ignore
.github/          export-ignore
</file>

<file path="packages/php/woocommerce-analytics/CHANGELOG.md">
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 0.17.0 - 2026-08-24
### Security
- Update wp-coding-standards/wpcs to 3.4.1 (security release). [#67036]

### Changed
- Update PHP development dependencies to versions that resolve reported security advisories. [#67595]
- Use the tooling catalog for shared Babel, PostCSS, and webpack versions. [#67842]

### Removed
- Minimum supported PHP version is now 7.4. [#67983]

## 0.16.7 - 2026-07-27
### Security
- Stop emitting request-derived properties into cacheable front-end page HTML. [#67003]

### Changed
- Update package dependencies. [#65999]

### Fixed
- Recognize active WooCommerce installations in custom plugin directories. [#66665]

## 0.16.6 - 2026-06-17
### Fixed
... (377 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/composer.json">
{
	"name": "automattic/woocommerce-analytics",
	"description": "Enhanced analytics for WooCommerce users.",
	"type": "jetpack-library",
	"license": "GPL-2.0-or-later",
	"version": "0.17.0",
	"require": {
		"php": ">=7.4",
		"automattic/jetpack-assets": "^4.3 || ^5.0",
		"automattic/jetpack-connection": "^8.1 || ^9.0",
		"automattic/jetpack-constants": "^3.0 || ^4.0",
		"automattic/jetpack-device-detection": "^3.4 || ^4.0",
		"automattic/block-delimiter": "^0.3 || ^0.4"
	},
	"require-dev": {
		"yoast/phpunit-polyfills": "^4.0.0",
		"automattic/wordbless": "^0.5",
		"woocommerce/woocommerce-sniffs": "1.0.0",
		"automattic/jetpack-changelogger": "^6.0 || ^7.0"
	},
	"autoload": {
		"classmap": [
			"src/"
		]
	},
	"scripts": {
		"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
		"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy",
		"phpunit": [
			"phpunit --colors=always"
... (41 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/LICENSE.txt">
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, see <https://www.gnu.org/licenses/>.


===================================


                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
 <https://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
... (326 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/package.json">
{
	"name": "@automattic/woocommerce-analytics",
	"description": "WooCommerce Analytics package to track frontend events",
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/php/woocommerce-analytics",
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git",
		"directory": "packages/php/woocommerce-analytics"
	},
	"license": "GPL-2.0-or-later",
	"author": "Automattic",
	"scripts": {
		"build": "pnpm run clean && webpack",
		"build:composer-package": "bash tasks/build-package.sh",
		"changelog": "XDEBUG_MODE=off composer install --quiet && composer exec -- changelogger",
		"build-production": "NODE_ENV=production BABEL_ENV=production pnpm run build",
		"clean": "rm -rf build/",
		"test": "jest --passWithNoTests",
		"test-coverage": "pnpm run test --coverage",
		"test:php": "composer test-php",
		"test:php:ci": "pnpm test:php",
		"build:ci": "pnpm run typecheck && pnpm run build-production",
		"typecheck": "tsc --noEmit",
		"postinstall": "XDEBUG_MODE=off composer install --quiet",
		"watch": "pnpm build --watch"
	},
	"dependencies": {
... (53 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/phpcs.xml">
<?xml version="1.0"?>
<ruleset name="WooCommerce Analytics Coding Standards">
	<rule ref="WordPress">
		<exclude name="WordPress.PHP.YodaConditions"/>
		<exclude name="Squiz.Commenting.InlineComment.InvalidEndChar"/>
	</rule>
	<file>src</file>
	<exclude-pattern>src/client/*</exclude-pattern>
	<rule ref="WordPress.WP.I18n">
		<properties>
			<property name="text_domain" type="array">
				<element value="woocommerce-analytics" />
			</property>
		</properties>
	</rule>
	<rule ref="WordPress.Utils.I18nTextDomainFixer">
		<properties>
			<property name="old_text_domain" type="array" />
			<property name="new_text_domain" value="woocommerce-analytics" />
		</properties>
	</rule>
	<exclude-pattern>vendor/*</exclude-pattern>
	<exclude-pattern>node_modules/*</exclude-pattern>
	<exclude-pattern>build/*</exclude-pattern>
	<exclude-pattern>tests/*</exclude-pattern>
</ruleset>
</file>

<file path="packages/php/woocommerce-analytics/README.md">
# WooCommerce Analytics

## Overview

Enhanced analytics package for WooCommerce stores with comprehensive frontend tracking for Automattic based projects.

### Key Features

-   **Comprehensive Event Tracking**: 25+ predefined events covering e-commerce, navigation, and user interactions
-   **Session Management**: Intelligent session tracking and user engagement metrics
-   **Proxy Tracking**: Optional proxy-based tracking for enhanced privacy and performance

## Installation & Setup

### WordPress Plugin Integration

```php
// Add to your plugin
use Automattic\Woocommerce_Analytics;

add_action(
 'after_setup_theme',
 function() {
  Woocommerce_Analytics::init();
 }
);

```

#### Initialization
... (284 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/SECURITY.md">
# Security Policy

Full details of the Automattic Security Policy can be found on [automattic.com/security](https://automattic.com/security/).

## Supported Versions

Generally, *only the latest version of WooCommerce has continued support*. If a critical vulnerability is found in the current version of WooCommerce, we may opt to backport any patches to previous versions. 

## Reporting a Vulnerability

[WooCommerce](https://wordpress.org/plugins/woocommerce) is an open-source plugin for WordPress. Our HackerOne program covers the plugin software, as well as a variety of related projects and infrastructure.

**For responsible disclosure of security issues and to be eligible for our bug bounty program, please submit your report based on instructions found on [automattic.com/security](https://automattic.com/security).**

Our most critical targets are:

* WooCommerce core (this repository)
* WooCommerce [Blocks](https://wordpress.org/plugins/woo-gutenberg-products-block/) and [Admin](https://wordpress.org/plugins/woocommerce-admin/) packages and plugins
* WooCommerce.com -- the primary marketplace and marketing site, and all of it subdomains, e.g. [developer.woocommerce.com](https://developer.woocommerce.com/)
* WordPress.com -- hosted WooCommerce for Business and eCommerce offering on WordPress.com.

For more targets, see the `In Scope` section on [HackerOne](https://hackerone.com/automattic).

Please note that the **WordPress software is a separate entity** from Automattic. Please report vulnerabilities for WordPress through [the WordPress Foundation's HackerOne page](https://hackerone.com/wordpress).

## Guidelines

We're committed to working with security researchers to resolve the vulnerabilities they discover. You can help us by following these guidelines:

*   Follow [HackerOne's disclosure guidelines](https://www.hackerone.com/disclosure-guidelines).
... (9 lines truncated)
</file>

<file path="packages/php/woocommerce-analytics/tsconfig.json">
{
	"include": [ "./src/client" ],
	"compilerOptions": {
		"target": "ES2020",
		"module": "ESNext",
		"moduleResolution": "node",
		"lib": [ "ES2020", "DOM", "DOM.Iterable" ],
		"jsx": "react-jsx",
		"strict": false,
		"esModuleInterop": true,
		"allowSyntheticDefaultImports": true,
		"typeRoots": [ "./node_modules/@types/", "./src/client/types" ],
		"sourceMap": true,
		"forceConsistentCasingInFileNames": true,
		"skipLibCheck": true
	}
}
</file>

<file path="packages/php/woocommerce-analytics/webpack.config.js">
requestToExternal( request )
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/.gitkeep">

</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/66097-bump-wp-env-and-playwright">
Significance: patch
Type: dev
Comment: Bump @wordpress/env to 11.9.0 and @playwright/test to 1.61.1 (dev dependencies; no merchant-facing change).
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-admin-list-queries">
Significance: minor
Type: add

Add status filtering, sorting, search, per-status counts, and a batched line-item count to the subscriptions list query, exposed on the Subscriptions facade.
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-basic-ci-config-for-woocommerce-subscriptions-engine">
Significance: minor
Type: dev

Add basic CI configuration
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-bogo-pricing-policy-type">
Significance: minor
Type: add

Add a value-less bogo pricing-policy type that grants a free unit of the same line item on in-scope cycles, materialized on renewal orders.
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-phpcs-sniff-to-require-const-visibility">
Significance: patch
Type: dev

Require explicit visibility for class constants
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-phpstan-validation-for-woocommerce-subscriptions-engine">
Significance: patch
Type: dev

Add PHPStan configuration and CI
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-rest-api-for-subscriptions-engine-plans">
Significance: minor
Type: add

Implement Plans REST API
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-selling-plans-catalog-read-facade">
Significance: minor
Type: add

Add the Api\SellingPlans catalog read facade (list_plans, get_plans) and an ids filter to PlanRepository::query().
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-subscriptions-engine-boundary-guards">
Significance: patch
Type: dev

Harden engine boundaries: reject negative cycle_count on Contract hydration, require a persisted order in ContractFactory, and guard ContractRepository::update() against a stale id / concurrent delete.
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-subscriptions-engine-customer-portal">
Significance: minor
Type: add

Add the customer-portal engine surface: extend the Api\Subscriptions facade with customer-scoped reads (list_for_customer, get_for_customer), hold/reactivate/cancel-at-period-end verbs, and get_related_orders(); add focused per-operation contract services (Hold, Reactivation, and a period-end mode on Cancellation); add authenticated wc/v3 lifecycle-action endpoints (hold, reactivate, cancel) under Api\Rest responding with a domain summary; and hydrate the contract's frozen plan snapshot on the facade reads (PlanSnapshot::get_billing_policy()).
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-subscriptions-engine-cycle-chain-schema">
Significance: patch
Type: dev

Add the cycle-chain data model: a live contract as the source of truth holding its latest snapshot references, immutable per-billing cycles on a chain as (contract_id, kind), and per-contract snapshots with copy-forward reuse, persisted through a contract repository with targeted cycle access.
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-subscriptions-engine-psr4-conversion">
Significance: patch
Type: dev

Convert the subscriptions-engine package source to PSR-4 PascalCase (behavior-preserving rename).
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-subscriptions-engine-renewal-advancement">
Significance: minor
Type: add

Add subscriptions engine renewal advancement money-path and Api\Subscriptions facade.
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-subscriptions-engine-renewal-dispatch">
Significance: minor
Type: add

Add subscriptions engine batch renewal dispatcher with cycle-aware selection, order-driven completion, admin-triggered renew and retry, and the processing gate.
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-subscriptions-engine-renewal-money-path">
Significance: patch
Type: dev

Add the renewal money-path: order-to-contract factory, the renewal engine (schedule, advance, charge, cancel) with its Action Scheduler bridge, the pure Core renewal calculator, and ContractRepository::update().
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/add-subscriptions-engine-status-machine-capabilities">
Significance: patch
Type: dev

Add the contract status-transition machine and the gateway capability registry.
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/dev-refactor-subscriptions-engine-support-helpers">
Significance: patch
Type: dev

Convert internal scalar and money support helpers from traits to static classes
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/fix-billing-policy-core-zone-purity">
Significance: patch
Type: dev

Keep the WordPress-free Core zone pure: use gettype() instead of wp_json_encode() in the BillingPolicy trial_duration validation message, and cover the previously-untested error branch with a unit test.
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/fix-double-escaping-in-plan-repository">
Significance: patch
Type: fix

Prevent double-escaping for incoming queries
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/fix-linting-issues-in-core-entities">
Significance: patch
Type: dev

Fix PHPDoc formatting issues that were flagged as linting problems
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/fix-subscriptions-engine-phpstan-findings">
Significance: patch
Type: dev

Resolve all PHPStan level 9 findings across the engine source and tests by adding type-safe hydration coercion at the entity, value object and repository boundaries (behavior-preserving for valid data).
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/flatten-selling-plans-catalog">
Significance: minor
Type: update

Flatten the selling-plans catalog: remove plan groups; plans carry merchant_code directly.
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/resync-composer-locks">
Significance: patch
Type: dev

Resync composer.lock.
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/update-php-dev-dependency-security-patches">
Significance: patch
Type: dev

Update PHP development dependencies to versions that resolve reported security advisories.
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/update-woosubs-engine-make-phpstan-ci-required">
Significance: patch
Type: dev

Mark PHPStan workflows as required for CI
</file>

<file path="packages/php/woocommerce-subscriptions-engine/changelog/update-wpcs-3-4-1">
Significance: patch
Type: dev

Update wp-coding-standards/wpcs to 3.4.1 (security release).
</file>

<file path="packages/php/woocommerce-subscriptions-engine/phpstan-stubs/stubs.php">
class PHPUnit_Framework_Exception {}
⋮----
namespace WordPress\AiClient\Providers {
⋮----
abstract class AbstractProvider {
⋮----
namespace WordPress\AiClient\Providers\DTO {
⋮----
class ProviderMetadata {
⋮----
namespace WordPress\AiClient\Providers\Models\DTO {
⋮----
class ModelMetadata {
⋮----
namespace WordPress\AiClient\Providers\Contracts {
⋮----
interface ProviderAvailabilityInterface {
public function isConfigured(): bool;
⋮----
interface ModelMetadataDirectoryInterface {
public function listModelMetadata(): array;
public function hasModelMetadata( string $modelId ): bool;
public function getModelMetadata( string $modelId ): \WordPress\AiClient\Providers\Models\DTO\ModelMetadata;
⋮----
interface ModelInterface {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Api/Rest/ContractsController.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Api\Rest;
⋮----
use DomainException;
use Throwable;
use WP_Error;
use WP_REST_Controller;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
use Automattic\WooCommerce\SubscriptionsEngine\Api\Subscriptions;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Contract;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Support\ScalarCoercion;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Support\RESTPermissions;
⋮----
final class ContractsController extends WP_REST_Controller {
⋮----
private $rest_permissions;
⋮----
public function __construct( ?RESTPermissions $rest_permissions = null ) {
⋮----
public static function register_hooks(): void {
⋮----
( new self() )->register_routes();
⋮----
public function register_routes(): void {
⋮----
'args'   => $this->id_arg(),
⋮----
public function permissions_check( $request ) {
return $this->rest_permissions->require_logged_in_permission();
... (46 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Api/Rest/PlansController.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Api\Rest;
⋮----
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Plan;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Support\ScalarCoercion;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\BillingPolicy;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\PricingPolicy;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\PlanRepository;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Support\RESTPermissions;
use InvalidArgumentException;
use Throwable;
use WP_Error;
use WP_REST_Controller;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
⋮----
final class PlansController extends WP_REST_Controller {
⋮----
private $plan_repository;
⋮----
private $rest_permissions;
⋮----
public function __construct( ?PlanRepository $plan_repository = null, ?RESTPermissions $rest_permissions = null ) {
⋮----
public static function register_hooks(): void {
⋮----
( new self() )->register_routes();
⋮----
public function register_routes(): void {
⋮----
... (191 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Api/SellingPlans.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Api;
⋮----
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Plan;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\PlanRepository;
⋮----
final class SellingPlans {
⋮----
private $extension_slugs;
⋮----
public function __construct( array $extension_slugs ) {
⋮----
public function list_plans(): array {
return ( new PlanRepository() )->query(
⋮----
public function get_plans( array $plan_ids ): array {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Api/Subscriptions.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Api;
⋮----
use WC_Order;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Contract;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Cycle;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Checkout\RelatedOrders;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Contracts\Cancellation;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Contracts\Hold;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Contracts\Reactivation;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Renewal\RenewalEngine;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\ContractRepository;
⋮----
final class Subscriptions {
⋮----
public static function get( int $contract_id ): ?Contract {
return ( new ContractRepository() )->find( $contract_id );
⋮----
public static function list( array $args = array() ): array {
return ( new ContractRepository() )->query( $args );
⋮----
public static function count_by_status(): array {
return ( new ContractRepository() )->count_by_status();
⋮----
public static function count( array $args = array() ): int {
return ( new ContractRepository() )->count( $args );
⋮----
public static function item_counts( array $contract_ids ): array {
return ( new ContractRepository() )->count_items_by_contract( $contract_ids );
⋮----
public static function list_for_customer( int $customer_id, int $limit = 20, int $offset = 0 ): array {
... (31 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/Entity/Contract.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\Entity;
⋮----
use DomainException;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Support\MoneyScale;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Support\ScalarCoercion;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\InstrumentRef;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\PlanSnapshot;
⋮----
final class Contract {
⋮----
private $id;
⋮----
private $status;
⋮----
private $customer_id;
⋮----
private $currency;
⋮----
private $selling_plan_id;
⋮----
private $origin_order_id;
⋮----
private $extension_slug;
⋮----
private $payment_method;
⋮----
private $payment_method_title;
⋮----
private $payment_token_id;
⋮----
... (175 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/Entity/ContractStatus.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\Entity;
⋮----
use DomainException;
⋮----
final class ContractStatus {
⋮----
public static function all(): array {
⋮----
public static function is_valid( string $status ): bool {
return in_array( $status, self::all(), true );
⋮----
public static function is_terminal( string $status ): bool {
return self::is_valid( $status ) && array() === self::transitions()[ $status ];
⋮----
public static function is_transition_allowed( string $from, string $to ): bool {
if ( ! self::is_valid( $from ) || ! self::is_valid( $to ) ) {
⋮----
return in_array( $to, self::transitions()[ $from ], true );
⋮----
public static function can_transition( string $from, string $to ): bool {
return self::is_transition_allowed( $from, $to );
⋮----
public static function assert_transition_allowed( string $from, string $to ): void {
if ( ! self::is_transition_allowed( $from, $to ) ) {
⋮----
private static function transitions(): array {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/Entity/Cycle.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\Entity;
⋮----
use DomainException;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Support\MoneyScale;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Support\ScalarCoercion;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\PlanSnapshot;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\ItemsSnapshot;
⋮----
final class Cycle {
⋮----
private $id;
⋮----
private $contract_id;
⋮----
private $sequence_no;
⋮----
private $count;
⋮----
private $kind;
⋮----
private $status;
⋮----
private $reason;
⋮----
private $starts_at_gmt;
⋮----
private $ends_at_gmt;
⋮----
private $expected_total;
⋮----
... (165 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/Entity/CycleStatus.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\Entity;
⋮----
use DomainException;
⋮----
final class CycleStatus {
⋮----
private $value;
⋮----
private function __construct( string $value ) {
⋮----
public static function from( string $value ): self {
if ( ! self::is_valid( $value ) ) {
⋮----
public static function pending(): self {
⋮----
public static function processing(): self {
⋮----
public static function billed(): self {
⋮----
public static function failed(): self {
⋮----
public static function cancelled(): self {
⋮----
public function get_value(): string {
⋮----
public function equals( CycleStatus $other ): bool {
⋮----
public function can_transition_to( CycleStatus $target ): bool {
return self::is_transition_allowed( $this->value, $target->value );
⋮----
... (24 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/Entity/Plan.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\Entity;
⋮----
use InvalidArgumentException;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\BillingPolicy;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\DeliveryPolicy;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\PricingPolicy;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Support\ScalarCoercion;
⋮----
final class Plan {
⋮----
private $id;
⋮----
private $name;
⋮----
private $description;
⋮----
private $billing_policy;
⋮----
private $delivery_policy;
⋮----
private $pricing_policy;
⋮----
private $category;
⋮----
private $status;
⋮----
private $sort_order;
⋮----
private $merchant_code;
⋮----
... (96 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/Gateway/GatewayCapabilities.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\Gateway;
⋮----
use InvalidArgumentException;
⋮----
final class GatewayCapabilities {
⋮----
private static $declarations = array();
⋮----
public static function known_capabilities(): array {
⋮----
public static function declare( string $gateway_id, array $capabilities ): void {
$known = self::known_capabilities();
⋮----
public static function is_declared( string $gateway_id, string $capability ): bool {
⋮----
public static function reset(): void {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/Renewal/RenewalCalculator.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\Renewal;
⋮----
use DateTimeImmutable;
use DateTimeZone;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Cycle;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\CycleStatus;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\BillingPolicy;
⋮----
final class RenewalCalculator {
⋮----
public static function has_reached_max_cycles( BillingPolicy $policy, int $cycle_count ): bool {
$max_cycles = $policy->get_max_cycles();
⋮----
public static function next_bill_date( BillingPolicy $policy, DateTimeImmutable $current_period_start ): DateTimeImmutable {
return $policy->compute_next_renewal_from( $current_period_start );
⋮----
public static function compute_next_cycle( BillingPolicy $policy, array $values ): Cycle {
⋮----
$end    = $policy->compute_next_renewal_from( $start );
⋮----
return Cycle::create(
⋮----
'status'            => CycleStatus::pending(),
'starts_at_gmt'     => $start->format( 'Y-m-d H:i:s' ),
'ends_at_gmt'       => $end->format( 'Y-m-d H:i:s' ),
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/Support/MoneyScale.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\Support;
⋮----
final class MoneyScale {
⋮----
private function __construct() {}
⋮----
public static function normalize_money( $value ): string {
return number_format( ScalarCoercion::coerce_float( $value ?? '0' ), 8, '.', '' );
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/Support/ScalarCoercion.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\Support;
⋮----
final class ScalarCoercion {
⋮----
private function __construct() {}
⋮----
public static function coerce_string( $value, string $fallback = '' ): string {
⋮----
public static function coerce_nullable_string( $value ): ?string {
⋮----
public static function coerce_int( $value, int $fallback = 0 ): int {
⋮----
public static function coerce_nullable_int( $value ): ?int {
⋮----
public static function coerce_float( $value, float $fallback = 0.0 ): float {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/BillingPolicy.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject;
⋮----
use DateTimeImmutable;
use DateTimeZone;
use DomainException;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Support\ScalarCoercion;
⋮----
final class BillingPolicy {
⋮----
private $period;
⋮----
private $interval;
⋮----
private $min_cycles;
⋮----
private $max_cycles;
⋮----
private $trial_duration;
⋮----
public function __construct( string $period, int $interval, ?int $min_cycles, ?int $max_cycles, ?array $trial_duration ) {
$this->validate_min_max_cycles( $min_cycles, $max_cycles );
⋮----
$this->trial_duration = self::normalize_trial_duration( $trial_duration );
⋮----
public static function from_array( array $data ): self {
⋮----
$trial = self::normalize_trial_duration( $trial );
⋮----
ScalarCoercion::coerce_nullable_int( $data['min_cycles'] ?? null ),
ScalarCoercion::coerce_nullable_int( $data['max_cycles'] ?? null ),
... (35 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/DeliveryPolicy.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject;
⋮----
final class DeliveryPolicy {
⋮----
private $anchors;
⋮----
private $cutoff;
⋮----
private $intent;
⋮----
public function __construct( array $anchors, $cutoff, $intent ) {
⋮----
public static function from_array( array $data ): self {
⋮----
public function get_anchors(): array {
⋮----
public function get_cutoff() {
⋮----
public function get_intent() {
⋮----
public function to_array(): array {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/InstrumentRef.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject;
⋮----
final class InstrumentRef {
⋮----
private $token_id;
⋮----
private $gateway;
⋮----
private $title;
⋮----
public function __construct( ?int $token_id, ?string $gateway = null, ?string $title = null ) {
⋮----
public function get_token_id(): ?int {
⋮----
public function get_gateway(): ?string {
⋮----
public function get_title(): ?string {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/ItemsSnapshot.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject;
⋮----
use DomainException;
⋮----
final class ItemsSnapshot {
⋮----
private $items;
⋮----
private $schema_version;
⋮----
private function __construct( array $items, int $schema_version ) {
⋮----
public static function from_items( array $items, int $schema_version = 1 ): self {
⋮----
public static function from_payload( array $payload, int $schema_version = 1 ): self {
⋮----
public function get_schema_version(): int {
⋮----
public function get_items(): array {
⋮----
public function to_payload(): array {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/OrderRef.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject;
⋮----
final class OrderRef {
⋮----
private $id;
⋮----
public function __construct( int $id ) {
⋮----
throw new \InvalidArgumentException( 'Order id must be greater than 0.' );
⋮----
public function get_id(): int {
⋮----
public function equals( OrderRef $other ): bool {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/PlanSnapshot.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject;
⋮----
use DomainException;
use InvalidArgumentException;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Support\ScalarCoercion;
⋮----
final class PlanSnapshot {
⋮----
private $data;
⋮----
private $schema_version;
⋮----
private function __construct( array $data, int $schema_version ) {
⋮----
public static function from_array( array $data, int $schema_version = 1 ): self {
⋮----
public static function from_payload( array $payload, int $schema_version = 1 ): self {
⋮----
public function get_schema_version(): int {
⋮----
public function get_selling_plan_id(): ?int {
return isset( $this->data['selling_plan_id'] ) ? ScalarCoercion::coerce_int( $this->data['selling_plan_id'] ) : null;
⋮----
public function get_billing_policy(): ?BillingPolicy {
⋮----
return BillingPolicy::from_array( self::string_keyed( $policy ) );
⋮----
public function get_pricing_policy(): ?PricingPolicy {
⋮----
return PricingPolicy::from_array( self::string_keyed( $policy ) );
... (7 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Core/ValueObject/PricingPolicy.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject;
⋮----
use InvalidArgumentException;
⋮----
final class PricingPolicy {
⋮----
private $policies;
⋮----
private $one_time_fees;
⋮----
public function __construct( array $policies, array $one_time_fees ) {
⋮----
public static function from_array( array $data ): self {
⋮----
$policy['starting_cycle'] = self::normalize_cycle( $entry['starting_cycle'], 'starting_cycle' );
⋮----
$policy['duration_cycles'] = self::normalize_cycle( $entry['duration_cycles'], 'duration_cycles' );
⋮----
public function get_policies(): array {
⋮----
public function get_one_time_fees(): array {
⋮----
public function calculate_price( float $base_price, int $cycle = 1 ): float {
⋮----
if ( ! $this->policy_applies_to_cycle( $policy, $cycle ) ) {
⋮----
public function calculate_line_total( float $unit_price, float $quantity, int $cycle = 1 ): float {
$effective_unit_price = $this->calculate_price( $unit_price, $cycle );
⋮----
public function calculate_bonus_quantity( float $paid_quantity, int $cycle = 1 ): float {
... (12 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Checkout/ContractFactory.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Checkout;
⋮----
use DateTimeImmutable;
use DateTimeZone;
use Throwable;
use WC_Order;
use WC_Order_Item_Product;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Contract;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Cycle;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\CycleStatus;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Plan;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Support\ScalarCoercion;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\ItemsSnapshot;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\PlanSnapshot;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\ContractRepository;
⋮----
final class ContractFactory {
⋮----
private $contracts;
⋮----
public function __construct( ?ContractRepository $contracts = null ) {
⋮----
public function create_from_order( WC_Order $order, Plan $plan, array $overrides = array() ): Contract {
$plan_id = $plan->get_id();
⋮----
throw new \RuntimeException( 'ContractFactory::create_from_order(): the selling plan must be persisted (have an id) before a contract can reference it.' );
⋮----
if ( ! $order->get_id() ) {
throw new \RuntimeException( 'ContractFactory::create_from_order(): the order must be persisted (have an id) before a contract can link to it.' );
⋮----
... (93 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Checkout/OrderLinkage.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Checkout;
⋮----
use InvalidArgumentException;
⋮----
final class OrderLinkage {
⋮----
public static function relation_types(): array {
⋮----
public static function assert_relation( string $relation ): void {
if ( ! in_array( $relation, self::relation_types(), true ) ) {
⋮----
esc_html( implode( ', ', self::relation_types() ) )
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Checkout/RelatedOrders.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Checkout;
⋮----
use WC_Order;
⋮----
final class RelatedOrders {
⋮----
public function for_contract( int $contract_id, int $limit = -1, int $offset = 0 ): array {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Contracts/Cancellation.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Contracts;
⋮----
use RuntimeException;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Contract;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\ContractStatus;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\CycleStatus;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\ContractRepository;
⋮----
final class Cancellation {
⋮----
private $contracts;
⋮----
public function __construct( ?ContractRepository $contracts = null ) {
⋮----
public function cancel( Contract $contract ): bool {
$id = $contract->get_id();
⋮----
$previous = $contract->get_status();
$contract->set_status( ContractStatus::CANCELLED );
⋮----
if ( ! $this->contracts->update_if_status( $contract, $previous ) ) {
throw new \DomainException( 'Cancellation::cancel(): the contract state changed concurrently; nothing was written.' );
⋮----
$current = $this->contracts->find_chain_head( $id );
if ( null !== $current && $current->get_status()->equals( CycleStatus::pending() ) ) {
$current->set_status( CycleStatus::cancelled() );
$this->contracts->update_cycle( $current );
⋮----
public function cancel_at_period_end( Contract $contract ): bool {
⋮----
... (7 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Contracts/Hold.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Contracts;
⋮----
use RuntimeException;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Contract;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\ContractStatus;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\ContractRepository;
⋮----
final class Hold {
⋮----
private $contracts;
⋮----
public function __construct( ?ContractRepository $contracts = null ) {
⋮----
public function hold( Contract $contract ): bool {
$id = $contract->get_id();
⋮----
$previous = $contract->get_status();
$contract->set_status( ContractStatus::ON_HOLD );
⋮----
if ( ! $this->contracts->update_if_status( $contract, $previous ) ) {
throw new \DomainException( 'Hold::hold(): the contract state changed concurrently; nothing was written.' );
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Contracts/Reactivation.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Contracts;
⋮----
use DateTimeImmutable;
use DateTimeZone;
use DomainException;
use RuntimeException;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Contract;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\ContractStatus;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Plan;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Renewal\RenewalCalculator;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\BillingPolicy;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\ContractRepository;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\PlanRepository;
⋮----
final class Reactivation {
⋮----
private $contracts;
⋮----
private $plans;
⋮----
public function __construct( ?ContractRepository $contracts = null, ?PlanRepository $plans = null ) {
⋮----
public function reactivate( Contract $contract, ?DateTimeImmutable $now = null ): bool {
$id = $contract->get_id();
⋮----
if ( ContractStatus::ON_HOLD !== $contract->get_status() ) {
⋮----
$now = ( $now ?? new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) ) )->setTimezone( new DateTimeZone( 'UTC' ) );
⋮----
$contract->set_status( ContractStatus::ACTIVE );
... (27 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Gateway/CapabilityRegistry.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Gateway;
⋮----
use WC_Order;
use WC_Payment_Gateway;
use WC_Payment_Gateways;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Gateway\GatewayCapabilities;
⋮----
final class CapabilityRegistry {
⋮----
private static $initialized = false;
⋮----
public static function init(): void {
⋮----
public static function declare_compatibility( string $gateway_id, array $capabilities ): void {
GatewayCapabilities::declare( $gateway_id, $capabilities );
⋮----
public static function supports( string $gateway_id, string $capability, ?WC_Order $context = null ): bool {
⋮----
$current = GatewayCapabilities::is_declared( $gateway_id, $capability );
⋮----
$current = self::gateway_instance_supports( $gateway_id, $capability );
⋮----
private static function gateway_instance_supports( string $gateway_id, string $capability ): bool {
⋮----
$registry = $wc->payment_gateways();
⋮----
$gateways = $registry->payment_gateways();
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Ownership/ConsumerRegistry.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Ownership;
⋮----
final class ConsumerRegistry {
⋮----
private static $slugs = array();
⋮----
public static function register( string $slug ): void {
⋮----
/**
	 * Remove a consumer registration. A deactivating consumer deregisters itself so the
	 * engine's gates re-evaluate while its code is still loaded - the engine only loads
	 * through its consumers, so the deactivation request is the last chance for components
	 * to clean up (e.g. the renewal dispatcher removes its recurring scan when the last
	 * consumer leaves). An unknown slug is a no-op.
	 *
	 * @param string $slug The consumer extension's registered slug.
	 */
public static function unregister( string $slug ): void {
⋮----
public static function is_empty(): bool {
⋮----
public static function all(): array {
⋮----
public static function reset(): void {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Renewal/RenewalDispatcher.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Renewal;
⋮----
use DateTimeImmutable;
use DateTimeZone;
use Throwable;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Ownership\ConsumerRegistry;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\ContractRepository;
⋮----
final class RenewalDispatcher {
⋮----
private $contracts;
⋮----
private $engine;
⋮----
private $selector;
⋮----
public function __construct( ?ContractRepository $contracts = null, ?RenewalEngine $engine = null, ?RenewalSelector $selector = null ) {
⋮----
public function register_hooks(): void {
⋮----
public static function ensure_scheduled(): void {
⋮----
if ( ConsumerRegistry::is_empty() ) {
⋮----
if ( self::is_scheduled() ) {
⋮----
private static function is_scheduled(): bool {
⋮----
public function handle_tick(): void {
$this->run_batch();
... (23 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Renewal/RenewalEngine.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Renewal;
⋮----
use DateTimeImmutable;
use DateTimeZone;
use InvalidArgumentException;
use Throwable;
use WC_Order;
use WC_Order_Item_Product;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Contract;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\ContractStatus;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Cycle;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\CycleStatus;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Plan;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Gateway\GatewayCapabilities;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Renewal\RenewalCalculator;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Support\ScalarCoercion;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\BillingPolicy;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\PlanSnapshot;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\PricingPolicy;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Checkout\OrderLinkage;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Gateway\CapabilityRegistry;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\ContractRepository;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\DuplicateCycleException;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\RenewalCandidate;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\PlanRepository;
⋮----
final class RenewalEngine {
⋮----
private $contracts;
... (318 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Renewal/RenewalIntent.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Renewal;
⋮----
final class RenewalIntent {
⋮----
private $contract_id;
⋮----
private $cycle_count;
⋮----
public function __construct( int $contract_id, int $cycle_count ) {
⋮----
public function get_contract_id(): int {
⋮----
public function get_cycle_count(): int {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Renewal/RenewalNotProcessable.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Renewal;
⋮----
use RuntimeException;
⋮----
final class RenewalNotProcessable extends RuntimeException {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Renewal/RenewalSelector.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Renewal;
⋮----
use DateTimeImmutable;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\CycleStatus;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\RenewalCandidate;
⋮----
final class RenewalSelector {
⋮----
public function select_scheduled_cycle( RenewalCandidate $candidate, DateTimeImmutable $now ): ?int {
$count = $candidate->get_head_count();
⋮----
$status = $candidate->get_head_status();
⋮----
if ( ! self::has_period_ended( $candidate->get_head_ends_at_gmt(), $now ) ) {
⋮----
public function select_manual_cycle( RenewalCandidate $candidate ): ?int {
⋮----
private static function has_period_ended( string $ends_at_gmt, DateTimeImmutable $now ): bool {
⋮----
return false !== $ends_at && $ends_at <= $now->getTimestamp();
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/ContractRepository.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage;
⋮----
use DateTimeImmutable;
use DateTimeZone;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Contract;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\ContractStatus;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Cycle;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\CycleStatus;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Support\ScalarCoercion;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\ItemsSnapshot;
use Automattic\WooCommerce\SubscriptionsEngine\Core\ValueObject\PlanSnapshot;
⋮----
final class ContractRepository {
⋮----
private $snapshots;
⋮----
public function __construct( ?SnapshotStore $snapshots = null ) {
⋮----
public function insert( Contract $contract ): int {
⋮----
$data = $contract->to_storage();
⋮----
$inserted = $wpdb->insert(
SchemaInstaller::get_table_name( SchemaInstaller::TABLE_CONTRACTS ),
⋮----
throw new \RuntimeException( 'Failed to insert contract.' );
⋮----
$contract->set_id( $id );
⋮----
$this->insert_items( $id, $contract->get_items() );
... (422 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/DuplicateCycleException.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage;
⋮----
use RuntimeException;
⋮----
final class DuplicateCycleException extends RuntimeException {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/PlanRepository.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage;
⋮----
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Plan;
use Automattic\WooCommerce\SubscriptionsEngine\Core\Support\ScalarCoercion;
⋮----
final class PlanRepository {
⋮----
public function insert( Plan $plan ): int {
⋮----
$data = $plan->to_storage();
⋮----
$inserted = $wpdb->insert(
SchemaInstaller::get_table_name( SchemaInstaller::TABLE_PLANS ),
⋮----
throw new \RuntimeException( 'Failed to insert plan.' );
⋮----
$plan->set_id( $id );
⋮----
public function find( int $id, ?string $extension_slug = null ): ?Plan {
⋮----
$table = SchemaInstaller::get_table_name( SchemaInstaller::TABLE_PLANS );
⋮----
$row = $wpdb->get_row(
⋮----
$wpdb->prepare( "SELECT * FROM {$table} WHERE id = %d {$extension_clause}", $params ),
⋮----
return $this->hydrate_row( $row );
⋮----
public function query( array $args = array() ): array {
⋮----
... (68 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/RenewalCandidate.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage;
⋮----
use Automattic\WooCommerce\SubscriptionsEngine\Core\Entity\Cycle;
⋮----
final class RenewalCandidate {
⋮----
private $contract_id;
⋮----
private $head_count;
⋮----
private $head_status;
⋮----
private $head_ends_at_gmt;
⋮----
public function __construct( int $contract_id, ?int $head_count, string $head_status, string $head_ends_at_gmt ) {
⋮----
public static function from_cycle( Cycle $cycle ): self {
⋮----
$cycle->get_contract_id(),
$cycle->get_count(),
$cycle->get_status()->get_value(),
$cycle->get_ends_at_gmt()
⋮----
public function get_contract_id(): int {
⋮----
public function get_head_count(): ?int {
⋮----
public function get_head_status(): string {
⋮----
public function get_head_ends_at_gmt(): string {
... (1 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/SchemaInstaller.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage;
⋮----
final class SchemaInstaller {
⋮----
public static function get_table_name( string $logical ): string {
⋮----
$names = self::get_table_names( $wpdb->prefix );
⋮----
throw new \InvalidArgumentException(
⋮----
public static function maybe_install(): void {
if ( self::is_current() ) {
⋮----
self::install();
⋮----
public static function install(): void {
⋮----
$collate = $wpdb->get_charset_collate();
$names   = self::get_table_names( $wpdb->prefix );
⋮----
foreach ( self::get_table_definitions( $names, $collate ) as $sql ) {
⋮----
public static function uninstall(): void {
⋮----
public static function is_current(): bool {
return self::get_version() === self::get_database_version();
⋮----
public static function get_version(): string {
⋮----
public static function get_database_version(): ?string {
... (5 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Storage/SnapshotStore.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage;
⋮----
final class SnapshotStore {
⋮----
public function insert( int $contract_id, string $snapshot_type, ?int $parent_id, array $payload, int $schema_version ): int {
⋮----
throw new \RuntimeException( 'Failed to JSON-encode snapshot payload.' );
⋮----
$table = SchemaInstaller::get_table_name( SchemaInstaller::TABLE_SNAPSHOTS );
⋮----
$inserted = $wpdb->insert(
⋮----
throw new \RuntimeException( 'Failed to insert snapshot.' );
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Support/RESTPermissions.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration\Support;
⋮----
class RESTPermissions {
⋮----
public function require_logged_in_permission() {
⋮----
return new \WP_Error(
⋮----
public function require_admin_permission() {
$logged_in = $this->require_logged_in_permission();
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Integration/Bootstrap.php">
namespace Automattic\WooCommerce\SubscriptionsEngine\Integration;
⋮----
use Automattic\WooCommerce\SubscriptionsEngine\Api\Rest\ContractsController;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Gateway\CapabilityRegistry;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Renewal\RenewalDispatcher;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Renewal\RenewalEngine;
use Automattic\WooCommerce\SubscriptionsEngine\Api\Rest\PlansController;
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Storage\SchemaInstaller;
⋮----
final class Bootstrap {
⋮----
private static $initialized = false;
⋮----
public static function init(): void {
⋮----
CapabilityRegistry::init();
⋮----
( new RenewalEngine() )->register_hooks();
PlansController::register_hooks();
ContractsController::register_hooks();
( new RenewalDispatcher() )->register_hooks();
⋮----
SchemaInstaller::maybe_install();
⋮----
RenewalDispatcher::ensure_scheduled();
</file>

<file path="packages/php/woocommerce-subscriptions-engine/src/Package.php">
namespace Automattic\WooCommerce\SubscriptionsEngine;
⋮----
use Automattic\WooCommerce\SubscriptionsEngine\Integration\Bootstrap;
⋮----
final class Package {
⋮----
public static function init(): void {
Bootstrap::init();
⋮----
public static function get_version(): string {
⋮----
public static function get_path(): string {
</file>

<file path="packages/php/woocommerce-subscriptions-engine/tasks/phpstan/composer.json">
{
	"name": "automattic/woocommerce-subscriptions-engine-phpstan",
	"description": "PHPStan analysis tasks for the WooCommerce Subscriptions engine.",
	"type": "project",
	"require": {
		"php": ">=7.4"
	},
	"require-dev": {
		"phpstan/phpstan": "^2.2",
		"phpstan/phpstan-phpunit": "^2.0",
		"php-stubs/woocommerce-stubs": "^10.8",
		"php-stubs/wordpress-tests-stubs": "^7.0",
		"szepeviktor/phpstan-wordpress": "^2.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	}
}
</file>

<file path="packages/php/woocommerce-subscriptions-engine/tasks/phpstan/phpstan-7.neon">
# Use the main phpstan config
includes:
	- phpstan.neon

# Rewrite tested PHP version
parameters:
	phpVersion: 70400
</file>

<file path="packages/php/woocommerce-subscriptions-engine/tasks/phpstan/phpstan.neon">
parameters:
	level: 9
	phpVersion: 80400
	tmpDir: temp
	bootstrapFiles:
		- ../../vendor/autoload.php
		- vendor/autoload.php
		- vendor/php-stubs/woocommerce-stubs/woocommerce-stubs.php
		- vendor/php-stubs/woocommerce-stubs/woocommerce-packages-stubs.php
		- ../../phpstan-stubs/stubs.php
		- vendor/php-stubs/wordpress-tests-stubs/wordpress-tests-stubs.php
	scanDirectories:
		- ../../phpstan-stubs
	paths:
		- ../../src
		- ../../tests
	treatPhpDocTypesAsCertain: false

	# Test bootstraps require the WP test framework at runtime, which PHPStan
	# must not follow; exclude them from analysis (mirrors the email-editor task).
	excludePaths:
		analyseAndScan:
			- ../../tests/unit/bootstrap.php
			- ../../tests/integration/bootstrap.php

includes:
	- vendor/szepeviktor/phpstan-wordpress/extension.neon
	- vendor/phpstan/phpstan-phpunit/extension.neon
</file>

<file path="packages/php/woocommerce-subscriptions-engine/tasks/phpstan/run-phpstan.sh">
set -e
cd "$(dirname "$0")"  # Ensure we're in the script directory
CLEANUP=true
for arg in "$@"; do
  if [ "$arg" = "--skip-cleanup" ]; then
    CLEANUP=false
    break
  fi
done
cleanup() {
  if [ "$CLEANUP" = true ]; then
    echo "🧹 Cleaning up PHPStan directories."
    rm -rf vendor/ temp/
  fi
}
trap cleanup EXIT
if ! command -v composer >/dev/null 2>&1; then
  echo "❌ Composer is not installed. Please install Composer first."
  exit 1
fi
CONFIG_FILE="phpstan.neon"
for arg in "$@"; do
  if [ "$arg" = "php7" ]; then
    CONFIG_FILE="phpstan-7.neon"
    break
  fi
done
if ! ./vendor/bin/phpstan --version >/dev/null 2>&1; then
  echo "🔧 PHPStan not found. Installing dependencies..."
  composer install --quiet
... (5 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/.wp-env.json">
{
	"phpVersion": "8.3",
	"plugins": [
		"https://downloads.wordpress.org/plugin/woocommerce.zip",
		"."
	],
	"config": {
		"JETPACK_AUTOLOAD_DEV": true,
		"WP_DEBUG_LOG": true,
		"WP_DEBUG_DISPLAY": true,
		"ALTERNATE_WP_CRON": true
	},
	"mappings": {
	},
	"env": {
		"development": {
			"port": 8883
		},
		"tests": {
			"port": 8083,
			"plugins": [
				"https://downloads.wordpress.org/plugin/woocommerce.zip",
				"."
			],
			"themes": [],
			"config": {
			}
		}
	}
}
... (1 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/composer.json">
{
	"name": "automattic/woocommerce-subscriptions-engine",
	"description": "Subscriptions engine for WooCommerce.",
	"type": "wordpress-plugin",
	"license": "GPL-2.0-or-later",
	"prefer-stable": true,
	"minimum-stability": "dev",
	"version": "0.0.1",
	"autoload": {
		"psr-4": {
			"Automattic\\WooCommerce\\SubscriptionsEngine\\": "src/"
		}
	},
	"autoload-dev": {
		"classmap": [
			"tests/unit/",
			"tests/integration/"
		]
	},
	"require": {
		"php": ">=7.4"
	},
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0",
		"phpunit/phpunit": "^9.6",
		"woocommerce/woocommerce-sniffs": "1.0.0",
		"yoast/phpunit-polyfills": "^4.0"
	},
	"config": {
		"platform": {
... (40 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/license.txt">
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

===================================


GNU GENERAL PUBLIC LICENSE
   Version 2, June 1991

Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

		Preamble

The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
... (327 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/package.json">
{
	"name": "@automattic/woocommerce-subscriptions-engine",
	"description": "Subscriptions engine for WooCommerce.",
	"scripts": {
		"changelog": "XDEBUG_MODE=off composer install --quiet && composer exec -- changelogger",
		"update:php": "XDEBUG_MODE=off composer update --quiet",
		"lint": "pnpm --if-present '/^lint:lang:.*$/'",
		"lint:fix": "pnpm --if-present '/^lint:fix:lang:.*$/'",
		"lint:fix:lang:php": "composer run-script phpcbf",
		"lint:lang:php": "composer run-script phpcs",
		"phpstan": "cd tasks/phpstan && ./run-phpstan.sh",
		"phpstan:php7": "cd tasks/phpstan && ./run-phpstan.sh php7",
		"phpstan:php8": "cd tasks/phpstan && ./run-phpstan.sh",
		"test:php:ci": "pnpm test:php:unit && pnpm test:php:integration",
		"test:php:unit": "composer run-script test:unit",
		"test:php:integration": "composer run-script test:integration",
		"env:test": "pnpm wp-env start --update",
		"postinstall": "composer install"
	},
	"license": "GPL-2.0-or-later",
	"devDependencies": {
		"@wordpress/env": "11.9.0"
	},
	"config": {
		"ci": {
			"lint": {
				"command": "lint",
				"changes": [
					"**/*.php",
					"phpcs.xml"
... (59 lines truncated)
</file>

<file path="packages/php/woocommerce-subscriptions-engine/phpcs.xml">
<?xml version="1.0"?>
<ruleset name="Custom WordPress Standards">
	<rule ref="WordPress"/>
	<file>.</file>
	<rule ref="PSR12.Properties.ConstantVisibility.NotFound">
		<type>error</type>
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="WordPress.Files.FileName">
		<exclude-pattern>tests/*</exclude-pattern>
	</rule>
	<rule ref="WordPress.Files.FileName.InvalidClassFileName">
		<exclude-pattern>src/</exclude-pattern>
	</rule>
	<rule ref="WordPress.Files.FileName.NotHyphenatedLowercase">
		<exclude-pattern>src/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Classes.ClassFileName">
		<include-pattern>src/</include-pattern>
	</rule>
	<rule ref="Squiz.Classes.ValidClassName">
		<include-pattern>src/</include-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FunctionComment.Missing">
		<exclude-pattern>tests/*</exclude-pattern>
	</rule>
	<rule ref="Generic.Commenting.DocComment.MissingShort">
		<exclude-pattern>tests/*</exclude-pattern>
	</rule>
	<rule ref="WordPress.Security.EscapeOutput">
		<exclude-pattern>src/Core/*</exclude-pattern>
	</rule>
	<rule ref="WordPress.DB.SlowDBQuery">
		<exclude-pattern>src/Integration/Storage/*</exclude-pattern>
	</rule>
	<rule ref="PSR2.Methods.MethodDeclaration.Underscore">
		<exclude-pattern>tests/unit</exclude-pattern>
	</rule>
	<exclude-pattern>vendor/*</exclude-pattern>
	<exclude-pattern>node_modules/*</exclude-pattern>
	<exclude-pattern>tasks/phpstan/temp/*</exclude-pattern>
	<exclude-pattern>phpstan-stubs/*</exclude-pattern>
	<exclude-pattern>build/*</exclude-pattern>
</ruleset>
</file>

<file path="packages/php/woocommerce-subscriptions-engine/README.md">
# WooCommerce Subscriptions Engine

This package implements a general-purpose subscriptions engine for WooCommerce.
</file>

<file path="packages/php/woocommerce-subscriptions-engine/woocommerce-subscriptions-engine.php">
\Automattic\WooCommerce\SubscriptionsEngine\Package::init();
</file>

<file path="packages/php/.gitkeep">

</file>

<file path="plugins/woocommerce/changelog/.gitkeep">

</file>

<file path="plugins/woocommerce/changelog/29386-product-name-css-class">
Significance: patch
Type: enhancement

Add a reusable CSS class to product names in improved order emails.
</file>

<file path="plugins/woocommerce/changelog/29906-fix-rest-review-rating-recompute">
Significance: patch
Type: fix

Update product rating aggregates when REST API reviews are created, re-rated, or moved between products in wc/v1, wc/v2, and wc/v3.
</file>

<file path="plugins/woocommerce/changelog/30964-support-array-structured-data-types">
Significance: patch
Type: fix

Allow structured data filters to return multiple schema types without causing a fatal error or dropping valid product markup.
</file>

<file path="plugins/woocommerce/changelog/30996-focus-product-search">
Significance: patch
Type: enhancement

Open the product picker automatically when adding products to an order, so merchants can start typing without an extra click.
</file>

<file path="plugins/woocommerce/changelog/31339-payment-method-all-methods-label">
Significance: patch
Type: update

Rename the default Payment method option on the order screen from "N/A" to "All methods available", so it says what the customer will actually be offered.
</file>

<file path="plugins/woocommerce/changelog/32209-add-phone-to-customer-reports">
Significance: minor
Type: add

Add billing and shipping phone columns to the Analytics Customers report, its REST API, and CSV export.
</file>

<file path="plugins/woocommerce/changelog/33410-fix-refund-customer-type-analytics">
Significance: patch
Type: fix

Analytics > Orders: report refunds with the customer type of the order they refund, instead of always reporting them as returning customers.
</file>

<file path="plugins/woocommerce/changelog/36329-fix-refund-attributed-to-user-1">
Significance: patch
Type: fix

Stop attributing refunds to user #1 when no user is logged in. refunded_by is now 0 in REST v1-v3 and null in v4, and the admin labels these refunds as System.
</file>

<file path="plugins/woocommerce/changelog/36538-selected-any-variation-names">
Significance: minor
Type: fix

Include selected "Any" variation values in classic cart and checkout displays and in new order item names, and stop variation values already shown in an item name from being repeated as cart or order metadata, including on existing orders.
</file>

<file path="plugins/woocommerce/changelog/36758-product-category-list-order">
Significance: minor
Type: add

Add an $orderby argument to wc_get_product_category_list() and order single-product meta categories by hierarchy. Stores on the stock single-product/meta.php template now render categories ancestor-first; return an empty string from woocommerce_product_meta_category_orderby to restore WordPress term-list order.
</file>

<file path="plugins/woocommerce/changelog/38347-fix-tax-lookup-grain">
Significance: minor
Type: fix

Store one wc_order_tax_lookup row per tax order item, so Analytics tax reports keep every tax line of an order, including lines that share a tax rate id, and drop rows for tax lines that have been removed.
</file>

<file path="plugins/woocommerce/changelog/38347-tax-lookup-failed-import-retry">
Significance: patch
Type: fix

Keep an order on the Analytics failed imports list when its tax lookup rows could not be written, so a retry that fails again stays visible instead of reporting success.
</file>

<file path="plugins/woocommerce/changelog/38347-tax-lookup-grain-schema">
Significance: minor
Type: dev

wc_order_tax_lookup gains an order_item_id column and is re-keyed on (order_id, tax_rate_id, order_item_id), so it now holds one row per tax line instead of one row per tax rate. Code summing the table is unaffected and code counting rows will see more of them. Code writing to the table with $wpdb->replace() on (order_id, tax_rate_id) lands on the new column's zero default rather than replacing the rows WooCommerce writes for that order. The reports leave such a row out while those rows stand, so its values are not read at all and it needs to write order_item_id too. Existing rows are rebuilt in the background, and can be rebuilt by hand from WooCommerce > Status > Tools.
</file>

<file path="plugins/woocommerce/changelog/41225-performance-skip-review-lookup-updates">
Significance: patch
Type: performance

Improve performance when product reviews are disabled by skipping product rating lookup table updates.
</file>

<file path="plugins/woocommerce/changelog/42348-batch-shipping-rate-selection">
Significance: patch
Type: fix

Keep other packages' shipping selections when one package's selection fails, and leave the rejected rate unselected so the shopper can retry it.
</file>

<file path="plugins/woocommerce/changelog/42469-keep-incompatible-notice-dismissed">
Significance: patch
Type: fix

Keep the Cart and Checkout incompatible extensions notices (editor sidebar and storefront banner) dismissed when an incompatible extension or payment gateway is disabled, and warn again only when something the merchant has not yet acknowledged becomes incompatible. Dismissals are now stored per site. Existing dismissals carry over on single-site installs but not on multisite installs, where notices may need to be dismissed again after upgrading.
</file>

<file path="plugins/woocommerce/changelog/42492-product-collection-sort-fixtures">
Significance: patch
Type: dev

Seed deterministic ratings and sales data for Product Collection Blocks E2E sorting tests.
</file>

<file path="plugins/woocommerce/changelog/42662-product-categories-inspector-controls-unit-tests">
Significance: patch
Type: dev

Add unit test coverage for the Product Categories List block attributes: display style, product count, category images, hierarchy, and empty categories.
</file>

<file path="plugins/woocommerce/changelog/44157-fix-paypal-api-credentials-link">
Significance: patch
Type: fix

Fix the PayPal API credentials settings link.
</file>

<file path="plugins/woocommerce/changelog/44613-fix-inconsistent-checkout-error-handling">
Significance: patch
Type: fix

Render Cart and Checkout notices with the same list markup whether there is one notice or several, and expose each notice's id as `data-id` on its list item.
</file>

<file path="plugins/woocommerce/changelog/45168-product-image-id-casts">
Significance: patch
Type: fix

Pass product image IDs to WordPress attachment functions as integers.
</file>

<file path="plugins/woocommerce/changelog/49059-include-dates-in-emailed-analytics-exports">
Significance: minor
Type: enhancement

Include the report's date range in emailed Analytics exports, in the email and in the downloaded file's name.
</file>

<file path="plugins/woocommerce/changelog/49368-add-webpack-chunk-names">
Significance: patch
Type: tweak

Give nice names to webpack JS and CSS dynamic chunks
</file>

<file path="plugins/woocommerce/changelog/50786-add-server-side-search-opt-out">
Significance: minor
Type: add

Add the `woocommerce_admin_report_server_side_search_item_types` JavaScript filter, so an integration that overrides an Analytics report route with a handler that does not read `search` can opt out of server-side search and keep receiving resolved item IDs.
</file>

<file path="plugins/woocommerce/changelog/50786-fix-analytics-products-search-limit">
Significance: minor
Type: fix

Show every matching product when a search matches more than 100 products, in the Analytics > Products report and in the single category view of the Analytics > Categories report. The products report endpoints now accept a `search` argument and resolve the search themselves.
</file>

<file path="plugins/woocommerce/changelog/51426-fix-prices-include-tax-on-order-create">
Significance: minor
Type: fix

Initialize new orders with the store's tax entry mode, and preserve saved order values when the store setting changes.
</file>

<file path="plugins/woocommerce/changelog/51602-fix-order-attribution-origin-overflow">
Significance: patch
Type: fix

Fix a long order origin overflowing the Order attribution metabox. The origin now takes the full width of the metabox and is truncated to one line while the details are collapsed, and the details toggle has moved to the bottom of the metabox.
</file>

<file path="plugins/woocommerce/changelog/52517-failed-order-text-filter">
Significance: patch
Type: add

Add an order-aware filter for failed order confirmation messages in classic and block renderers.
</file>

<file path="plugins/woocommerce/changelog/53136-platform-selector-mobile-keyboard">
Significance: patch
Type: fix

Stop the virtual keyboard from opening on the core profiler platform selector on touch devices.
</file>

<file path="plugins/woocommerce/changelog/57940-checkout-country-change-shipping-rates">
Significance: patch
Type: fix

Recalculate shipping options as soon as the country is changed at checkout, instead of keeping the previous country's options until the rest of the address is filled in.
</file>

<file path="plugins/woocommerce/changelog/60577-featured-image-metadata-loss">
Significance: patch
Type: fix

Prevent featured image metadata loss when a WooCommerce image size is not registered.
</file>

<file path="plugins/woocommerce/changelog/60577-fix-attachment-metadata-loss">
Significance: patch
Type: fix

Preserve third party attachment metadata keys when regenerating product images.
</file>

<file path="plugins/woocommerce/changelog/63303-admin-price-wrapping">
Significance: patch
Type: fix

Prevent price amounts from wrapping onto multiple lines in admin list tables when a space is used as the thousands separator.
</file>

<file path="plugins/woocommerce/changelog/63697-analytics-taxes-taxable-amount">
Significance: minor
Type: add

Add a taxable amount column to the Analytics Taxes report, recording the net amount each tax rate applied to.
</file>

<file path="plugins/woocommerce/changelog/64439-fix-stock-notifications-cancel-page">
Significance: patch
Type: fix

Stock notifications: return the customer to the page they cancelled a notification from, instead of the first page of the list.
</file>

<file path="plugins/woocommerce/changelog/64439-my-account-stock-notifications">
Significance: minor
Type: add

Add a Stock notifications tab to My Account, so customers can review the back-in-stock sign-ups they have made and cancel the ones they no longer want.
</file>

<file path="plugins/woocommerce/changelog/65412-fix-hidden-required-fields">
Significance: patch
Type: fix

Skip required validation for hidden address fields on the classic checkout and My Account address form.
</file>

<file path="plugins/woocommerce/changelog/65484-fix-cart-item-data-non-scalar">
Significance: patch
Type: fix

Prevent non-scalar cart item data provided by extensions from causing a fatal error when rendering the classic cart.
</file>

<file path="plugins/woocommerce/changelog/65764-checkout-order-summary-breakpoint">
Significance: patch
Type: enhancement

Cart and Checkout blocks: give the order summary a fixed 360px column and hold the single-column layout until there is room for both columns, so mid-range viewports are no longer cramped.
</file>

<file path="plugins/woocommerce/changelog/66072-perf-v4-customer-schema-gate-aggregates">
Significance: patch
Type: performance

REST API: in the wc/v4 customers endpoint, only compute the order count, total spent and avatar fields when they are requested via _fields, avoiding wasted per-customer aggregate queries on sparse requests.
</file>

<file path="plugins/woocommerce/changelog/66317-perf-memoize-country-extensions">
Significance: patch
Type: performance

Memoize the payment extension suggestions list per country and context so it is built once per request instead of once per registered gateway.
</file>

<file path="plugins/woocommerce/changelog/66520-fix-revenue-table-stale-rows">
Significance: patch
Type: fix

Fix Analytics Revenue table rows keeping the first dataset loaded when an extension report filter changes.
</file>

<file path="plugins/woocommerce/changelog/66953-unify-postcode-validation">
Significance: patch
Type: fix

Unify postcode validation rules used by the server and Checkout blocks.
</file>

<file path="plugins/woocommerce/changelog/67124-fix-store-api-cart-session-error-boundary">
Significance: patch
Type: fix

Return a Store API error response instead of a fatal error when the cart cannot be loaded from the session.
</file>

<file path="plugins/woocommerce/changelog/67323-fix-product-permalink-radio-checked-state">
Significance: patch
Type: fix

Fix product permalink settings radio buttons reverting to "Custom base" after saving Default, Shop base, or Shop base with category.
</file>

<file path="plugins/woocommerce/changelog/67354-fix-own-stock-reservation-lockout">
Significance: patch
Type: fix

Fix a shopper being blocked in the checkout shortcode by a stock hold created by their own cancelled order.
</file>

<file path="plugins/woocommerce/changelog/67459-lv-postcode-validation">
Significance: patch
Type: fix

Add postcode validation for Latvia, which previously accepted invalid values.
</file>

<file path="plugins/woocommerce/changelog/67496-fix-sale-price-dates-help-tip-position">
Significance: patch
Type: fix

Fix the Sale price dates help tip rendering below the Cancel link instead of next to its label in the product editor.
</file>

<file path="plugins/woocommerce/changelog/67644-variation-price-filter-docs">
Significance: patch
Type: fix

Clarify that variation price filters use string values.
</file>

<file path="plugins/woocommerce/changelog/67709-invalidate-product-term-cache">
Significance: patch
Type: fix

Invalidate cached product terms when their taxonomy terms are reordered.
</file>

<file path="plugins/woocommerce/changelog/67711-fix-order-attribution-form-dedup">
Significance: patch
Type: fix
Comment: Select if this PR needs a generated summary for release notes:  - [ ] **Feature Highlight** - For user-facing features (what changed, user impact) - [ ] **Developer Advisory** - For developer-facing changes (what changed, how to detect, actions needed)  <details> <summary>When to use each?</summary>  **Feature Highlight**: New features, UI changes, or improvements that merchants/store owners will notice. - Example: "New bulk editing for products", "Improved checkout performance"  **Developer Advisory**: Breaking changes, deprecations, or changes that affect themes/plugins/extensions. - Example: "Hook signature change", "Deprecated filter", "REST API field removed"  An AI will analyze your PR and post a draft comment for you to review and edit.
</file>

<file path="plugins/woocommerce/changelog/67855-hook-docs-generator-guards">
Significance: patch
Type: dev

Guard every hook.doc read in the Blocks hook docs generator. No change to the generated reference.
</file>

<file path="plugins/woocommerce/changelog/67855-hook-docs-product-add-to-cart">
Significance: patch
Type: dev

Fix the product and add to cart block hook docblocks.
</file>

<file path="plugins/woocommerce/changelog/67855-hook-docs-storeapi-shipping">
Significance: patch
Type: dev

Correct the Store API cart and checkout hook docblocks, and say where the local pickup tax filters are documented.
</file>

<file path="plugins/woocommerce/changelog/67931-revert-67751-fix-67354-own-reserved-stock-grace-window">
Significance: patch
Type: fix

Restore pending stock holds to prevent multiple payable orders from reserving the same stock.
</file>

<file path="plugins/woocommerce/changelog/67978-add-localized-thousands-separators-to-legacy-report-counts">
Significance: minor
Type: enhancement

Format count values in the legacy Reports chart legends with locale-aware thousands separators.
</file>

<file path="plugins/woocommerce/changelog/68009-order-count-cache-late-registered-status">
Significance: patch
Type: fix

Flush the order count cache when a plugin is activated or deactivated, so newly registered order statuses show up in the Orders list right away.
</file>

<file path="plugins/woocommerce/changelog/68064-add-bis-e2e-variation-coverage">
Significance: patch
Type: dev
Comment: Add Playwright E2E coverage for Back in Stock Notifications on variable products and variations (form show/hide per variation, variation signup, variation attributes in the emails, and the back-in-stock CTA linking back to a fixed-value variation).
</file>

<file path="plugins/woocommerce/changelog/68079-add-bis-e2e-signup-and-email-branch-coverage">
Significance: patch
Type: dev
Comment: Add Playwright E2E coverage for the remaining Back in Stock Notifications signup and email branches (signups disabled, account creation on signup, requires-account login flow, logged-in email footer, frontend verify/unsubscribe notices, tampered and expired email links, invalid email/product/nonce rejections).
</file>

<file path="plugins/woocommerce/changelog/68101-grant-access-search-exclude">
Significance: patch
Type: fix

Pass the include/exclude parameters through to the downloadable product search so the Grant access field on the order edit screen no longer lists products that are already selected.
</file>

<file path="plugins/woocommerce/changelog/68165-65956-mini-cart">
Significance: patch
Type: fix

Prevent Mini-Cart item removals from being cancelled when navigating away.
</file>

<file path="plugins/woocommerce/changelog/68168-order-fieldset-not-tied-to-order-notes">
Significance: patch
Type: fix

Fix the shortcode checkout dropping every other field in the order fieldset when order notes are disabled, which also left a required field there blocking checkout with no way to fill it in.
</file>

<file path="plugins/woocommerce/changelog/68292-my-account-pending-stock-notifications">
Significance: minor
Type: add

Add an "Awaiting confirmation" section to the Stock notifications My Account tab, listing unconfirmed sign-ups with Resend email and Cancel actions above the active notifications table.
</file>

<file path="plugins/woocommerce/changelog/68368-fix-receipt-deleted-variation-parent">
Significance: patch
Type: fix

Fix a fatal error generating receipts for orders with a deleted variation parent.
</file>

<file path="plugins/woocommerce/changelog/68515-fix-bis-new-install-allow-signups">
Significance: patch
Type: fix

Enable Back in Stock Notifications sign-ups by default on new installs, as intended, instead of leaving the sign-up form off because the install hook wrote the wrong option name.
</file>

<file path="plugins/woocommerce/changelog/68530-order-summary-collapsible-bar-keyboard-defaults">
Significance: patch
Type: fix

Checkout block: stop Space scrolling the page and Enter submitting the form when toggling the collapsible order summary.
</file>

<file path="plugins/woocommerce/changelog/68530-order-summary-collapsible-bar-operable">
Significance: patch
Type: fix

Checkout block: keep the collapsible order summary expandable by mouse and keyboard before the container width has been measured.
</file>

<file path="plugins/woocommerce/changelog/68xxx-fix-stock-notifications-endpoint-slug-sanitize">
Significance: patch
Type: fix

Sanitize the stock notifications My Account endpoint slug when saved from settings.
</file>

<file path="plugins/woocommerce/changelog/add-35684-chw-currency">
Significance: minor
Type: add

Add the WIR franc (CHW) to the list of available store currencies.
</file>

<file path="plugins/woocommerce/changelog/add-cart-item-data-raw-key">
Significance: minor
Type: add

Store API: add `raw_key` to cart item `item_data` so extensions can identify their own entries without matching a translated label.
</file>

<file path="plugins/woocommerce/changelog/add-dismiss-whats-next-tasks">
Significance: patch
Type: add

Add a skip action for individual Things to do next tasks.
</file>

<file path="plugins/woocommerce/changelog/add-filter-chips-styles">
Significance: minor
Type: add

Add support for typography, padding, and border radius styles to the Chips block
</file>

<file path="plugins/woocommerce/changelog/add-helper-api-rate-limit-backoff">
Significance: minor
Type: add

Add rate-limit (HTTP 429) backoff for WooCommerce.com update-check and subscriptions API requests, respecting the Retry-After header.
</file>

<file path="plugins/woocommerce/changelog/add-identifier-placeholder-sniff">
Significance: patch
Type: dev

Add a PHPCS sniff that flags unguarded use of the `%i` SQL identifier placeholder in `wpdb::prepare()` calls, so trusted identifiers are interpolated directly (or `%i` is guarded with `wpdb::has_cap( 'identifier_placeholders' )`).
</file>

<file path="plugins/woocommerce/changelog/add-order-withdrawal-emails">
Significance: minor
Type: add

Add configurable customer and merchant emails for order withdrawal requests.
</file>

<file path="plugins/woocommerce/changelog/add-payment-placement-contract-tests">
Significance: patch
Type: dev

Add per-country, per-section contract tests pinning the Payments settings partner recommendations, replacing two duplicated suggestion-count data providers and several per-country spot tests.
</file>

<file path="plugins/woocommerce/changelog/add-phpcs-inline-lint-annotations">
Significance: patch
Type: dev

Surface PHPCS findings as inline annotations on a pull request's Files changed tab.
</file>

<file path="plugins/woocommerce/changelog/add-product-filter-overlay-controls">
Significance: minor
Type: add

Add Off, Mobile, and Always overlay modes to Product Filters block.
</file>

<file path="plugins/woocommerce/changelog/add-quantity-selector-background-color">
Significance: minor
Type: add

Add support for text and background color styles in the Product Quantity block
</file>

<file path="plugins/woocommerce/changelog/add-quantity-selector-border-radius">
Significance: minor
Type: add

Add support for border radius styles in the Product Quantity block
</file>

<file path="plugins/woocommerce/changelog/add-role-to-customers-report">
Significance: minor
Type: add

Add a Role column to the Analytics > Customers report and its CSV export, showing each customer's WordPress role(s).
</file>

<file path="plugins/woocommerce/changelog/add-store-api-cart-item-quantity-validation-filter">
Significance: minor
Type: add

Add a woocommerce_store_api_cart_item_quantity_validation filter so extensions can validate cart item quantity changes made via the Store API.
</file>

<file path="plugins/woocommerce/changelog/add-tax-rate-modal-search-pagination">
Significance: patch
Type: tweak

Add search, pagination, and an empty state to the order edit Add tax modal.
</file>

<file path="plugins/woocommerce/changelog/add-wccom-2873-auto-update-status">
Significance: minor
Type: add

Add an "Automatic updates" column to the My Subscriptions screen that turns auto-updates on or off for installed extensions and themes, and shows "Blocked" when they are on but something else stops the product updating
</file>

<file path="plugins/woocommerce/changelog/bis-features-screen-toggle">
Significance: minor
Type: dev

Move Back in Stock Notifications activation from the WOOCOMMERCE_BIS_ALPHA_ENABLED wp-config constant to a normal feature toggle at WooCommerce → Settings → Advanced → Features → Experimental.
</file>

<file path="plugins/woocommerce/changelog/blocks-e2e-seed-idempotency">
Significance: patch
Type: dev

Make the Blocks e2e seed re-runnable and fail loudly on a broken step.
</file>

<file path="plugins/woocommerce/changelog/codex-fix-product-filters-zero-block-gap">
Significance: patch
Type: fix

Ensure Product Filters respect zero block spacing on the frontend.
</file>

<file path="plugins/woocommerce/changelog/codex-woothme-502-product-filters-sticky-support">
Significance: minor
Type: add

Add sticky positioning support to the Product Filters block.
</file>

<file path="plugins/woocommerce/changelog/core-e2e-remove-redundant-tests">
Significance: patch
Type: dev

Remove core E2E tests whose coverage exists elsewhere: the duplicated logged-in Checkout Link block, the WordPress-core lost password specs, and seven of eight identical order status filter cases.
</file>

<file path="plugins/woocommerce/changelog/deprecate-brand-recount-methods">
Significance: minor
Type: update

Deprecate the WC_Brands recount methods in favor of the shared term recount functions.
</file>

<file path="plugins/woocommerce/changelog/dev-66603-folloup-deprecate-cycle-start">
Significance: minor
Type: dev

Product ordering: start legacy algorithm deprecation cycle.
</file>

<file path="plugins/woocommerce/changelog/dev-ci-jobs-job-level-ignore">
Significance: patch
Type: dev
Comment: CI configuration only: adds job-level ignore globs to the plugin's config.ci jobs so non-code files stop triggering them.
</file>

<file path="plugins/woocommerce/changelog/dev-clean-settings-ui-styles">
Significance: patch
Type: dev
Comment: Remove obsolete Settings UI renderer styles and duplicate DataViews CSS; no merchant-facing change.
</file>

<file path="plugins/woocommerce/changelog/dev-fix-classic-assets-stylelint-scss-syntax">
Significance: patch
Type: dev

Fix the classic-assets stylelint setup to parse SCSS and clean up the violations it surfaced. Tooling and source-formatting only, no functional CSS changes.
</file>

<file path="plugins/woocommerce/changelog/dev-markup-contract-suppressions">
Significance: patch
Type: dev

Document intentional product, order, and payment markup contracts with exact coding-standard annotations.
</file>

<file path="plugins/woocommerce/changelog/dev-phpcs-test-hook-sniff-exclusions">
Significance: patch
Type: dev

Exclude the hook comment and hyphenated hook name phpcs sniffs for tests and remove the redundant inline ignores.
</file>

<file path="plugins/woocommerce/changelog/dev-remove-autoprefixer-legacy-css">
Significance: patch
Type: dev

Remove the no-op autoprefixer step from the legacy assets CSS build and clean the obsolete vendor prefixes it was stripping from the sources. Built CSS is unchanged.
</file>

<file path="plugins/woocommerce/changelog/dev-remove-ie8-leftovers">
Significance: patch
Type: dev

Remove IE8-era leftovers from the classic-assets build: the ie8 uglify flag, the IE 8/9 browserslist targets, and two dead IE-only CSS hacks. Minified output changes; no behavior change on any supported browser.
</file>

<file path="plugins/woocommerce/changelog/dev-remove-settings-ui-group-actions">
Significance: patch
Type: dev
Comment: Remove unsupported group header actions from the experimental Settings UI schema.
</file>

<file path="plugins/woocommerce/changelog/dev-remove-unused-grunt-phpcs-clean">
Significance: patch
Type: dev
Comment: Remove the unused grunt-phpcs and grunt-contrib-clean packages from the classic-assets Grunt setup; no registered task ever ran them.
</file>

<file path="plugins/woocommerce/changelog/dev-report-header-advanced-filters-type">
Significance: patch
Type: dev
Comment: Type the ReportHeader advancedFilters prop with AdvancedFilterConfig from @woocommerce/components.
</file>

<file path="plugins/woocommerce/changelog/dev-resolve-more-npm-alerts">
Significance: patch
Type: dev

Update npm dependencies and remove unused build tools to close more Dependabot alerts.
</file>

<file path="plugins/woocommerce/changelog/dev-revert-classic-assets-node-build">
Significance: patch
Type: dev

Revert the @woocommerce/classic-assets node build script and restore the Grunt pipeline. Built assets are unchanged either way.
</file>

<file path="plugins/woocommerce/changelog/dev-settings-registration-admin-init-priority">
Significance: patch
Type: dev

Settings registration now runs on `admin_init` at priority 999 instead of the default 10, so it runs after other callbacks on that hook rather than before. Code that unhooks it must match the new priority: `remove_action( 'admin_init', array( WC(), 'register_wp_admin_settings' ), 999 )`; the no-priority form that matches in 11.0.1 and 11.1 silently stops matching.
</file>

<file path="plugins/woocommerce/changelog/dev-settings-request-boundary-suppressions">
Significance: patch
Type: dev

Document intentional raw-data boundaries in the settings APIs with exact coding-standard annotations.
</file>

<file path="plugins/woocommerce/changelog/dev-test-bootstrap-disable-code-hacker">
Significance: patch
Type: dev

Allow running the PHPUnit suite without the code hacker by setting the WC_TEST_DISABLE_CODE_HACKER environment variable, for tools such as mutation testers that need to own the file stream wrapper.
</file>

<file path="plugins/woocommerce/changelog/docs-analytics-customer-hook-timing">
Significance: patch
Type: dev
Comment: Document Analytics customer creation hook timing and cover repeated customer-history views and imports.
</file>

<file path="plugins/woocommerce/changelog/docs-enum-get-all-scope">
Significance: patch
Type: dev

Document what Enums get_all() returns compared with the filterable wc_get_*() helpers, including the differing return shapes and the wc- prefix on order statuses.
</file>

<file path="plugins/woocommerce/changelog/enhancement-53323-analytics-default-status-filters">
Significance: minor
Type: add

Introduce two new PHP filters, woocommerce_analytics_settings_default_excluded_order_statuses and woocommerce_analytics_settings_default_actionable_order_statuses, that let plugins change the default order statuses used by Analytics. The filters apply everywhere, not only to the boxes pre-checked on the Analytics Settings screen: on a store that has never saved these options they also change report totals, the order status enum returned by the reports REST controllers, the Activity Panel orders-to-fulfill count, and the Customer History box.
</file>

<file path="plugins/woocommerce/changelog/fix-28591-coupon-discount-on-edited-order-totals">
Significance: patch
Type: fix

Fix coupons applied in the order editor ignoring manually edited line item totals.
</file>

<file path="plugins/woocommerce/changelog/fix-29727-csv-importer-plus-in-path">
Significance: patch
Type: fix

Fix product CSV importer failing between steps when the file path contains special characters such as '+', and show a clear error when the CSV file cannot be opened.
</file>

<file path="plugins/woocommerce/changelog/fix-31068-order-item-qty-validation">
Significance: minor
Type: fix

Show the browser validation message for negative order item quantities in the admin order editor instead of silently failing, and reject them server-side in the order items AJAX endpoints.
</file>

<file path="plugins/woocommerce/changelog/fix-31637-rtl-currency-symbol-bidi">
Significance: patch
Type: fix

Direction-isolate the currency symbol in wc_price() so RTL-script symbols (e.g. Lebanese Pound) respect the configured currency position and no longer bleed into surrounding text.
</file>

<file path="plugins/woocommerce/changelog/fix-31656-order-item-cache-shape">
Significance: patch
Type: fix

Ensure the cached order item data always includes the item type and item ID, so the cache shape is consistent between the order data store and the order item data store.
</file>

<file path="plugins/woocommerce/changelog/fix-32113-short-description-pagehide">
Significance: patch
Type: fix

Fix the product short description editor becoming blank after moving its metabox.
</file>

<file path="plugins/woocommerce/changelog/fix-33344-unnamed-product-save">
Significance: patch
Type: fix

Preserve product data when saving a new product without a name in the classic editor by using the default “(no title)” name.
</file>

<file path="plugins/woocommerce/changelog/fix-35607-product-search-order">
Significance: patch
Type: fix

Prioritize product title matches in default admin searches while preserving broad matches and explicit sorting.
</file>

<file path="plugins/woocommerce/changelog/fix-35635-account-orders-column-filter">
Significance: patch
Type: add

Add composable woocommerce_account_orders_column_content_{$column_id} filters for the My Account orders table columns and bump the myaccount/orders.php template version to 11.1.0.
</file>

<file path="plugins/woocommerce/changelog/fix-36937-installing-rewrite-flush">
Significance: patch
Type: fix
Comment: Defer rewrite rule flushes raised during WordPress installing-mode requests, when themes and plugins may not be loaded, to the next normal request.
</file>

<file path="plugins/woocommerce/changelog/fix-37121-sequential-coupon-order">
Significance: patch
Type: fix

Make sequential coupons with equal priorities calculate in application order.
</file>

<file path="plugins/woocommerce/changelog/fix-37789-exact-attribute-term-search">
Significance: patch
Type: fix

Ensure exact global attribute terms remain selectable when partial matches fill the search results.
</file>

<file path="plugins/woocommerce/changelog/fix-38574-tracker-retry-snapshots">
Significance: patch
Type: fix

Retry failed usage-tracking snapshot deliveries on the next scheduled run instead of silently dropping them for a week.
</file>

<file path="plugins/woocommerce/changelog/fix-38919-unregister-deleted-attribute-taxonomy">
Significance: patch
Type: fix

Unregister a global product attribute's runtime taxonomy when the attribute is deleted so its slug can be reused in the same request.
</file>

<file path="plugins/woocommerce/changelog/fix-39052-normalize-ces-submit-label">
Significance: patch
Type: fix

Use the canonical customer effort score submit label property for inline survey dispatches.
</file>

<file path="plugins/woocommerce/changelog/fix-39112-api-tests-tracking-enabled">
Significance: patch
Type: dev

Run Core API tests with usage tracking enabled in pull request, nightly, and release CI.
</file>

<file path="plugins/woocommerce/changelog/fix-39462-date-paid-filter-timezone">
Significance: patch
Type: fix

Make the date_paid/date_completed day filter on the legacy orders list table respect the site timezone, so the listed orders match the requested local day.
</file>

<file path="plugins/woocommerce/changelog/fix-39652-samesite-password-reset">
Significance: patch
Type: fix

Allow password reset links to work when reset cookies use SameSite=Strict.
</file>

<file path="plugins/woocommerce/changelog/fix-40443-checkout-notice-validation">
Significance: patch
Type: fix

Prevent non-error checkout update notices from triggering field validation.
</file>

<file path="plugins/woocommerce/changelog/fix-40683">
Significance: patch
Type: fix

Fix the Create shipping label button by showing a completion notice and a Reload page button after WooCommerce Shipping is installed and activated.
</file>

<file path="plugins/woocommerce/changelog/fix-40791-checkout-apostrophe-encoding">
Significance: patch
Type: fix

Encode apostrophes in classic checkout request data.
</file>

<file path="plugins/woocommerce/changelog/fix-40831-stock-report-export-post-status">
Significance: patch
Type: fix

Analytics: pin the Stock report to published and private products so its CSV export always completes and its download email is sent.
</file>

<file path="plugins/woocommerce/changelog/fix-41318-hpos-orders-date-filter">
Significance: patch
Type: fix

Fix date filtering of the HPOS orders list via links from Analytics reports (order_date_type and day-granularity date params were ignored).
</file>

<file path="plugins/woocommerce/changelog/fix-41577-nbsp-separator-entities">
Significance: patch
Type: fix

Display the real character instead of the raw HTML entity when the price thousand or decimal separator is stored as an entity such as &nbsp; in Analytics, admin screens, and blocks.
</file>

<file path="plugins/woocommerce/changelog/fix-44554-analytics-excluded-long-custom-statuses">
Significance: patch
Type: fix

Respect excluded order statuses in Analytics reports when a custom status slug exceeds the 20-character storage limit
</file>

<file path="plugins/woocommerce/changelog/fix-45521-attribute-term-id-order">
Significance: patch
Type: fix

Honor the Term ID sort order for product attribute terms and variation dropdowns.
</file>

<file path="plugins/woocommerce/changelog/fix-45770-order-status-translator-context">
Significance: patch
Type: fix

Add translator context to the Orders list table "Status" column so it can be translated independently of the unrelated "Status" strings elsewhere in the admin.
</file>

<file path="plugins/woocommerce/changelog/fix-46459-core-deprecation-versions">
Significance: patch
Type: dev

Use WooCommerce Core versions in JavaScript deprecation notices.
</file>

<file path="plugins/woocommerce/changelog/fix-47008-disabled-button-state">
Significance: patch
Type: fix

Fade the whole button rather than only its label when a cart or checkout button is disabled, and stop disabled outlined buttons from taking on the dark hover styling.
</file>

<file path="plugins/woocommerce/changelog/fix-48583-cart-empty-message-translation">
Significance: patch
Type: fix

Store the default Cart page empty cart headings as block pattern references so they follow the site language instead of the install language, and restore the missing "Browse store" link.
</file>

<file path="plugins/woocommerce/changelog/fix-51088-analytics-translations-combined-file">
Significance: patch
Type: fix

Regenerate the missing combined translation file for WooCommerce Admin scripts on demand, so Analytics and other admin screens no longer show untranslated strings when the file is absent.
</file>

<file path="plugins/woocommerce/changelog/fix-51209-rest-uncaught-invalid-product">
Significance: patch
Type: fix

Prevent REST product update and duplicate requests from fatally erroring when given a variation ID, and preserve the stored product type instead of converting the product to simple when the requested type names no known class.
</file>

<file path="plugins/woocommerce/changelog/fix-52385-core-profiler-mobile-button-spacing">
Significance: patch
Type: fix

Fix the oversized gap between the two buttons on the core profiler welcome screen at mobile widths.
</file>

<file path="plugins/woocommerce/changelog/fix-53234-repair-corrupted-dashboard-sections">
Significance: patch
Type: fix

Render the Analytics dashboard and repair the stored preference when the woocommerce_admin_dashboard_sections user meta is corrupted.
</file>

<file path="plugins/woocommerce/changelog/fix-53303-day-range-in-localized-format">
Significance: patch
Type: fix

Fix the Analytics date range label showing a garbled date in languages whose month names contain digits, such as Japanese.
</file>

<file path="plugins/woocommerce/changelog/fix-53766-fee-tax_status-non-taxable">
Significance: patch
Type: fix

Set tax_status to 'none' when creating fee order items from non-taxable cart fees.
</file>

<file path="plugins/woocommerce/changelog/fix-55817-rtl-pagination-arrows">
Significance: patch
Type: fix

Fix reversed pagination arrows on Analytics report tables in RTL locales
</file>

<file path="plugins/woocommerce/changelog/fix-56112-product-task-menu">
Significance: patch
Type: fix

Correctly highlight Products submenu items throughout the empty All Products add-product flow.
</file>

<file path="plugins/woocommerce/changelog/fix-58000-strip-invisible-chars-phone">
Significance: patch
Type: fix

Strip invisible Unicode characters from phone numbers so pasted numbers are not rejected over characters the customer cannot see, store the cleaned number from the Checkout block and the My Account address form, and stop the classic checkout marking the field invalid. wc_remove_non_displayable_chars() now removes every Unicode default-ignorable code point, including the word joiner (U+2060) and the variation selectors it used to keep.
</file>

<file path="plugins/woocommerce/changelog/fix-58084-checkout-unavailable-country-select">
Significance: patch
Type: fix

Show a returning customer's saved country as a disabled option in the checkout country dropdown when the store no longer sells or ships to that country
</file>

<file path="plugins/woocommerce/changelog/fix-60415-uninstall-unschedule-actions">
Significance: patch
Type: fix

Ensure WooCommerce scheduled actions are removed on uninstall by bootstrapping Action Scheduler when no other plugin has loaded it.
</file>

<file path="plugins/woocommerce/changelog/fix-62151-refund-fix-tool-notice">
Significance: minor
Type: add

Add inbox notice pointing merchants to the full refund data fix tool
</file>

<file path="plugins/woocommerce/changelog/fix-62620-hpos-order-notes-orphaned">
Significance: patch
Type: fix

Delete orphaned order notes (comments) when an order is permanently deleted with HPOS enabled and sync disabled.
</file>

<file path="plugins/woocommerce/changelog/fix-64557-transient-version-precision">
Significance: patch
Type: fix

Fix cache invalidation no-ops when transient versions refresh within the same second.
</file>

<file path="plugins/woocommerce/changelog/fix-66720-scheduled-sales-churn">
Significance: patch
Type: fix

Stop the daily scheduled-sales cron reprocessing every completed scheduled sale as both a starting and an ending sale. Developer note: on a store whose only matches were completed sales, all four of wc_before/after_products_starting_sales and wc_before/after_products_ending_sales stop firing rather than firing with a shorter list, and the daily `wc_products_onsale` transient delete and product transient-version bump stop with them. All of these still run whenever a sale genuinely starts or ends.
</file>

<file path="plugins/woocommerce/changelog/fix-66943-additional-fields-empty-document-object">
Significance: patch
Type: fix

Fix conditional checkout fields when dependency values are missing, contain punctuation, or come from a saved order during payment retries.
</file>

<file path="plugins/woocommerce/changelog/fix-67169-historical-data-description-copy">
Significance: patch
Type: fix

Update the Import historical data description in Analytics settings to stop referencing activating WooCommerce Admin.
</file>

<file path="plugins/woocommerce/changelog/fix-67170-historical-data-actions-alignment">
Significance: patch
Type: fix

Left-align the action buttons on the Analytics settings page (Import historical data, and Reset defaults / Save settings) with the rest of the page content on wide viewports.
</file>

<file path="plugins/woocommerce/changelog/fix-67697-customer-history-excluded-long-statuses">
Significance: patch
Type: fix

Respect excluded order statuses in the Customer History metabox when a custom status slug exceeds the 20-character storage limit
</file>

<file path="plugins/woocommerce/changelog/fix-67704-normalize-coupon-spend-amounts">
Significance: patch
Type: fix

Normalize locale-formatted coupon minimum/maximum spend amounts before validating and storing them in WC_Coupon::set_minimum_amount() and WC_Coupon::set_maximum_amount().
</file>

<file path="plugins/woocommerce/changelog/fix-67862-woocommerce-template-parts-leaking-on-creation">
Significance: patch
Type: fix

Avoid customized WooCommerce template parts taking priority over template parts queried directly
</file>

<file path="plugins/woocommerce/changelog/fix-67886-product-meta-lookup-join-guard">
Significance: patch
Type: fix

Fix product list filters and sorting breaking when an extension joins the wc_product_meta_lookup table under its own alias.
</file>

<file path="plugins/woocommerce/changelog/fix-68028-deleted-product-lookup">
Significance: patch
Type: fix

Prevent fatal errors when product attribute lookup updates run after a product is deleted.
</file>

<file path="plugins/woocommerce/changelog/fix-68084-plugin-install-error-message">
Significance: patch
Type: fix

Plugin install and activation failure notices now name the plugin once and state the reason WordPress reported (for example an unmet PHP version) instead of generic advice.
</file>

<file path="plugins/woocommerce/changelog/fix-68092-error-notices-from-plugin-error">
Significance: patch
Type: fix

Dispatch plugin install/activate failures as error notices instead of success notices when the rejected PluginError is passed to createNoticesFromResponse().
</file>

<file path="plugins/woocommerce/changelog/fix-68145-skip-themes-rewrite-flush">
Significance: patch
Type: fix

Prevent WP-CLI runs that skip the active theme from consuming queued rewrite flushes and dropping theme-registered rewrite rules.
</file>

<file path="plugins/woocommerce/changelog/fix-68177-hpos-order-notes-hidden-after-untrash">
Significance: patch
Type: fix

Restore order notes when an HPOS order is untrashed, instead of leaving them permanently hidden.
</file>

<file path="plugins/woocommerce/changelog/fix-68294-default-category-tooltip-wipes-name-column">
Significance: patch
Type: fix

Fix default product category row losing Name column and actions on WordPress 7.1.
</file>

<file path="plugins/woocommerce/changelog/fix-68306-free-shipping-label-in-order-emails">
Significance: patch
Type: fix

Only show "Free!" for Free Shipping in order emails, so zero cost Flat Rate and Local Pickup methods keep their titles, and add the woocommerce_email_order_shipping_show_free_label filter to override it
</file>

<file path="plugins/woocommerce/changelog/fix-7579-installing-rewrite-call-sites">
Significance: patch
Type: fix

Prevent endpoint rewrite flushes from persisting incomplete rules during WordPress installation requests.
</file>

<file path="plugins/woocommerce/changelog/fix-add-extra-test-68477">
Significance: patch
Type: dev
Comment: Block-based Single Product template password-form logic: add extra test
</file>

<file path="plugins/woocommerce/changelog/fix-admin-dataviews-uuid-dependency">
Significance: patch
Type: dev

Declare the UUID dependency required by WooCommerce Admin builds.
</file>

<file path="plugins/woocommerce/changelog/fix-analytics-customer-type-import-order">
Significance: patch
Type: fix

Report a customer's first order as new in Analytics regardless of the order in which its orders and refunds are imported
</file>

<file path="plugins/woocommerce/changelog/fix-analytics-disjoint-category-product-filters">
Significance: patch
Type: fix

Report nothing instead of everything in Analytics when the category and product filters have no product in common. An empty intersection was indistinguishable from an absent product filter, so both filters were dropped. Affects the products, products/stats, variations, variations/stats and orders/stats report endpoints.
</file>

<file path="plugins/woocommerce/changelog/fix-analytics-export-email-never-arrives">
Significance: patch
Type: fix

Fix emailed Analytics report exports never arriving on stores with a persistent object cache.
</file>

<file path="plugins/woocommerce/changelog/fix-analytics-settings-report-cache">
Significance: patch
Type: fix

Refresh Analytics reports after saving report-affecting settings.
</file>

<file path="plugins/woocommerce/changelog/fix-bis-duplicate-signup-cross-state">
Significance: patch
Type: fix

Fix Back in Stock duplicate signup detection: match guest and logged-in signups with the same email, ignore cancelled and sent notifications, and keep signups for different variation attributes separate.
</file>

<file path="plugins/woocommerce/changelog/fix-bis-email-cta-drops-attribute">
Significance: patch
Type: fix

Fix the back-in-stock notification email CTA dropping the selected "Any" attribute from the product link.
</file>

<file path="plugins/woocommerce/changelog/fix-bis-form-add-to-cart-with-options-legacy-mode">
Significance: patch
Type: fix

Stop the Back in Stock form from rendering inside the Add to Cart + Options block, which forced the block into a legacy HTML form.
</file>

<file path="plugins/woocommerce/changelog/fix-blocks-e2e-template-revert-action">
Significance: patch
Type: dev
Comment: Scope the Blocks E2E template revert action to the requested template card; test-only, no merchant-facing change.
</file>

<file path="plugins/woocommerce/changelog/fix-blocks-hook-docs-pipeline">
Significance: patch
Type: dev

Fix the WooCommerce Blocks hook docs pipeline (build:docs) and regenerate the hooks reference (filters.md, actions.md) from the current PHP sources.
</file>

<file path="plugins/woocommerce/changelog/fix-blocks-interactivity-entries-path-substring">
Significance: patch
Type: dev
Comment: Select interactivity block build assets by file name instead of by substring of the absolute path, so the Blocks build works in checkout directories containing "style", "editor" or "frontend".
</file>

<file path="plugins/woocommerce/changelog/fix-blueprint-exclude-payment-settings">
Significance: patch
Type: fix

Exclude payment settings from Blueprint exports and clarify this in the export interface.
</file>

<file path="plugins/woocommerce/changelog/fix-cancel-order-redirect-callback">
Significance: patch
Type: dev
Comment: Follow-up to #68141 (unreleased). Move the order cancellation redirect into a separate wp_loaded callback so direct calls to WC_Form_Handler::cancel_order() keep their historical return behavior. No user-facing change.
</file>

<file path="plugins/woocommerce/changelog/fix-cancel-order-refresh-error">
Significance: patch
Type: fix

Prevent a false order cancellation error after shoppers refresh the return page.
</file>

<file path="plugins/woocommerce/changelog/fix-canonical-product-pagination">
Significance: patch
Type: fix

Fix product archive pagination links to the first page.
</file>

<file path="plugins/woocommerce/changelog/fix-catalog-sorting-label-alignment">
Significance: patch
Type: fix

Fix Catalog sorting label vertical alignment
</file>

<file path="plugins/woocommerce/changelog/fix-checkbox-description-markup">
Significance: patch
Type: fix

Normalize checkbox description tooltip markup while preserving supported formatting.
</file>

<file path="plugins/woocommerce/changelog/fix-checkout-autofill-section-prefix">
Significance: patch
Type: fix

Stop wrapping block checkout autofill hints in a billing/shipping prefix the HTML autofill grammar rejects. Browsers offer saved values on the email field again, and a field an extension set to "off" stays opted out
</file>

<file path="plugins/woocommerce/changelog/fix-consistent-stock-threshold-sanitization">
Significance: patch
Type: fix

Ensure low-stock thresholds are stored as non-negative integers.
</file>

<file path="plugins/woocommerce/changelog/fix-coupon-minimum-amount-validation">
Significance: patch
Type: fix

Validate minimum spend amount does not exceed maximum spend amount in WC_Coupon::set_minimum_amount().
</file>

<file path="plugins/woocommerce/changelog/fix-current-user-data-rest-fields">
Significance: patch
Type: fix

Include WooCommerce user fields in currentUserData when the REST API has not been initialized.
</file>

<file path="plugins/woocommerce/changelog/fix-dk-postcode-separator">
Significance: patch
Type: fix

Accept Danish postcodes that carry the DK prefix with no separator or with a space, matching the separator handling introduced for Latvian postcodes.
</file>

<file path="plugins/woocommerce/changelog/fix-duplicate-shopify-variant-sku-mapping">
Significance: patch
Type: dev

Remove the duplicated Variant SKU entry from the Shopify importer column mapping.
</file>

<file path="plugins/woocommerce/changelog/fix-e2e-wp-env-cli-cache-race">
Significance: patch
Type: dev
Comment: Read the Settings UI E2E options one at a time so two wp-env processes cannot corrupt its cache; no production change.
</file>

<file path="plugins/woocommerce/changelog/fix-email-listing-dataviews-styles">
Significance: patch
Type: fix

Restore the table styles on the Settings > Emails listing.
</file>

<file path="plugins/woocommerce/changelog/fix-external-product-category-count">
Significance: patch
Type: fix

Refresh category, tag, and brand counts after an out-of-stock product visibility term is removed.
</file>

<file path="plugins/woocommerce/changelog/fix-featured-items-image-editor-natural-size">
Significance: patch
Type: fix

Restore the real image dimensions in the Featured Product and Featured Category image editor, which opened at a square default after WordPress 6.2 merged the image editing provider into the editor component.
</file>

<file path="plugins/woocommerce/changelog/fix-features-controller-reentrancy">
Significance: patch
Type: fix

Prevent recursive feature definition initialization when hooks check WooCommerce features during translation or option callbacks.
</file>

<file path="plugins/woocommerce/changelog/fix-hydration-restore-cart-context">
Significance: patch
Type: fix

Restore the cart context after hydrating a Store API route, so a front-end page render no longer inherits the store-api cart context and its shipping behaviour.
</file>

<file path="plugins/woocommerce/changelog/fix-idempotent-settings-registration">
Significance: patch
Type: fix

Fix settings groups being registered twice, and settings pages or email classes registered from admin_init callbacks being dropped.
</file>

<file path="plugins/woocommerce/changelog/fix-identifier-placeholders-orders">
Significance: patch
Type: fix

Interpolate trusted order table names directly instead of using the `%i` placeholder in the order data stores, list table, customer history meta box, and orders REST query, so these queries stay valid on database layers that run on a supported WordPress version but don't implement `%i`.
</file>

<file path="plugins/woocommerce/changelog/fix-identifier-placeholders-sessions">
Significance: patch
Type: fix

Interpolate trusted session table names directly instead of using the `%i` placeholder, so session queries stay valid on database layers that run on a supported WordPress version but don't implement `%i`.
</file>

<file path="plugins/woocommerce/changelog/fix-last-quarter-end-date-rollover">
Significance: patch
Type: fix

Fix the last_quarter end date in TimeInterval::get_timeframe_dates(), which used an invalid September 31 and rolled over to October 1, widening the quarter by a day.
</file>

<file path="plugins/woocommerce/changelog/fix-locale-aware-geographical-cache">
Significance: patch
Type: fix

Refresh country, state, and continent names when the active locale changes.
</file>

<file path="plugins/woocommerce/changelog/fix-lv-postcode-separator">
Significance: patch
Type: fix

Accept Latvian postcodes that carry the LV prefix without a hyphen, restoring values that validated before postcode rules were added for Latvia.
</file>

<file path="plugins/woocommerce/changelog/fix-marketplace-missing-rating-guard">
Significance: patch
Type: fix

Hide the rating block on in-app Marketplace product cards when a product has no rating
</file>

<file path="plugins/woocommerce/changelog/fix-marketplace-theme-directory-copy-spacing">
Significance: patch
Type: dev
Comment: Restore a missing space in the Marketplace Themes tab copy; too small for a release note.
</file>

<file path="plugins/woocommerce/changelog/fix-mastercard-branding">
Significance: patch
Type: fix

Update the Mastercard payment-card label to use the brand's current spelling.
</file>

<file path="plugins/woocommerce/changelog/fix-mini-cart-pattern-wrappers">
Significance: patch
Type: fix

Prevent duplicate Mini-Cart markup when a template part references a block pattern.
</file>

<file path="plugins/woocommerce/changelog/fix-order-attribution-form-dedup">
Significance: patch
Type: fix

Preserve classic checkout order attribution when duplicate input groups exist outside the checkout form.
</file>

<file path="plugins/woocommerce/changelog/fix-order-withdrawal-feature-hooks">
Significance: patch
Type: fix

Register order withdrawal endpoint hooks only when the feature is enabled.
</file>

<file path="plugins/woocommerce/changelog/fix-orders-report-export-customer-name-guard">
Significance: patch
Type: fix

Prevent the Orders Analytics CSV export from logging warnings and writing a lone space when an order has no customer name.
</file>

<file path="plugins/woocommerce/changelog/fix-orders-stats-refund-fixture-hour-boundary">
Significance: patch
Type: dev

Pin the refund fixtures' dates in the Orders Stats report tests, closing the half of the hour-boundary flake that pinning the orders alone left open.
</file>

<file path="plugins/woocommerce/changelog/fix-orders-stats-report-test-hour-boundary">
Significance: patch
Type: dev

Pin date_paid on the Orders Stats report test fixtures so a run that crosses the top of the hour no longer drops orders out of the queried window.
</file>

<file path="plugins/woocommerce/changelog/fix-outofstock-update-since">
Significance: patch
Type: dev

Update term count release version metadata.
</file>

<file path="plugins/woocommerce/changelog/fix-password-protected-products-patterns">
Significance: patch
Type: fix

Correctly hide patterns containing product-related blocks when products are password-protected
</file>

<file path="plugins/woocommerce/changelog/fix-password-reset-preserve-login">
Significance: patch
Type: fix

Preserve the current customer's login after a password reset without logging in a different customer.
</file>

<file path="plugins/woocommerce/changelog/fix-phpcs-relative-sniff-path">
Significance: patch
Type: dev

Resolve custom PHPCS sniff paths relative to the WooCommerce ruleset.
</file>

<file path="plugins/woocommerce/changelog/fix-phpstan-baseline-transient-files">
Significance: patch
Type: dev

Remove two stale PHPStan baseline entries for TransientFilesEngine that no longer match any reported error.
</file>

<file path="plugins/woocommerce/changelog/fix-pos-catalog-response-url">
Significance: patch
Type: fix

Ensure POS catalog download URLs reflect the current site URL.
</file>

<file path="plugins/woocommerce/changelog/fix-price-html-sanitizer-dir-attr">
Significance: patch
Type: fix

Keep the dir and translate attributes wc_price() puts on the currency symbol when Product Elements, Wishlist, and Save for later swap price_html client-side, so RTL-script currency symbols keep honoring the currency position setting after hydration.
</file>

<file path="plugins/woocommerce/changelog/fix-product-category-display-type-normalization">
Significance: patch
Type: fix

Properly sanitize product category display settings before storage.
</file>

<file path="plugins/woocommerce/changelog/fix-product-description-recursion-guard">
Significance: patch
Type: fix

Prevent recursive product description formatting between the Product Description block and Store API product schema.
</file>

<file path="plugins/woocommerce/changelog/fix-product-import-stale-original-id-markers">
Significance: patch
Type: fix

Clear product CSV import mapping markers in the last import batch, so an import abandoned during cleanup cannot make a later import resolve its id: references to the wrong products.
</file>

<file path="plugins/woocommerce/changelog/fix-product-widget-slowdbquery-suppressions">
Significance: patch
Type: dev

Correct PHPCS slow query suppressions for empty product widget query containers.
</file>

<file path="plugins/woocommerce/changelog/fix-protected-product-descriptions">
Significance: patch
Type: fix

Hide product and variation descriptions until the product password is entered.
</file>

<file path="plugins/woocommerce/changelog/fix-receipt-payment-method-non-string">
Significance: patch
Type: fix

Cast the payment method title to string on printed order receipts so a non-string value from the woocommerce_printable_order_receipt_data filter no longer fatals receipt generation.
</file>

<file path="plugins/woocommerce/changelog/fix-recently-viewed-widget-query-cap">
Significance: patch
Type: fix

Limit the Recently Viewed Products widget query to the 15 most recent product IDs from the cookie. This prevents oversized cookies from increasing query workload while preserving normal browsing behavior.
</file>

<file path="plugins/woocommerce/changelog/fix-refund-marker-migration-docblock">
Significance: patch
Type: dev
Comment: Correct the refund marker migration docblock to explain which reports remain affected after a database error.
</file>

<file path="plugins/woocommerce/changelog/fix-refund-returning-customer-clobbered-on-first-order-recalc">
Significance: patch
Type: fix

Keep refund rows' returning_customer NULL when a customer's first order is recalculated, so Analytics > Orders keeps reporting refunds with the refunded order's customer type
</file>

<file path="plugins/woocommerce/changelog/fix-remove-dead-slowdbquery-suppression">
Significance: patch
Type: dev

Remove an unnecessary coding-standard suppression from product review rating counts.
</file>

<file path="plugins/woocommerce/changelog/fix-review-avatar-spacing">
Significance: patch
Type: fix

Remove empty spacing from product reviews when avatars are disabled.
</file>

<file path="plugins/woocommerce/changelog/fix-settings-ui-dataviews-17-compatibility">
Significance: patch
Type: fix

Load the matching DataForm 17.1 stylesheet only for successfully resolved Settings UI pages.
</file>

<file path="plugins/woocommerce/changelog/fix-settings-ui-shell-tab-focus-ring">
Significance: patch
Type: fix

Restore WordPress focus and modal styling, identify current navigation links, and preserve other plugins' navigation warnings in the experimental Settings UI.
</file>

<file path="plugins/woocommerce/changelog/fix-stale-task-redirect-scope">
Significance: patch
Type: fix

Scope the stale task redirect to the Home screen and skip it when task lists have not loaded, so failed fetches or stray task params no longer navigate away.
</file>

<file path="plugins/woocommerce/changelog/fix-store-api-item-data-hidden-type">
Significance: patch
Type: fix

Correct the public TypeScript type for the Store API item_data `hidden` flag, which arrives as a string rather than a boolean.
</file>

<file path="plugins/woocommerce/changelog/fix-store-api-item-schema-extensions">
Significance: patch
Type: fix

Store API: the cart items endpoint now publishes and validates extensions registered against `cart-item`, rather than those registered against `product`. The order items schema, which isn't extendable, no longer advertises `product` extensions it never returned.
</file>

<file path="plugins/woocommerce/changelog/fix-store-api-order-awaiting-payment">
Significance: patch
Type: fix

Ensure Store API checkout carts clear after redirect payments.
</file>

<file path="plugins/woocommerce/changelog/fix-store-api-order-item-data-hidden-meta-id">
Significance: patch
Type: fix

Store API: the order endpoint no longer reports a hidden metadata row's ID on an item_data entry an extension appended. That entry now correctly reports a null `id`.
</file>

<file path="plugins/woocommerce/changelog/fix-store-api-order-item-data-schema">
Significance: minor
Type: fix

Store API: the order endpoint now returns item_data as a list, matching the cart endpoint and its own documented schema. Each entry carries its metadata row ID in a new `id` property, null when an extension added the entry without a stored row.
</file>

<file path="plugins/woocommerce/changelog/fix-store-api-rate-limit-status">
Significance: patch
Type: fix

Return HTTP 429 instead of 400 when Store API requests exceed the rate limit.
</file>

<file path="plugins/woocommerce/changelog/fix-structured-data-falsy-types">
Significance: patch
Type: fix

Fix a fatal error when structured data is requested without a type filter on a store whose markup uses multiple schema types.
</file>

<file path="plugins/woocommerce/changelog/fix-style-attributes-utils-optimizations">
Significance: patch
Type: performance
Comment: Optimize StyleAttributesUtils so unused styles aren't computed
</file>

<file path="plugins/woocommerce/changelog/fix-tests-base-teardown-singleton-cleanup">
Significance: patch
Type: dev

Clear the WC singleton cart, cart context, notice queue, and cached country locale in the base test case teardown, and remove the per-class cleanup that is now redundant.
</file>

<file path="plugins/woocommerce/changelog/fix-timeframe-dates-site-timezone">
Significance: patch
Type: fix

Use the site timezone instead of the server timezone for the default reference date in TimeInterval::get_timeframe_dates(), so remote spec timeframe rules select the correct period near period boundaries.
</file>

<file path="plugins/woocommerce/changelog/fix-toggle-bubble-cleanup">
Significance: patch
Type: dev
Comment: Remove no longer used Activity Panel components
</file>

<file path="plugins/woocommerce/changelog/fix-tracker-unbuildable-snapshot-retries">
Significance: patch
Type: fix

Stop rebuilding a WC Tracker snapshot on every daily run when building it fails.
</file>

<file path="plugins/woocommerce/changelog/fix-update-antom-icon">
Significance: patch
Type: tweak

Update Antom payment gateway icon to use partner-supplied brand logo
</file>

<file path="plugins/woocommerce/changelog/fix-variation-attribute-header-width">
Significance: patch
Type: fix

Allow variation attribute selectors to use available header space and wrap on narrow screens.
</file>

<file path="plugins/woocommerce/changelog/fix-variation-bulk-save-race">
Significance: patch
Type: fix

Prevent bulk variation edits from racing unsaved variation changes.
</file>

<file path="plugins/woocommerce/changelog/fix-variation-password-protection-flag">
Significance: patch
Type: fix

Report inherited password protection correctly for product variations in Store API responses.
</file>

<file path="plugins/woocommerce/changelog/fix-variation-report-order-pluralization">
Significance: patch
Type: fix

Internationalization: use the singular form for the variation report order count.
</file>

<file path="plugins/woocommerce/changelog/fix-variation-selector-custom-attribute-identity">
Significance: patch
Type: fix

Fix Variation Selector attribute rows being unselectable, and colliding with each other, for custom (non-taxonomy) product attributes in the editor.
</file>

<file path="plugins/woocommerce/changelog/fix-variation-selector-placeholder-terms">
Significance: patch
Type: fix

Prevent Variation Selector placeholders from querying the Store API, which could break the editor preview or display unrelated attribute terms.
</file>

<file path="plugins/woocommerce/changelog/fix-verbose-page-rule-detection">
Significance: patch
Type: fix

Keep Shop subpage rewrite rules in sync with the product permalink base.
</file>

<file path="plugins/woocommerce/changelog/fix-wc-get-orders-day-precision-timezone">
Significance: patch
Type: fix

Anchor day-precision date queries on the store's local midnight instead of UTC midnight, so wc_get_orders() and wc_get_products() match the day a merchant means when filtering on date_paid, date_completed, date_on_sale_from and date_on_sale_to. A `start...end` range now covers the whole of its final day, where before it collapsed that day down to a single second, so range queries return one more day of results than they used to.
</file>

<file path="plugins/woocommerce/changelog/fix-wccom-2840-surface-subscriptions-api-errors">
Significance: minor
Type: fix

Surface WooCommerce.com API failures on My Subscriptions instead of rendering an empty subscription list, including the rate-limit message for the whole backoff window after an HTTP 429.
</file>

<file path="plugins/woocommerce/changelog/fix-week-start-setting">
Significance: patch
Type: dev

Spread the actual @wordpress/date module in the import status bar test mock.
</file>

<file path="plugins/woocommerce/changelog/fix-woo6-113-auth-callback-suppressions">
Significance: patch
Type: fix

Reject array values for the wc-auth handshake parameters so they no longer cause a fatal error, and replace legacy WPCS suppression comments in the auth, REST authentication and PayPal IPN handlers with exact PHPCS annotations.
</file>

<file path="plugins/woocommerce/changelog/fix-woo6-114-download-authorization-suppressions">
Significance: patch
Type: fix

Treat product download links whose query arguments arrive as arrays as invalid links instead of letting them raise a PHP error.
</file>

<file path="plugins/woocommerce/changelog/fix-woo6-115-public-interaction-suppressions">
Significance: patch
Type: fix

Product review ratings posted as a fraction below one, such as 0.5, are no longer stored as a rating of 0.
</file>

<file path="plugins/woocommerce/changelog/fix-woo6-116-mixed-request-validation-suppressions">
Significance: patch
Type: fix

Fix a fatal error on the order received page when the order key is passed as an array, and replace legacy WPCS suppression comments in the settings save handler, thanks page, conditional tag helpers and terms template with exact PHPCS annotations.
</file>

<file path="plugins/woocommerce/changelog/fix-woo6-117-extensible-sql-contract-suppressions">
Significance: patch
Type: dev

Replace legacy WPCS suppression comments on extension-facing SQL and order note queries with scoped phpcs:ignore annotations.
</file>

<file path="plugins/woocommerce/changelog/fix-woo6-119-context-specific-output-escaping">
Significance: patch
Type: fix

Escape settings field attributes and currency symbols in legacy report scripts.
</file>

<file path="plugins/woocommerce/changelog/fix-woo6-120-mis-scoped-output-suppressions">
Significance: patch
Type: fix

Escape product titles in the dashboard top-seller report and correct output annotations.
</file>

<file path="plugins/woocommerce/changelog/fix-woo6-121-hook-docs-and-output-suppressions">
Significance: patch
Type: fix

Run the product title in the single product reviews heading through wp_kses_post and replace legacy WPCS output suppressions with documented hooks and exact PHPCS annotations.
</file>

<file path="plugins/woocommerce/changelog/fix-woo6-122-download-read-failure">
Significance: patch
Type: fix

Handle read errors while streaming product downloads.
</file>

<file path="plugins/woocommerce/changelog/fix-woo6-124-widget-html-rendering-suppressions">
Significance: patch
Type: dev

Replace legacy WPCS suppression comments in the widget rendering paths with exact PHPCS annotations, and run the remaining widget form setting labels through wp_kses_post().
</file>

<file path="plugins/woocommerce/changelog/fix-woo6-126-template-markup-suppressions">
Significance: patch
Type: fix

Fix the shipping method label's for attribute so it matches the input ID when a shipping package uses a non-numeric key.
</file>

<file path="plugins/woocommerce/changelog/fix-woo6-146-qr-login-session-handling">
Significance: patch
Type: fix

Update mobile app QR login session handling.
</file>

<file path="plugins/woocommerce/changelog/fix-WOO6-151-exclude-password-protected-product-reviews-from-rest-api">
Significance: patch
Type: fix

Exclude password-protected product reviews from the Store API
</file>

<file path="plugins/woocommerce/changelog/fix-WOO6-159-shared-cached-product-reviews">
Significance: patch
Type: fix
Comment: Prevent password-protected product reviews from showing up to wrong users when they were cached
</file>

<file path="plugins/woocommerce/changelog/fix-wooairr-102-settings-stale-error">
Significance: patch
Type: fix

Fix Analytics settings so a failed save can be retried and no longer reports an error after it succeeds.
</file>

<file path="plugins/woocommerce/changelog/fix-wooairr-128-editor-scoped-subtotal-sync">
Significance: patch
Type: dev
Comment: Same-cycle fix for a #67731 regression, never released.
</file>

<file path="plugins/woocommerce/changelog/fix-wooairr-218-report-export-filename">
Significance: patch
Type: fix

Ignore array values for the analytics report export filename instead of raising a PHP warning.
</file>

<file path="plugins/woocommerce/changelog/fix-wooairr-248-locale-filter-recursion">
Significance: patch
Type: fix

Stop locale filters that read country, state, or continent data from recursing when geographical data is looked up.
</file>

<file path="plugins/woocommerce/changelog/fix-wooairr-273-stale-attribute-readers">
Significance: patch
Type: fix

Keep product responses, admin variation screens and CSV exports working after one of a product's global attributes is deleted.
</file>

<file path="plugins/woocommerce/changelog/fix-WOOAIRR-283-missing-spacing-mini-cart-header-editor">
Significance: patch
Type: fix
Comment: Fix missing spacing between parts in the Mini-Cart header when seen in the editor
</file>

<file path="plugins/woocommerce/changelog/fix-wooairr-31-stale-combined-translations">
Significance: patch
Type: dev
Comment: Same-cycle regression from #67548, never present in a stable release; a Fix entry would describe a bug no 11.1.x upgrader experienced.
</file>

<file path="plugins/woocommerce/changelog/fix-wooairr-48-taxes-report-columns-bc">
Significance: patch
Type: fix

Analytics: restore the released unqualified parent_id form of the Taxes orders_count column carried by the woocommerce_admin_report_columns filter, and invalidate report caches on the first-ever save of the analytics date type.
</file>

<file path="plugins/woocommerce/changelog/fix-wooairr-97-restore-recently-viewed-query-ids">
Significance: patch
Type: fix

Restore the full Recently Viewed Products cookie ID list for widget query filters to preserve extension compatibility.
</file>

<file path="plugins/woocommerce/changelog/fix-wooplug-1113-revenue-tax-refunded-orders">
Significance: patch
Type: fix

Exclude refunds of never-paid or never-completed orders from Revenue analytics filtered by paid or completed date, so manually refunded failed orders no longer produce phantom returns, negative net sales and uncollected tax amounts. Applies to refunds synced after this fix; previously imported rows update on re-sync or historical data re-import.
</file>

<file path="plugins/woocommerce/changelog/fix-wooplug-3391-stale-task-redirect">
Significance: patch
Type: fix

Redirect missing WooCommerce Admin task routes to Home instead of leaving a blank screen.
</file>

<file path="plugins/woocommerce/changelog/fix-wooplug-4518-duplicate-manual-order-customers">
Significance: patch
Type: fix

Prevent duplicate customer entries in Analytics after manually creating guest orders without an email address.
</file>

<file path="plugins/woocommerce/changelog/fix-wooplug-529-refunded-order-count">
Significance: patch
Type: fix

Fix Customers report aggregates and numeric filters for refunds and parented orders.
</file>

<file path="plugins/woocommerce/changelog/fix-wooplug-6420-taxes-report-date-type">
Significance: patch
Type: fix

Analytics: report the Taxes report period by the configured date type (default date paid) so its order counts and tax totals reconcile with the Orders and Revenue reports.
</file>

<file path="plugins/woocommerce/changelog/fix-wooplug-7556-rest-product-query-suppressions">
Significance: patch
Type: dev

Replace legacy WPCS suppression comments on REST product and variation meta queries with explicit phpcs:ignore annotations that record why postmeta remains the correct path.
</file>

<file path="plugins/woocommerce/changelog/fix-wooplug-7557-report-aggregation-queries">
Significance: patch
Type: performance

Count the customer and review report totals with aggregate queries instead of one query per bucket.
</file>

<file path="plugins/woocommerce/changelog/fix-wooplug-7558-original-id-cache">
Significance: patch
Type: performance

Cache CSV importer original-ID lookups within each import batch, so CSVs with repeated IDs or many product references (grouped, upsell, cross-sell) no longer run the same postmeta query for every occurrence.
</file>

<file path="plugins/woocommerce/changelog/fix-wooplug-7559-product-widget-sorting">
Significance: patch
Type: performance

Sort the products widget by sales and the top rated products widget by rating through the product lookup table instead of post meta.
</file>

<file path="plugins/woocommerce/changelog/fix-wooplug-7653-variation-inherited-image">
Significance: patch
Type: fix

Variation gallery: stop persisting the inherited parent image on variation save, prefer variation-owned galleries on the storefront, and clean up previously frozen variation thumbnails.
</file>

<file path="plugins/woocommerce/changelog/fix-wooplug-7659-order-key-array-guards">
Significance: patch
Type: fix

Treat array-valued order keys as invalid on the order pay, cancel and PayPal return paths instead of raising a PHP error.
</file>

<file path="plugins/woocommerce/changelog/fix-wooplug-7691-stock-notifications-rest-settings">
Significance: patch
Type: fix

Expose the Customer Stock Notifications settings through the REST settings API by registering them outside the admin context.
</file>

<file path="plugins/woocommerce/changelog/fix-wooplug-791-separator-numeric-validation">
Significance: patch
Type: fix

Prevent numbers from being saved as the thousand or decimal separator in currency settings.
</file>

<file path="plugins/woocommerce/changelog/fix-wooprd-3593-settings-ui-components">
Significance: patch
Type: fix

Validate Settings UI schemas and script handles before mounting, with a complete classic fallback for server-side failures.
</file>

<file path="plugins/woocommerce/changelog/fix-wooprd-3594-settings-value-boundary">
Significance: patch
Type: fix

Preserve classic setting names, values, and visibility rules while canonicalizing typed Settings UI fields.
</file>

<file path="plugins/woocommerce/changelog/fix-wooprd-3596-settings-ui-save-button">
Significance: patch
Type: fix

Keep the Settings UI Save button disabled when a visibility toggle restores the original values.
</file>

<file path="plugins/woocommerce/changelog/fix-WOOTHME-462-make-mini-cart-header-smaller">
Significance: minor
Type: update

Update Mini-Cart drawer header style to use smaller font size and align it with the close button
</file>

<file path="plugins/woocommerce/changelog/fix-WOOTHME-492-product-quantity-extra-style">
Significance: minor
Type: add

Add support for border and shadow styles to the Product Quantity block and also apply them to the Cart quantity selector
</file>

<file path="plugins/woocommerce/changelog/fix-WOOTHME-504-product-image-border-style">
Significance: minor
Type: add

Add support for border styles to the Product Image block
</file>

<file path="plugins/woocommerce/changelog/fix-yoast-replace-editor-reentry">
Significance: patch
Type: fix

Fix the block email editor loading in a broken state when a plugin (e.g. Yoast SEO Premium) calls WP_Screen::get() from admin_enqueue_scripts, re-entering the replace_editor filter mid-render
</file>

<file path="plugins/woocommerce/changelog/fix-zero-variation-sale-adjustment">
Significance: patch
Type: fix

Preserve variation sale prices when a bulk decrease from regular prices is empty or invalid.
</file>

<file path="plugins/woocommerce/changelog/flush-product-count-cache-on-plugin-activation">
Significance: patch
Type: fix

Flush product count cache on plugin (de)activation so custom product statuses appear immediately.
</file>

<file path="plugins/woocommerce/changelog/move-customers-csv-role-column-to-end">
Significance: patch
Type: tweak
Comment: Amends unreleased #67653 (CSV Role column order); its changelog entry already describes the shipped behavior.
</file>

<file path="plugins/woocommerce/changelog/optimize-template-customization-e2e-rest">
Significance: patch
Type: dev

Speed up block template customization end-to-end tests using REST API setup and cleanup.
</file>

<file path="plugins/woocommerce/changelog/patch-2">
Significance: patch
Type: fix
Comment: Remove unused render_order_downloads_column_headers parameter
</file>

<file path="plugins/woocommerce/changelog/perf-58284-purchasable-variations-candidate-scan">
Significance: patch
Type: performance

Check likely-purchasable variations first in WC_Product_Variable::has_purchasable_variations() so listings and Store API responses stop hydrating every variation of each variable product.
</file>

<file path="plugins/woocommerce/changelog/performance-67913-cap-prices-transient-size">
Significance: patch
Type: performance

Cap variable product prices transient size.
</file>

<file path="plugins/woocommerce/changelog/performance-admin-ajax-inbox-note-cleanup">
Significance: patch
Type: performance

Avoid running Inbox Note cleanup during admin initialization.
</file>

<file path="plugins/woocommerce/changelog/performance-products-reordering-ajax">
Significance: minor
Type: performance

Fixed ordering products performance (N-query pattern).
</file>

<file path="plugins/woocommerce/changelog/performance-scope-product-import-cleanup">
Significance: patch
Type: performance

Avoid site-wide orphan cleanup after product CSV imports.
</file>

<file path="plugins/woocommerce/changelog/performance-tuneup-product-caches-invalidation">
Significance: minor
Type: performance

Tune terms and post meta cache invalidation during product saving.
</file>

<file path="plugins/woocommerce/changelog/pr-37557">
Significance: patch
Type: fix

Corrected the `@since` tag for WC_Coupon::set_status() from 3.0.0 to 6.2.0
</file>

<file path="plugins/woocommerce/changelog/pr-402-users-endpoint-field-permissions">
Significance: patch
Type: fix

Return is_super_admin and woocommerce_meta fields in users REST endpoint only for requests in 'edit' context, and only when requesting own user or with 'list_users' capability.
</file>

<file path="plugins/woocommerce/changelog/pr-64361">
Significance: patch
Type: add

Add woocommerce_order_removed_coupon action hook to WC_Order::remove_coupon() for parity with WC_Cart and the existing woocommerce_order_applied_coupon hook.
</file>

<file path="plugins/woocommerce/changelog/prepare-order-item-deletion-query">
Significance: patch
Type: fix

Prepare order-item deletion queries with an integer placeholder.
</file>

<file path="plugins/woocommerce/changelog/qatar-postcode-not-required">
Significance: patch
Type: fix

Hide the postcode field and make the state optional for Qatar at checkout.
</file>

<file path="plugins/woocommerce/changelog/ralucaStan-saved-for-later-cart-template">
Significance: patch
Type: fix

Saved for Later declares its auto-injection after the Cart block via block.json blockHooks, injects wherever the Cart block is used, stays registered while the feature is off to prevent an unsupported-block notice, and allows only one instance per page
</file>

<file path="plugins/woocommerce/changelog/refactor-bounded-settings-ui-cleanup">
Significance: patch
Type: dev
Comment: Document Settings UI registration replacement and existing save adapter choices.
</file>

<file path="plugins/woocommerce/changelog/refactor-wooplug-656-split-orders-stats-tests">
Significance: patch
Type: dev

Split the legacy Orders Stats report test class into focused test classes under tests/php/src, with no change in coverage
</file>

<file path="plugins/woocommerce/changelog/remove-abandoned-cart-recovery-feature">
Significance: minor
Type: update

Remove the experimental abandoned cart recovery feature.
</file>

<file path="plugins/woocommerce/changelog/remove-agentic-checkout-api">
Significance: minor
Type: dev

Remove the experimental Agentic Checkout API.
</file>

<file path="plugins/woocommerce/changelog/remove-obsolete-block-patterns">
Significance: minor
Type: update

Remove 20 WooCommerce patterns from the pattern library.
</file>

<file path="plugins/woocommerce/changelog/remove-old-blocks-release-testing">
Significance: patch
Type: dev
Comment: Remove archived Blocks release testing documentation and its index links.
</file>

<file path="plugins/woocommerce/changelog/remove-orphaned-reviews-stylesheet">
Significance: patch
Type: dev

Remove an unused Reviews by Product editor stylesheet.
</file>

<file path="plugins/woocommerce/changelog/revert-pr-68036">
Significance: patch
Type: dev
Comment: Revert PR #68036, see WOOAIRR-226
</file>

<file path="plugins/woocommerce/changelog/role-column-last-in-customers-table">
Significance: patch
Type: tweak
Comment: Aligns the browser-side Customers CSV with the server export order from #67843; the Role column feature (#67653) is unreleased so no shipped behavior changes.
</file>

<file path="plugins/woocommerce/changelog/rsm-437-bis-notification-image-overflow">
Significance: patch
Type: fix

Constrain the product image on the stock notification edit screen so it no longer overflows its column and overlaps the Update button.
</file>

<file path="plugins/woocommerce/changelog/rsm-437-bis-playwright-coverage">
Significance: patch
Type: dev

Add Playwright e2e coverage for the Back in Stock Notifications signup, email, and admin management flows.
</file>

<file path="plugins/woocommerce/changelog/test-add-csv-upload-helper-unit-tests">
Significance: patch
Type: dev

Add unit tests for CSVUploadHelper.
</file>

<file path="plugins/woocommerce/changelog/test-rest-api-orders-refunds">
Significance: patch
Type: dev
Comment: Add REST orders and refunds controller tests asserting persisted state, status transitions, search, collection filters and ordering.
</file>

<file path="plugins/woocommerce/changelog/test-rest-api-shipping-reports-webhooks-customers">
Significance: patch
Type: dev
Comment: Add REST shipping, reports, webhooks and customers tests covering lifecycles, default-zone guards and report response contracts against persisted state.
</file>

<file path="plugins/woocommerce/changelog/test-rest-api-taxes">
Significance: patch
Type: dev
Comment: Add REST taxes controller tests covering tax class and tax rate CRUD and batch lifecycles against persisted state.
</file>

<file path="plugins/woocommerce/changelog/test-shop-page-trash-rewrite-guard">
Significance: patch
Type: dev

Cover the trashed-shop-page guard that keeps a rewrite flush from being queued.
</file>

<file path="plugins/woocommerce/changelog/testops-234-add-to-cart-form">
Significance: patch
Type: dev
Comment: Reduce Add to Cart Form E2E tests from 13 to 8; Jest owns the quantity stepper's clamping, change-event dispatch, decimal rounding, and input defaults.
</file>

<file path="plugins/woocommerce/changelog/testops-234-add-to-cart-with-options">
Significance: patch
Type: dev
Comment: Add Jest coverage for the four Add to Cart with Options Interactivity API stores, plus PHPUnit coverage for the legacy form markup and the grouped-product quantity handler. No E2E tests are removed.
</file>

<file path="plugins/woocommerce/changelog/testops-234-blocks-acceptance-fixture-stabilization">
Significance: patch
Type: dev
Comment: Make nine retained Blocks E2E specs own their fixtures: resolve attribute IDs at run time, create their own tax rate and media, and scope the flaky locators and waits.
</file>

<file path="plugins/woocommerce/changelog/testops-234-blocks-seed-convergence">
Significance: patch
Type: dev
Comment: Make the Blocks E2E seed reset the shipping zones, tax classes, and tax settings it depends on, and document switching between the Core and Blocks E2E profiles. Test infrastructure only.
</file>

<file path="plugins/woocommerce/changelog/testops-234-cart-checkout-extensibility">
Significance: patch
Type: dev
Comment: Move 4 extension cart update E2E tests to Jest and PHPUnit, covering the extensionCartUpdate wrapper, the cart thunk, the notice context, and the CartExtensions route; keep one browser title per spec.
</file>

<file path="plugins/woocommerce/changelog/testops-234-cart-checkout-notices">
Significance: patch
Type: dev
Comment: Move 7 Cart and Checkout notice template E2E tests to a new NoticesTest PHPUnit matrix, keeping two block-theme browser titles and one classic-theme browser title.
</file>

<file path="plugins/woocommerce/changelog/testops-234-cart-checkout-shopper-journeys">
Significance: patch
Type: dev
Comment: Consolidate the Cart block shopper E2E journeys and move the discount-label, single-use coupon, and shipping-topology checks to Jest and PHPUnit; replace the wall-clock nonce expiry with one deterministic invalid nonce.
</file>

<file path="plugins/woocommerce/changelog/testops-234-catalog-sorting">
Significance: patch
Type: dev
Comment: Add Jest coverage for the Catalog Sorting block's registration, dynamic save callback and editor placeholder. No E2E test is removed.
</file>

<file path="plugins/woocommerce/changelog/testops-234-checkout-block-fields">
Significance: patch
Type: dev
Comment: Reduce additional checkout field E2E tests from 12 to 7; a new CheckoutFieldsAdminTest owns the order admin field formatting and update contract.
</file>

<file path="plugins/woocommerce/changelog/testops-234-checkout-block-shopper">
Significance: patch
Type: dev
Comment: Reduce Checkout block shopper E2E tests from 13 to 5; a Jest suite and a Checkout block PHPUnit test own the shipping-topology guard.
</file>

<file path="plugins/woocommerce/changelog/testops-234-classic-style-loading-cache">
Significance: patch
Type: dev

Move the classic-theme block style decision cache from a function-local static to a BlockTypesController instance property so it can be isolated in PHP tests.
</file>

<file path="plugins/woocommerce/changelog/testops-234-customer-account-block">
Significance: patch
Type: dev
Comment: Add Jest coverage for the Customer Account block's sidebar settings and PHPUnit coverage for the accessible name its link exposes, which nothing covered before.
</file>

<file path="plugins/woocommerce/changelog/testops-234-delete-redundant-blocks-e2e-tests">
Significance: patch
Type: dev
Comment: Remove 7 redundant blocks E2E tests already covered by PHPUnit and Jest unit tests.
</file>

<file path="plugins/woocommerce/changelog/testops-234-on-sale-badge">
Significance: patch
Type: dev
Comment: Reduce On-Sale Badge E2E tests from 6 to 1; PHPUnit owns the sale check and the alignment classes.
</file>

<file path="plugins/woocommerce/changelog/testops-234-order-confirmation-blocks">
Significance: patch
Type: dev
Comment: Move order confirmation policy from 6 E2E tests to PHPUnit; the Order Confirmation block spec keeps 3 browser titles.
</file>

<file path="plugins/woocommerce/changelog/testops-234-patterns-editor">
Significance: patch
Type: dev
Comment: Reduce pattern editor E2E tests from 4 to 1; the synced block theme pattern title stays as the pattern editor canary.
</file>

<file path="plugins/woocommerce/changelog/testops-234-product-button">
Significance: patch
Type: dev
Comment: Reduce Product Button E2E tests from 7 to 3; PHPUnit owns the add-to-cart text filter and the block theme script dequeue.
</file>

<file path="plugins/woocommerce/changelog/testops-234-product-collection-compatibility">
Significance: patch
Type: dev
Comment: Move 9 collection compatibility hook checks to PHPUnit; the spec keeps two rendered-order browser titles.
</file>

<file path="plugins/woocommerce/changelog/testops-234-product-collection-frontend">
Significance: patch
Type: dev
Comment: Reduce Product Collection frontend E2E tests from 37 to 20; PHPUnit owns the renderer's state and route parity, Jest owns the editor contracts and the product template's request, and one new browser title keeps the empty-collection and No Results render.
</file>

<file path="plugins/woocommerce/changelog/testops-234-product-collection-registration">
Significance: patch
Type: dev
Comment: Add Jest coverage for __experimentalRegisterProductCollection, covering falsy-value preservation, invalid-input rejection, prop-injection scoping and reference-context routing. No E2E test is removed.
</file>

<file path="plugins/woocommerce/changelog/testops-234-product-filters-block">
Significance: patch
Type: dev
Comment: Reduce Product Filters E2E tests from 9 to 3; PHPUnit owns the attribute filter's options and counts, and Jest owns the store's attribute toggle.
</file>

<file path="plugins/woocommerce/changelog/testops-234-product-gallery">
Significance: patch
Type: dev
Comment: Reduce Product Gallery E2E tests from 12 to 8; Jest owns the block's registered defaults and its Single Product ancestry.
</file>

<file path="plugins/woocommerce/changelog/testops-234-product-results-count">
Significance: patch
Type: dev
Comment: Add Jest coverage for the Product Results Count block's registration and PHPUnit coverage for its rendered result count. No E2E test is removed.
</file>

<file path="plugins/woocommerce/changelog/testops-234-refresh-block-manifest-copies">
Significance: patch
Type: dev
Comment: Refresh generated block.json copies deterministically so PHP test metadata matches the source manifests.
</file>

<file path="plugins/woocommerce/changelog/testops-234-remove-duplicate-register-product-collection-tests">
Significance: patch
Type: dev
Comment: Remove 16 duplicated Product Collection registration E2E tests.
</file>

<file path="plugins/woocommerce/changelog/testops-234-remove-role-smoke-duplicate">
Significance: patch
Type: dev
Comment: Remove the duplicate Blocks role smoke E2E spec. The admin, customer, and guest sessions it loaded are already exercised by the retained Blocks editor, My Account, and storefront journeys.
</file>

<file path="plugins/woocommerce/changelog/testops-234-single-product-server-render">
Significance: patch
Type: dev
Comment: Move 4 Single Product page E2E tests to PHPUnit; SingleProductTemplateTests owns the body classes and ProductRatingTest owns the review visibility.
</file>

<file path="plugins/woocommerce/changelog/testops-234-unregister-block-types">
Significance: patch
Type: dev
Comment: Extend the unregister-block-types unrestricted-context test to cover Catalog Sorting and Product Results Count.
</file>

<file path="plugins/woocommerce/changelog/testops-288-block-email-rendering-source">
Significance: patch
Type: dev
Comment: Trim block email rendering-source coverage to one browser journey; two rules move to their PHPUnit owners.
</file>

<file path="plugins/woocommerce/changelog/testops-288-checkout-link">
Significance: patch
Type: dev
Comment: Reduce Checkout Link E2E tests from 5 to 3 and rewrite CheckoutLinkTest from 2 methods to 9; PHPUnit owns the invalid coupon, invalid product and malformed list cases, and a new browser test covers the logged-in redirect.
</file>

<file path="plugins/woocommerce/changelog/testops-288-checkout-shortcode-flows">
Significance: patch
Type: dev
Comment: Make checkout payment-method selectors exact in two retained E2E specs.
</file>

<file path="plugins/woocommerce/changelog/testops-288-colour-picker">
Significance: patch
Type: dev
Comment: Strengthen the colour picker swatch E2E test to pin the painted box in both the pre-WP 7.0 and WP 7.0 states, so the box-sizing half of the compatibility rule is covered.
</file>

<file path="plugins/woocommerce/changelog/testops-288-customer-payment-page">
Significance: patch
Type: dev
Comment: Make the customer payment page's payment-method selector exact.
</file>

<file path="plugins/woocommerce/changelog/testops-288-email-editor-loads">
Significance: patch
Type: dev
Comment: Move the email editor feature flag, preview send and REST failure coverage below E2E; the browser spec goes from six titles to five.
</file>

<file path="plugins/woocommerce/changelog/testops-288-linked-products">
Significance: patch
Type: dev
Comment: Cut the linked products E2E spec from 4 titles to 2; clearing up-sells and cross-sells now covered by WC_Meta_Box_Product_Data_Linked_Products_Test.
</file>

<file path="plugins/woocommerce/changelog/testops-288-orders-admin">
Significance: patch
Type: dev
Comment: Move order admin coverage below E2E; twenty-two browser titles become fifteen.
</file>

<file path="plugins/woocommerce/changelog/testops-288-paypal-standard">
Significance: patch
Type: dev
Comment: Isolate the PayPal Standard E2E fixture's settings per test and reload the settings page after onboarding, so both retained browser titles pass from any starting state; no coverage moves between layers.
</file>

<file path="plugins/woocommerce/changelog/testops-288-post-comments-fixture">
Significance: patch
Type: dev
Comment: The WordPress post comments E2E spec now creates and deletes its own post instead of relying on the default Hello world post, which no longer exists in the shared E2E environment.
</file>

<file path="plugins/woocommerce/changelog/testops-288-product-images">
Significance: patch
Type: dev
Comment: Cut the product images E2E spec from 6 titles to 3; image and gallery persistence and rendering now covered by WC_Meta_Box_Product_Images_Test.
</file>

<file path="plugins/woocommerce/changelog/testops-288-products-admin-export">
Significance: patch
Type: dev
Comment: Cut the product export E2E spec from 4 titles to 1; the export screen's rendering and the exporter's row scoping now covered by WC_Admin_Product_Export_View_Test and WC_Product_CSV_Exporter_Test.
</file>

<file path="plugins/woocommerce/changelog/update-action-scheduler-via-automation">
Significance: minor
Type: update

Update the Action Scheduler package to version 4.1.0.
</file>

<file path="plugins/woocommerce/changelog/update-catalog-sorting-content-width">
Significance: patch
Type: tweak

Size the Catalog Sorting block to the selected option.
</file>

<file path="plugins/woocommerce/changelog/update-extract-dual-api-to-plugin">
Significance: minor
Type: update

Move the experimental dual API engine out of WooCommerce core into the WooCommerce Dual API plugin.
</file>

<file path="plugins/woocommerce/changelog/update-mini-cart-default-labels">
Significance: patch
Type: update

Update the default Mini-Cart labels.
</file>

<file path="plugins/woocommerce/changelog/update-patterns-category-name">
Significance: patch
Type: update

Rename patterns category from WooCommerce to Shop
</file>

<file path="plugins/woocommerce/changelog/update-php-dev-dependency-security-patches">
Significance: patch
Type: dev

Update PHP development dependencies to versions that resolve reported security advisories.
</file>

<file path="plugins/woocommerce/changelog/update-plugin-directory-screenshots">
Significance: patch
Type: update

Update the plugin directory product screenshots with the correct heading design.
</file>

<file path="plugins/woocommerce/changelog/update-react-number-format-5">
Significance: minor
Type: update

Update react-number-format from 4.9.3 to 5.4.5.
</file>

<file path="plugins/woocommerce/changelog/update-SingleProductTemplateTests-utils">
Significance: patch
Type: dev
Comment: Create strip_whitespace and strip_whitespace_and_password_form_ids utils for SingleProductTemplateTests to avoid repeating the same logic in every test
</file>

<file path="plugins/woocommerce/changelog/update-vendored-graphql-php-security">
Significance: patch
Type: update

Update the vendored webonyx/graphql-php to 15.32.3 to limit parser recursion and field comparisons.
</file>

<file path="plugins/woocommerce/changelog/wc-36802-assigned-issue">
Significance: minor
Type: enhancement

Add a variation bulk action to set sale prices from regular prices.
</file>

<file path="plugins/woocommerce/changelog/wc-67498-front-page-filters-design">
Significance: patch
Type: fix

Fix Product Filters on a Shop page set as the static front page.
</file>

<file path="plugins/woocommerce/changelog/wc-product-filter-inline-style-enqueue">
Significance: patch
Type: fix
Comment: Fix Product Filter responsive styles in unified editor assets.
</file>

<file path="plugins/woocommerce/changelog/wccom-2879-forced-autoupdate-passthrough">
Significance: minor
Type: add

Honor the WooCommerce.com `autoupdate` flag on plugin and theme updates, so a critical extension release can be installed automatically when the package is installable. Theme update items now also report their PHP requirement, so an automatic update is skipped on an incompatible PHP version.
</file>

<file path="plugins/woocommerce/changelog/wccom-2879-update-check-installed-version">
Significance: minor
Type: update

Send the installed version of each WooCommerce.com extension in the update-check request.
</file>

<file path="plugins/woocommerce/changelog/wccom-2882-marketplace-tab-focus-ring">
Significance: patch
Type: fix

Remove the stray blue box drawn around the selected Marketplace tab on WordPress 7.1.
</file>

<file path="plugins/woocommerce/changelog/wccom-2892-quality-badge-compact-card-placement">
Significance: patch
Type: update

Move the quality badge above the price on in-app marketplace cards (between the name and the price on compact cards), centre compact card content vertically, and pin the price row to the bottom of regular cards.
</file>

<file path="plugins/woocommerce/changelog/woo6-108-resolve-high-npm-alerts">
Significance: patch
Type: dev

Update npm dependencies that resolve high-severity security advisories.
</file>

<file path="plugins/woocommerce/changelog/woo6-109-npm-security-tooling">
Significance: patch
Type: dev
Comment: Remove deprecated Request dependencies, upgrade release tooling, and refresh compatible npm dependencies to close critical and high security alerts.
</file>

<file path="plugins/woocommerce/changelog/woo6-109-storybook-10">
Significance: patch
Type: dev
Comment: Upgrade Storybook development tooling to version 10.
</file>

<file path="plugins/woocommerce/changelog/wooa7s-1541-customer-filter-tag-label">
Significance: patch
Type: fix

Analytics: label a customer filter tag with the username or email when the customer is registered without a name. Affects the Downloads and Customers reports.
</file>

<file path="plugins/woocommerce/changelog/wooa7s-1541-downloads-customer-filter">
Significance: minor
Type: update

Analytics: search the Downloads report's advanced filter by customer name, username or email instead of username only.
</file>

<file path="plugins/woocommerce/changelog/wooa7s-1857-repeatable-report-downloads">
Significance: patch
Type: fix

Keep emailed Analytics report exports downloadable for a week instead of deleting them on the first request.
</file>

<file path="plugins/woocommerce/changelog/wooairr-126-product-filters-block-gap-guard">
Significance: patch
Type: fix

Prevent invalid Product Filters block spacing values from being rendered.
</file>

<file path="plugins/woocommerce/changelog/wooairr-278-rest-endpoint-slug-sanitize-test">
Significance: patch
Type: dev

Add a regression test covering that the stock notifications My Account endpoint slug is sanitized when saved through the REST settings API.
</file>

<file path="plugins/woocommerce/changelog/WOOMKT-825-846-849">
Significance: patch
Type: fix

Three small Marketplace fixes: the clear button in the search field only shows when there is text to clear and resets the results, search results get a "Results for" heading, and the WooCommerce.com account menu link reads "Your WooCommerce.com account" and points at My account.
</file>

<file path="plugins/woocommerce/changelog/WOOMKT-848-850-859">
Significance: patch
Type: tweak

Three small Marketplace UI fixes: the Plugins > Add Plugin "WooCommerce Marketplace" tab lands on Discover, the Extensions page title matches other admin page titles, and compact product cards show the "Sponsored" label.
</file>

<file path="plugins/woocommerce/changelog/WOOMKT-851">
Significance: patch
Type: enhancement

Add a dismiss button and an inline disconnect link to the connected account banner on the marketplace's My Subscriptions tab.
</file>

<file path="plugins/woocommerce/changelog/wooplug-1772-per-order-guest-names">
Significance: patch
Type: fix

Show each guest order's billing name in Analytics when orders share an email address.
</file>

<file path="plugins/woocommerce/changelog/wooplug-2191-post-action-webhook-validation">
Significance: patch
Type: fix

Validate post-action webhooks using the affected post ID instead of request-global post type state.
</file>

<file path="plugins/woocommerce/changelog/wooplug-4996-stock-notifications-signup-rate-limiter">
Significance: minor
Type: enhancement

Rate limit stock notification sign-ups per client and e-mail address.
</file>

<file path="plugins/woocommerce/changelog/wooplug-59489-coupon-error-event">
Significance: minor
Type: add

Add errored_coupon and errored_coupon_in_checkout JS events fired when a coupon fails to apply on the classic cart and checkout pages.
</file>

<file path="plugins/woocommerce/changelog/wooplug-6456-add-date-field-type">
Significance: minor
Type: add

Add support for the `date` field type in the additional checkout fields API.
</file>

<file path="plugins/woocommerce/changelog/wooplug-6456-checkout-field-types">
Significance: patch
Type: dev

Move additional checkout field type behavior into per-type classes, and field value storage into a trait, with no change in behavior.
</file>

<file path="plugins/woocommerce/changelog/wooplug-6456-date-field-min-max">
Significance: minor
Type: add

Add `min` and `max` options to `date` additional checkout fields, accepting an absolute date or an ISO 8601-2 duration relative to today such as `P1D` or `-P18Y`.
</file>

<file path="plugins/woocommerce/changelog/wooplug-7407-non-sticky-admin-header">
Significance: patch
Type: fix

Make the WooCommerce Admin header non-sticky on all pages.
</file>

<file path="plugins/woocommerce/changelog/wooplug-7407-white-classic-editor-tools">
Significance: patch
Type: fix

Prevent product editor content from showing through the sticky editor tools.
</file>

<file path="plugins/woocommerce/changelog/wooplug-7525-track-product-sorting-usage">
Significance: patch
Type: add

Add tracking for product sorting views and manual reordering.
</file>

<file path="plugins/woocommerce/changelog/wooplug-7542-match-global-unique-id">
Significance: minor
Type: add

Use GTIN, UPC, EAN, or ISBN as the match key for existing product and variation CSV updates when ID and SKU are absent, and let a variation row identified only by one create a new variation.
</file>

<file path="plugins/woocommerce/changelog/wooplug-7554-add-tooling-catalog">
Significance: patch
Type: dev

Use the tooling catalog for shared Babel, PostCSS, and webpack versions.
</file>

<file path="plugins/woocommerce/changelog/wooplug-7656-configurable-endpoint-slug">
Significance: minor
Type: add

Add a Stock notifications setting under Settings > Advanced > Account endpoints, so the My Account endpoint slug can be renamed or cleared to turn the page off.
</file>

<file path="plugins/woocommerce/changelog/wooplug-7663-bis-normalize-customer-emails">
Significance: patch
Type: fix

Normalize customer emails in Back in Stock Notifications so signups and lookups match regardless of letter case, rewrite existing rows in the same form, and fix lookups for emails containing a single quote.
</file>

<file path="plugins/woocommerce/changelog/wooplug-7667-bis-my-account-template-no-internals">
Significance: patch
Type: dev
Comment: Prepare the My Account stock notifications template data in MyAccountView instead of calling MyAccountEndpoint from the template. The feature is unreleased, so there is no user-facing change.
</file>

<file path="plugins/woocommerce/changelog/wooplug-7704-stock-notifications-tests-off-by-default">
Significance: patch
Type: dev
Comment: Stop force-enabling the Back In Stock Notifications feature for the whole PHPUnit suite; affected tests now enable it themselves (no runtime change).
</file>

<file path="plugins/woocommerce/changelog/wooprd-3662-remove-activity-panel">
Significance: patch
Type: update

Remove the Activity panel from WooCommerce pages while keeping the Inbox on Woo Home.
</file>

<file path="plugins/woocommerce/changelog/wpcs-replacement">
Significance: patch
Type: dev

Replace legacy WPCS suppression comments with PHPCS directives.
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/activity-card/index.js">
const isDateString = ( value )
⋮----
class ActivityCard extends Component
⋮----
getCard()
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/activity-card/placeholder.js">
class ActivityCardPlaceholder extends Component
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/activity-card/README.md">
ActivityCard
============

A card designed for use in the activity panel. This is a very structured component, which expects at minimum a label and content. It can optionally also include a date, actions, an image, and a dropdown menu.

## How to use:

```jsx
import { ActivityCard } from 'components/activity-card';

render: function() {
  return (
    <ActivityCard
      title="Insight"
      icon={ <Gridicon icon="search" /> }
      date="2018-07-10T00:00:00Z"
      actions={ [ <a href="/">Action link</a>, <a href="/">Action link 2</a> ] }
    >
      Insight content goes in this area here. It will probably be a couple of lines long and may
      include an accompanying image. We might consider color-coding the icon for quicker
      scanning.
    </ActivityCard>
  );
}
```

## Props

* `title`: A title for this card (required).
* `subtitle`: An element rendered right under the title.
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/activity-header/index.js">
class ActivityHeader extends Component
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/activity-header/README.md">
ActivityHeader
============

A component designed for use in the activity panel. It returns a title and can optionally also include a component like dropdown or Ellipsis menu.

## How to use:

```jsx
import ActivityHeader from 'layout/activity-panel/activity-header';

render: function() {
  return (
    <ActivityHeader
      title="Reviews"
    />
  );
}
```

## Props

* `title`: A title for this card (required).
* `className`: Additional class names.
* `menu`: A dropdown menu (EllipsisMenu) shown at the top-right of the card.
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/display-options/icons/display.js">
export const DisplayIcon = () => (
	<svg
		width="18"
		height="18"
		viewBox="0 0 24 24"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<g id="block-template-part-sidebar">
			<path
				id="Shape"
				fillRule="evenodd"
				clipRule="evenodd"
				d="M6 4H18C19.1046 4 20 4.89543 20 6V18C20 19.1046 19.1046 20 18 20H6C4.89543 20 4 19.1046 4 18V6C4 4.89543 4.89543 4 6 4ZM18 5.5H6C5.72386 5.5 5.5 5.72386 5.5 6V9H18.5V6C18.5 5.72386 18.2761 5.5 18 5.5ZM18.5 10.5H10L10 18.5H18C18.2761 18.5 18.5 18.2761 18.5 18V10.5Z"
				fill="#1E1E1E"
			/>
		</g>
	</svg>
);
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/display-options/icons/single-column.js">
export const SingleColumnIcon = () => (
	<svg
		className="woocommerce-layout__activity-panel-tab-icon"
		width="12"
		height="14"
		viewBox="0 0 12 14"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<rect x="0.5" y="0.5" width="11" height="13" strokeWidth="1" />
	</svg>
);
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/display-options/icons/two-columns.js">
export const TwoColumnsIcon = () => (
	<svg
		className="woocommerce-layout__activity-panel-tab-icon"
		width="18"
		height="14"
		viewBox="0 0 18 14"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<rect x="0.5" y="0.5" width="7" height="13" strokeWidth="1" />
		<rect x="9.5" y="0.5" width="7" height="13" strokeWidth="1" />
	</svg>
);
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/display-options/index.js">
export const DisplayOptions = () =>
⋮----
onClick: ()
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/highlight-tooltip/index.js">
function HighlightTooltip( {
	title,
	closeButtonText,
	content,
	show = true,
	id,
	onClose,
	delay,
	onShow = noop,
	useAnchor = false,
	shouldCloseOnClickOutside = true,
} )
⋮----
const showTooltip = ( container ) =>
⋮----
const triggerShowTooltip = ( container ) =>
⋮----
const triggerClose = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/panels/setup-tasks/setup-tasks-panel.tsx">
import { TaskLists } from '~/task-lists';
⋮----
type QueryTypeProps = {
	query: {
		task?: string;
	};
};
⋮----
export const SetupTasksPanel = (
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/panels/help.js">
function getHomeItems()
⋮----
function getAppearanceItems()
⋮----
function getMarketingItems( props )
⋮----
function getPaymentGatewaySuggestions( props )
⋮----
function getProductsItems()
⋮----
function getShippingItems(
⋮----
function getTaxItems( props )
⋮----
function getItems( props )
⋮----
function handleOnItemClick( props, event )
⋮----
function getListItems( props )
⋮----
export const HelpPanel = ( {
	taskName,
	recordEvent = fallbackRecordEvent,
	...props
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/tab/index.js">
export const Tab = ( {
	icon,
	title,
	name,
	selected,
	isPanelOpen,
	onTabClick,
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/tabs/index.js">
export const Tabs = ( {
	tabs,
	onTabClick,
	selectedTab: selectedTabName,
	tabOpen = false,
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/activity-panel.js">
export const ActivityPanel = (
⋮----
const closePanel = () =>
⋮----
const clearPanel = () =>
⋮----
const togglePanel = ( tab ) =>
⋮----
// Record a Tracks event when a panel is being opened or switched in
// (not when closing). Previously the Tabs child fired this — moved
// here so it stays consistent with the rest of the intent logic.
⋮----
const isProductScreen = () =>
⋮----
const isAddProductPage = () =>
⋮----
const isPerformingSetupTask = () =>
⋮----
const getTabs = () =>
⋮----
onClick: () =>
⋮----
onRecordScore: () =>
onCloseModal: () =>
⋮----
const getPanelContent = ( tab ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/index.js">
const ActivityPanelHeaderItem = () => (
	<WooHeaderItem order={ 20 }>
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/panel.js">
export const Panel = ( {
	content,
	isPanelOpen,
	isPanelSwitching,
	currentTab,
	tab,
	closePanel,
	clearPanel,
} ) =>
⋮----
const handleFocusOutside = ( event ) =>
⋮----
const possibleFocusPanel = () =>
⋮----
const finishTransition = ( e ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/activity-panel/README.md">
# Activity Panel

This component contains the Activity Panel. This is shown on every page and is rendered as part of the header.
It provides access to the notices system and actionable items like stock.

## Components

### ActivityCard

See activity-card/README.md
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/import-status-bar/import-status-bar.tsx">
import { __ } from '@wordpress/i18n';
import { dateI18n } from '@wordpress/date';
import { Button, Spinner } from '@wordpress/components';
import { useDispatch } from '@wordpress/data';
import { useSettings } from '@woocommerce/data';
⋮----
import { useImportStatus } from './use-import-status';
⋮----
const formatStatusDate = ( date: string | null ): string =>
⋮----
const handleTriggerImport = async (): Promise< void > =>
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/import-status-bar/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/import-status-bar/types.ts">
export interface ImportStatus {
	mode: 'scheduled' | 'immediate';
	last_processed_date: string | null;
	next_scheduled: string | null;
	import_in_progress_or_due: boolean | null;
}
⋮----
export interface UseImportStatusReturn {
	status: ImportStatus | null;
	isLoading: boolean;
	error: string | null;
	triggerImport: () => Promise< void >;
	isTriggeringImport: boolean;
}
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/import-status-bar/use-import-status.ts">
import { useState, useEffect, useCallback, useRef } from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';
import { __ } from '@wordpress/i18n';
⋮----
import type { ImportStatus, UseImportStatusReturn } from './types';
⋮----
export function useImportStatus(): UseImportStatusReturn
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/leaderboard/data/top-selling-products-mock-data.js">

</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/leaderboard/index.js">
export class Leaderboard extends Component
⋮----
getFormattedHeaders()
⋮----
getFormattedRows()
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/report-chart/index.js">
export class ReportChart extends Component
⋮----
shouldComponentUpdate( nextProps )
⋮----
getItemChartData()
⋮----
getTimeChartData()
⋮----
getTimeChartTotals()
⋮----
renderChart( mode, isRequesting, chartData, legendTotals )
⋮----
renderItemComparison()
⋮----
renderTimeComparison()
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/report-chart/utils.js">
export function getSelectedFilter( filters, query, selectedFilterArgs =
⋮----
export function getChartMode( selectedFilter, query )
⋮----
export function createDateFormatter( format )
⋮----
export function dataContainsLeapYear( data )
⋮----
export function buildChartData(
	primaryData,
	secondaryData,
	primaryDatePicker,
	secondaryDatePicker,
	comparison,
	selectedChartKey,
	currentInterval
)
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/report-filters/index.js">
class ReportFilters extends Component
⋮----
onDateSelect( data )
⋮----
onFilterSelect( data )
⋮----
onAdvancedFilterAction( action, data )
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/report-header/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/report-header/report-header.tsx">
import type { AdvancedFilterConfig } from '@woocommerce/components';
⋮----
import { ImportStatusBar } from '../import-status-bar';
import ReportFilters from '../report-filters';
⋮----
interface ReportHeaderProps {
	advancedFilters?: AdvancedFilterConfig;
	filters?: Array< unknown >;
	path: string;
	query: object;
	showDatePicker?: boolean;
	report: string;
}
⋮----
export default function ReportHeader( props: ReportHeaderProps ): JSX.Element
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/report-summary/index.js">
export class ReportSummary extends Component
⋮----
formatVal( val, type )
⋮----
getValues( key, type )
⋮----
render()
⋮----
const renderSummaryNumbers = (
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/report-table/download-icon.js">

</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/report-table/index.js">
const ReportTable = ( props ) =>
⋮----
const onPageChange = ( newPage, source ) =>
⋮----
const trackTableSearch = () =>
⋮----
const onSort = ( key, direction ) =>
⋮----
const filterShownHeaders = ( headers, hiddenKeys ) =>
⋮----
const applyTableFilters = ( data, totals, totalResults ) =>
⋮----
const onClickDownload = () =>
⋮----
const onCompare = () =>
⋮----
const onSearchChange = ( values ) =>
⋮----
const selectAllRows = ( checked ) =>
⋮----
const selectRow = ( i, checked ) =>
⋮----
const getCheckbox = ( i ) =>
⋮----
const getAllCheckbox = () =>
⋮----
const onColumnsChange = ( shownColumns, toggledColumn ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/report-table/utils.js">
function collectFilterParamKeys( configs, keys )
⋮----
function getFilterParamKeys( filters = [] )
⋮----
export function getExportQuery(
	reportQuery = {},
	urlQuery = {},
	filters = [],
	advancedFilters = {}
)
⋮----
export function extendTableData(
	extendedStoreSelector,
	props,
	queriedTableData
)
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/scheduled-updates-promotion-notice/index.tsx">
import { getAdminLink } from '@woocommerce/settings';
import { __ } from '@wordpress/i18n';
import { useSettings, useUserPreferences } from '@woocommerce/data';
import { createInterpolateElement } from '@wordpress/element';
import { Button } from '@wordpress/components';
import { recordEvent } from '@woocommerce/tracks';
⋮----
const onDismiss = () =>
⋮----
href=
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/analytics/components/utils.js">
export function hasEmptySearchResults( query, limitBy )
⋮----
export function getEmptyMessage( query, limitBy )
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/historical-data/actions.js">
function HistoricalDataActions( {
	clearStatusAndTotalsCache,
	createNotice,
	dateFormat,
	importDate,
	onImportStarted,
	selectedPeriod,
	stopImport,
	skipChecked,
	status,
	setImportStarted,
	updateImportation,
} )
⋮----
const makeQuery = ( path, errorMessage, importStarted = false ) =>
⋮----
const onStartImport = () =>
⋮----
const onStopImport = () =>
⋮----
const deletePreviousData = () =>
const reimportData = () =>
const getActions = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/historical-data/failed-orders-notice.tsx">
import { __, _n, sprintf } from '@wordpress/i18n';
import {
	createInterpolateElement,
	useCallback,
	useEffect,
	useState,
} from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';
import { Button, Notice } from '@wordpress/components';
import { useDispatch } from '@wordpress/data';
import { getAdminLink } from '@woocommerce/settings';
⋮----
interface FailedImportsStatus {
	failed_count: number;
	failed_overflow_count: number;
}
⋮----
interface RetryFailedResponse {
	success: boolean;
	message: string;
	retried_count: number;
	pruned_count: number;
	already_scheduled_count: number;
	error_count: number;
}
⋮----
function getErrorMessage( err: unknown, fallback: string ): string
⋮----
/**
 * Shows a warning when some orders failed to import into analytics, with a
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/historical-data/index.js">
class HistoricalData extends Component
⋮----
startStatusCheckInterval()
⋮----
cancelStatusCheckInterval()
⋮----
clearCache( resolver, query )
⋮----
stopImport()
⋮----
onImportFinished()
⋮----
onImportStarted()
⋮----
clearStatusAndTotalsCache()
⋮----
isImportationInProgress()
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/historical-data/layout.js">
class HistoricalDataLayout extends Component
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/historical-data/period-selector.js">
function HistoricalDataPeriodSelector( {
	dateFormat,
	disabled,
	setImportPeriod,
	value,
} )
⋮----
const onSelectChange = ( val ) =>
const onDatePickerChange = ( val ) =>
⋮----
const getDatePickerError = ( momentDate ) =>
const getDatePicker = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/historical-data/progress.js">
function HistoricalDataProgress(
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/historical-data/skip-checkbox.js">
function HistoricalDataSkipCheckbox(
⋮----
const skipChange = ( value ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/historical-data/status.js">
function HistoricalDataStatus(
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/historical-data/utils.js">
export const formatParams = ( dateFormat, period, skipChecked ) =>
⋮----
export const getStatus = ( {
	cacheNeedsClearing,
	customersProgress,
	customersTotal,
	isError,
	inProgress,
	ordersProgress,
	ordersTotal,
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/config.js">

</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/default-date.js">
const DefaultDate = (
⋮----
const change = ( query ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/import-mode-confirmation-modal.tsx">
import {
	Button,
	Modal,
	Flex,
	__experimentalText as Text,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
interface ImportModeConfirmationModalProps {
	isOpen: boolean;
	onClose: () => void;
	onConfirm: () => void;
}
⋮----
title=
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/index.js">
const Settings = (
⋮----
function warnIfUnsavedChanges( event )
⋮----
const resetDefaults = () =>
⋮----
const saveChanges = () =>
⋮----
const handleInputChange = ( e ) =>
⋮----
const handleImportModeConfirm = () =>
⋮----
const handleImportModeCancel = () =>
⋮----
const getSettingValue = ( setting ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/README.md">
Settings
=======

The settings used to modify the way data is retrieved or displayed in WooCommerce reports.

## Extending Settings

Settings can be added, removed, or modified outside oc `wc-admin` by hooking into `woocommerce_admin_analytics_settings`.  For example:

```js
addFilter( 'woocommerce_admin_analytics_settings', 'wc-example/my-setting', settings => {
	return [
		...settings,
		{
            name: 'custom_setting',
            label: __( 'Custom setting:', 'woocommerce' ),
            inputType: 'text',
            helpText: __( 'Help text to describe what the setting does.' ),
            defaultValue: 'Default value',
		},
	];
} );
```

Each settings has the following properties:

- `name` (string): The slug of the setting to be updated.
- `label` (string): The label used to describe and displayed next to the setting.
- `inputType` (enum: text|checkbox|checkboxGroup): The type of input to use.
- `helpText` (string): Text displayed beneath the setting.
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/analytics/settings/setting.js">
class Setting extends Component
⋮----
renderCheckboxOptions( options )
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/blueprint/components/BlueprintUploadDropzone.tsx">
import {
	DropZone,
	FormFileUpload,
	Notice,
	Spinner,
	Button,
	Icon,
} from '@wordpress/components';
import { closeSmall, upload, check, cautionFilled } from '@wordpress/icons';
import { __, sprintf } from '@wordpress/i18n';
import { useMachine } from '@xstate5/react';
import {
	assertEvent,
	assign,
	enqueueActions,
	fromPromise,
	setup,
} from 'xstate5';
import apiFetch from '@wordpress/api-fetch';
import { dispatch } from '@wordpress/data';
import { recordEvent } from '@woocommerce/tracks';
import { createInterpolateElement } from '@wordpress/element';
import { getAdminLink } from '@woocommerce/settings';
⋮----
import { OverwriteConfirmationModal } from '../settings/overwrite-confirmation-modal';
import { getOptionGroupsFromSteps } from './get-option-groups';
import { getStepActions } from './get-step-actions';
import {
	BlueprintQueueResponse,
	BlueprintImportResponse,
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/blueprint/components/get-option-groups.ts">
import { BlueprintStep } from './types';
⋮----
export const getOptionGroups = ( options: string[] ) =>
⋮----
export const getOptionGroupsFromSteps = (
	steps: ( BlueprintStep & { options?: Record< string, string > } )[]
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/blueprint/components/get-step-actions.ts">
import { _n, sprintf } from '@wordpress/i18n';
⋮----
import { BlueprintStep } from './types';
⋮----
export const getStepActions = ( steps: BlueprintStep[] ): string[] =>
</file>

<file path="plugins/woocommerce/client/admin/client/blueprint/components/types.ts">
export type BlueprintQueueResponse = {
	error_type?: string;
	errors?: string[];
	settings_to_overwrite?: string[];
};
⋮----
export type BlueprintImportResponse = {
	processed: boolean;
	message: string;
	data: {
		redirect: string;
		result: {
			is_success: boolean;
			messages: {
				step: string;
				type: string;
				message: string;
			}[];
		};
	};
};
⋮----
export type BlueprintStep = {
	step: string;
	options?: Record< string, string >;
};
⋮----
export type BlueprintImportStepResponse = {
	success: boolean;
	messages: {
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/blueprint/settings/overwrite-confirmation-modal.tsx">
import { Modal, Button, Notice, Spinner } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
⋮----
type OverwriteConfirmationModalProps = {
	isOpen: boolean;
	isImporting: boolean;
	onClose: () => void;
	onConfirm: () => void;
	overwrittenItems: string[];
	additionalActions?: string[];
};
⋮----
title=
⋮----
⋮----
className=
</file>

<file path="plugins/woocommerce/client/admin/client/blueprint/settings/slotfill.js">
const Blueprint = () =>
⋮----
const exportBlueprint = async ( _steps ) =>
⋮----
const handleOnChange = ( groupId, itemId ) =>
⋮----
const BlueprintSlotfill = () =>
⋮----
export const registerBlueprintSlotfill = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/blueprint/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/components/tracked-link/tracked-link.tsx">
import { Text } from '@woocommerce/experimental';
import interpolateComponents from '@automattic/interpolate-components';
import { Link } from '@woocommerce/components';
import { recordEvent, ExtraProperties } from '@woocommerce/tracks';
import { __ } from '@wordpress/i18n';
⋮----
interface TextProps {
	as?: string;
	className?: string;
}
⋮----
interface TrackedLinkProps {
	textProps?: TextProps;
	message: string;
	eventName?: string;
	eventProperties?: ExtraProperties;
	targetUrl: string;
	linkType?: 'wc-admin' | 'wp-admin' | 'external';
	target?: '_blank' | undefined;
	onClickCallback?: () => void;
}
⋮----
onClickCallback();
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/actions/tracks.tsx">
import { getSetting } from '@woocommerce/settings';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { CoreProfilerStateMachineContext } from '..';
import {
	UserProfileEvent,
	BusinessInfoEvent,
	PluginsLearnMoreLinkClickedEvent,
	PluginsInstallationCompletedWithErrorsEvent,
	PluginsInstallationCompletedEvent,
	PluginsInstallationRequestedEvent,
} from '../events';
import { POSSIBLY_DEFAULT_STORE_NAMES } from '../pages/BusinessInfo';
import {
	InstalledPlugin,
	PluginInstallError,
} from '../services/installAndActivatePlugins';
import { getPluginTrackKey, getTimeFrame } from '~/utils';
import { getPluginSlug } from '~/utils/plugins';
import { getCountryCode } from '~/dashboard/utils';
⋮----
const isShippingPlugin = ( pluginKey: string )
⋮----
const getShippingPartnerTrackingBase = (
	context: CoreProfilerStateMachineContext
) =>
⋮----
const recordTracksStepViewed = ( _: unknown, params:
⋮----
const recordTracksStepSkipped = ( _: unknown, params:
... (78 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/components/choice/choice.tsx">
import clsx from 'clsx';
⋮----
type Props = {
	className?: string;
	selected: boolean;
	title: string | React.ReactNode;
	name: string;
	value: string;
	onChange: ( value: string ) => void;
	subOptionsComponent?: React.ReactNode;
};
⋮----
const changeHandler = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/components/geolocation-country-select/geolocation-country-select.tsx">
import {
	useEffect,
	useState,
	createInterpolateElement,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Button, Notice } from '@wordpress/components';
import { SelectControl } from '@woocommerce/components';
import { Icon, chevronDown } from '@wordpress/icons';
import { findCountryOption, getCountry } from '@woocommerce/onboarding';
import { GeolocationResponse } from '@woocommerce/data';
⋮----
import type { CountryStateOption } from '../../services/country';
⋮----
type Props = {
	countries: CountryStateOption[];
	geolocatedLocation?: GeolocationResponse | null;
	initialValue: CountryStateOption;
	label: string;
	placeholder: string;
	onChange: ( country: CountryStateOption ) => void;
	onGeolocationOverruledChange?: ( overruled: boolean ) => void;
};
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/components/heading/heading.tsx">
import clsx from 'clsx';
⋮----
type Props = {
	title: string | JSX.Element;
	subTitle?: string | JSX.Element;
	className?: string;
};
⋮----
export const Heading = (
⋮----
<div className=
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/components/loader/Loader.tsx">
import { Loader } from '@woocommerce/onboarding';
⋮----
import { CoreProfilerStateMachineContext } from '../..';
import { getLoaderStageMeta } from '../../utils/get-loader-stage-meta';
⋮----
export type Stage = {
	title: string;
	image?: string | JSX.Element;
	paragraphs: Array< {
		label: string;
		text: string;
		duration?: number;
		element?: JSX.Element;
	} >;
};
⋮----
export type Stages = Array< Stage >;
export type LoaderContextProps = Pick<
	CoreProfilerStateMachineContext,
	'loader'
>;
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/components/multiple-selector/multiple-selector.tsx">
import { __ } from '@wordpress/i18n';
import {
	__experimentalSelectControl as SelectControl,
	selectControlStateChangeTypes,
} from '@woocommerce/components';
⋮----
import { renderMenu } from './render-menu';
⋮----
type Props = {
	options: Array< { label: string; value: string } >;
	onSelect: (
		selectedOptions: Array< { label: string; value: string } >
	) => void;
	selectedOptions?: Array< { label: string; value: string } >;
	placeholder?: string;
	onOpenClose?: ( isOpen: boolean ) => void;
};
⋮----
export const MultipleSelector = ( {
	options,
	onSelect,
	selectedOptions = [],
	placeholder = __( 'Select platforms', 'woocommerce' ),
	onOpenClose = () => {},
}: Props ) =>
⋮----
getFilteredItems={ ( allItems ) => allItems }
			selected={ selectedOptions }
			inputProps={ {
				readOnly: true,
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/components/multiple-selector/render-menu.tsx">
import { CheckboxControl } from '@wordpress/components';
import { useEffect } from '@wordpress/element';
import {
	__experimentalSelectControlMenu as Menu,
	__experimentalSelectControlMenuItem as MenuItem,
} from '@woocommerce/components';
import type { ChildrenProps } from '@woocommerce/components/build-types/experimental-select-control/types';
import clsx from 'clsx';
⋮----
type Props = {
	selectedOptions: Array< { label: string; value: string } >;
	onOpenClose: ( isOpen: boolean ) => void;
};
⋮----
export const renderMenu =
(
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/components/navigation/navigation.tsx">
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
import { Button } from '@wordpress/components';
⋮----
import WooLogo from './woologo';
⋮----
import ProgressBar from '../progress-bar/progress-bar';
⋮----
type NavigationProps = {
	onSkip?: () => void;
	percentage?: number;
	previous?: string;
	showProgress?: boolean;
	showLogo?: boolean;
	classNames?: { mobile?: boolean };
	skipText?: string;
	progressBarColor?: string;
};
⋮----
className=
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/components/navigation/woologo.tsx">
const WooLogo = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/components/profile-spinner/profile-spinner.tsx">
import { Spinner } from '@wordpress/components';
⋮----
export const ProfileSpinner = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/components/progress-bar/progress-bar.tsx">
import { HTMLAttributes } from 'react';
⋮----
type ProgressBarProps = {
	className?: string;
	percent?: number;
	color?: string;
	bgcolor?: string;
};
⋮----
const ProgressBar = ( {
	className = '',
	percent = 0,
	color = '#674399',
	bgcolor = 'var(--wp-admin-theme-color)',
}: ProgressBarProps ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/pages/Plugins/components/plugin-card/plugin-card.tsx">
import { CheckboxControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
import { Extension } from '@woocommerce/data';
import { Link } from '@woocommerce/components';
import {
	useMemo,
	Children,
	isValidElement,
	cloneElement,
} from '@wordpress/element';
⋮----
import sanitizeHTML from '~/lib/sanitize-html';
⋮----
// @ts-expect-error -- @types/react is deficient here
⋮----
className=
⋮----
dangerouslySetInnerHTML=
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/pages/Plugins/components/plugin-error-banner/PluginErrorBanner.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import interpolateComponents from '@automattic/interpolate-components';
⋮----
import { PluginInstallError } from '../../../../services/installAndActivatePlugins';
import { joinWithAnd, composeListFormatParts } from '../../Plugins';
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/pages/Plugins/components/plugin-terms-of-service/PluginsTermsOfService.tsx">
import { sprintf, _n } from '@wordpress/i18n';
import interpolateComponents from '@automattic/interpolate-components';
import { Link } from '@woocommerce/components';
import { ExtensionList } from '@woocommerce/data';
⋮----
import { joinWithAnd, composeListFormatParts } from '../../Plugins';
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/pages/Plugins/NoPermissions.tsx">
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import clsx from 'clsx';
⋮----
import { CoreProfilerStateMachineContext } from '../../index';
import {
	PluginsLearnMoreLinkClickedEvent,
	PluginsInstallationRequestedEvent,
	PluginsPageSkippedEvent,
} from '../../events';
import { Heading } from '../../components/heading/heading';
import { Navigation } from '../../components/navigation/navigation';
import { PluginCard } from './components/plugin-card/plugin-card';
import { PluginErrorBanner } from './components/plugin-error-banner/PluginErrorBanner';
⋮----
const skipPluginsPage = () =>
⋮----
className=
⋮----
sendEvent( {
												type: 'PLUGINS_LEARN_MORE_LINK_CLICKED',
												payload: {
													plugin: pluginSlug,
													learnMoreLink,
												},
											} );
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/pages/Plugins/Plugins.tsx">
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { Extension, ExtensionList } from '@woocommerce/data';
import { useState, useMemo } from '@wordpress/element';
import { useMediaQuery } from '@wordpress/compose';
import clsx from 'clsx';
⋮----
import { CoreProfilerStateMachineContext } from '../../index';
import {
	PluginsLearnMoreLinkClickedEvent,
	PluginsInstallationRequestedEvent,
	PluginsPageSkippedEvent,
	PluginsPageCompletedWithoutSelectingPluginsEvent,
} from '../../events';
import { Heading } from '../../components/heading/heading';
import { Navigation } from '../../components/navigation/navigation';
import { PluginCard } from './components/plugin-card/plugin-card';
import { getAdminSetting } from '~/utils/admin-settings';
import { PluginErrorBanner } from './components/plugin-error-banner/PluginErrorBanner';
import { PluginsTermsOfService } from './components/plugin-terms-of-service/PluginsTermsOfService';
⋮----
export const joinWithAnd = (
	items: string[],
	locale: string = currentLocale
) =>
⋮----
export const composeListFormatParts = ( part: {
	type: string;
	value: string;
} ) =>
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/pages/BusinessInfo.tsx">
import { __ } from '@wordpress/i18n';
import {
	Button,
	TextControl,
	Spinner,
	CheckboxControl,
	Notice,
} from '@wordpress/components';
import { FormInputValidation } from '@automattic/components';
import { SelectControl } from '@woocommerce/components';
import { Icon, chevronDown } from '@wordpress/icons';
import {
	useEffect,
	useState,
	createInterpolateElement,
} from '@wordpress/element';
import { decodeEntities } from '@wordpress/html-entities';
import { z } from 'zod';
import clsx from 'clsx';
⋮----
import { CoreProfilerStateMachineContext } from '../index';
import { BusinessInfoEvent } from '../events';
import { CountryStateOption } from '../services/country';
import { Heading } from '../components/heading/heading';
import { Navigation } from '../components/navigation/navigation';
import { GeolocationCountrySelect } from '../components/geolocation-country-select/geolocation-country-select';
⋮----
export type IndustryChoice = ( typeof industryChoices )[ number ][ 'key' ];
⋮----
export type IndustryChoiceOption = ( typeof industryChoices )[ number ];
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/pages/BusinessLocation.tsx">
import { __ } from '@wordpress/i18n';
import { Button, Notice } from '@wordpress/components';
import { useState, createInterpolateElement } from '@wordpress/element';
⋮----
import { CoreProfilerStateMachineContext } from '../index';
import { BusinessLocationEvent } from '../events';
import { CountryStateOption } from '../services/country';
import { Heading } from '../components/heading/heading';
import { Navigation } from '../components/navigation/navigation';
import { GeolocationCountrySelect } from '../components/geolocation-country-select/geolocation-country-select';
⋮----
sendEvent( {
												type: 'RETRY_COUNTRIES_LIST',
											} );
⋮----
sendEvent( {
												type: 'BUSINESS_LOCATION_COMPLETED',
												payload: {
													storeLocation: 'US:CA',
												},
											} );
⋮----
onClick=
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/pages/IntroOptIn.tsx">
import { __ } from '@wordpress/i18n';
import { Button, CheckboxControl } from '@wordpress/components';
import { useState } from '@wordpress/element';
import interpolateComponents from '@automattic/interpolate-components';
import { Link } from '@woocommerce/components';
⋮----
import { IntroOptInEvent } from '../events';
import { Heading } from '../components/heading/heading';
import { Navigation } from '../components/navigation/navigation';
import { CoreProfilerStateMachineContext } from '..';
⋮----
title=
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/pages/UserProfile.tsx">
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { SelectControl } from '@woocommerce/components';
import { Icon, chevronDown } from '@wordpress/icons';
import clsx from 'clsx';
⋮----
import { CoreProfilerStateMachineContext } from '../index';
import { UserProfileEvent } from '../events';
import { Navigation } from '../components/navigation/navigation';
import { Heading } from '../components/heading/heading';
import { Choice } from '../components/choice/choice';
import { MultipleSelector } from '../components/multiple-selector/multiple-selector';
⋮----
export type BusinessChoice = ( typeof businessOptions )[ 0 ][ 'value' ];
export type SellingOnlineAnswer =
	( typeof sellingOnlineOptions )[ 0 ][ 'value' ];
export type SellingPlatform = ( typeof platformOptions )[ 0 ][ 'value' ];
⋮----
⋮----
sendEvent( {
			type: 'USER_PROFILE_COMPLETED',
			payload: {
				userProfile: {
					businessChoice,
					sellingOnlineAnswer:
						businessChoice === 'im_already_selling'
							? sellingOnlineAnswer
							: null,
					sellingPlatforms:
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/services/country.ts">
import { Country } from '@woocommerce/data';
import { decodeEntities } from '@wordpress/html-entities';
⋮----
export type CountryStateOption = {
	key: string;
	label: string;
};
⋮----
export function getCountryStateOptions(
	countries: Country[]
): CountryStateOption[]
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/services/installAndActivatePlugins.ts">
import {
	ExtensionList,
	pluginsStore,
	PluginNames,
	onboardingStore,
} from '@woocommerce/data';
import { dispatch } from '@wordpress/data';
import {
	DoneActorEvent,
	ErrorActorEvent,
	assign,
	createMachine,
	fromPromise,
	sendParent,
} from 'xstate5';
⋮----
import {
	PluginInstalledAndActivatedEvent,
	PluginsInstallationCompletedEvent,
	PluginsInstallationCompletedWithErrorsEvent,
} from '../events';
import { getPluginSlug } from '~/utils/plugins';
⋮----
export type InstalledPlugin = {
	plugin: string;
	installTime: number;
};
⋮----
export type InstallationCompletedResult = {
	installedPlugins: InstalledPlugin[];
... (50 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/stories/BusinessInfo.story.tsx">
import { BusinessInfo } from '../pages/BusinessInfo';
⋮----
import { WithSetupWizardLayout } from './WithSetupWizardLayout';
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/stories/BusinessLocation.story.tsx">
import { BusinessLocation } from '../pages/BusinessLocation';
⋮----
import { WithSetupWizardLayout } from './WithSetupWizardLayout';
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/stories/IntroOptIn.story.tsx">
import { CoreProfilerStateMachineContext } from '..';
import { IntroOptIn } from '../pages/IntroOptIn';
⋮----
import { WithSetupWizardLayout } from './WithSetupWizardLayout';
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/stories/Loader.story.tsx">
import { CoreProfilerLoader } from '../components/loader/Loader';
import { WithSetupWizardLayout } from './WithSetupWizardLayout';
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/stories/Plugins.story.tsx">
import { Plugins } from '../pages/Plugins/Plugins';
import { NoPermissionsError } from '../pages/Plugins/NoPermissions';
import { PluginsTermsOfService } from '../pages/Plugins/components/plugin-terms-of-service/PluginsTermsOfService';
import { PluginErrorBanner } from '../pages/Plugins/components/plugin-error-banner/PluginErrorBanner';
⋮----
import { WithSetupWizardLayout } from './WithSetupWizardLayout';
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/stories/UserProfile.story.tsx">
import { UserProfile } from '../pages/UserProfile';
⋮----
import { WithSetupWizardLayout } from './WithSetupWizardLayout';
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/stories/WithSetupWizardLayout.tsx">
export const WithSetupWizardLayout = ( Story: React.ComponentType ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/utils/get-loader-stage-meta.tsx">
import { __ } from '@wordpress/i18n';
⋮----
import LightBulbImage from '../assets/images/loader-lightbulb.svg';
import DevelopingImage from '../assets/images/loader-developing.svg';
import LayoutImage from '../assets/images/loader-layout.svg';
import OpeningTheDoorsImage from '../assets/images/loader-openingthedoors.svg';
import Hearticon from '../assets/images/loader-hearticon.svg';
⋮----
import { Stages } from '../components/loader/Loader';
⋮----
export const getLoaderStageMeta = ( key: string ): Stages =>
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/events.tsx">
import { CountryStateOption } from '@woocommerce/onboarding';
⋮----
import { IndustryChoice } from './pages/BusinessInfo';
import {
	InstallationCompletedResult,
	PluginInstallError,
} from './services/installAndActivatePlugins';
import { CoreProfilerStateMachineContext } from '.';
⋮----
export type InitializationCompleteEvent = {
	type: 'INITIALIZATION_COMPLETE';
	payload: { optInDataSharing: boolean };
};
⋮----
export type IntroOptInEvent = IntroCompletedEvent | IntroSkippedEvent;
⋮----
export type IntroCompletedEvent = {
	type: 'INTRO_COMPLETED';
	payload: { optInDataSharing: boolean };
};
⋮----
export type IntroSkippedEvent = {
	type: 'INTRO_SKIPPED';
	payload: { optInDataSharing: boolean };
};
⋮----
export type UserProfileEvent =
	| {
			type: 'USER_PROFILE_COMPLETED';
			payload: {
... (107 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/index.tsx">
import {
	createMachine,
	assign,
	fromPromise,
	spawnChild,
	raise,
	assertEvent,
	enqueueActions,
	DoneActorEvent,
	fromCallback,
	or,
} from 'xstate5';
import { useMachine, useSelector } from '@xstate5/react';
import { useMemo } from '@wordpress/element';
import { resolveSelect, dispatch } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import {
	updateQueryString,
	getQuery,
	getNewPath,
} from '@woocommerce/navigation';
import {
	ExtensionList,
	COUNTRIES_STORE_NAME,
	Country,
	onboardingStore,
	Extension,
	GeolocationResponse,
	pluginsStore,
	userStore,
... (134 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/core-profiler/types.tsx">
import { CoreProfilerStateMachineContext } from '.';
⋮----
export type ComponentMeta = {
	component: ( arg0: ComponentProps ) => JSX.Element;
	progress: number;
};
⋮----
export type ComponentProps = {
	navigationProgress: number | undefined;
	sendEvent: unknown;
	context: CoreProfilerStateMachineContext;
};
</file>

<file path="plugins/woocommerce/client/admin/client/customize-store/site-hub/entrepreneur-flow.ts">
import { addFilter } from '@wordpress/hooks';
⋮----
export const isEntrepreneurFlow = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/customize-store/site-hub/index.tsx">
import clsx from 'clsx';
import { useSelect } from '@wordpress/data';
import {
	__unstableMotion as motion,
	__unstableAnimatePresence as AnimatePresence,
	__experimentalHStack as HStack,
} from '@wordpress/components';
import { useReducedMotion } from '@wordpress/compose';
import { store as coreStore } from '@wordpress/core-data';
import { decodeEntities } from '@wordpress/html-entities';
import { forwardRef } from '@wordpress/element';
⋮----
import SiteIcon from '@wordpress/edit-site/build-module/components/site-icon';
import { getNewPath, getPersistedQuery } from '@woocommerce/navigation';
import { Link } from '@woocommerce/components';
import WordPressLogo from '~/lib/wordpress-logo';
⋮----
import { isEntrepreneurFlow } from './entrepreneur-flow';
⋮----
className=
</file>

<file path="plugins/woocommerce/client/admin/client/customize-store/index.tsx">
import { useEffect, useMemo } from '@wordpress/element';
import { __, isRTL } from '@wordpress/i18n';
import {
	Button,
	__experimentalHStack as HStack,
	__experimentalHeading as Heading,
	__experimentalVStack as VStack,
	__unstableMotion as motion,
} from '@wordpress/components';
import { getAdminLink } from '@woocommerce/settings';
import { getNewPath } from '@woocommerce/navigation';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import SidebarButton from '@wordpress/edit-site/build-module/components/sidebar-button';
import { chevronRight, chevronLeft } from '@wordpress/icons';
⋮----
import { useFullScreen } from '~/utils';
import { isWooExpress } from '~/utils/is-woo-express';
import { SiteHub } from './site-hub';
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
import { useDispatch, useSelect } from '@wordpress/data';
import banner1Shape from './assets/banner-1-shape.svg';
import banner2Shape from './assets/banner-2-shape.svg';
import banner1Illu from './assets/banner-1-illu.svg';
import banner2Illu from './assets/banner-2-illu.svg';
⋮----
const markTaskComplete = async () =>
⋮----
const isNewTabClick = ( event: React.MouseEvent ) =>
⋮----
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/components/connect/index.js">
export class Connect extends Component
⋮----
componentDidUpdate( prevProps )
⋮----
connectJetpack()
⋮----
render()
⋮----
setIsPending: () =>
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/components/settings/general/store-address.tsx">
import { __ } from '@wordpress/i18n';
import { countriesStore, Country, Locale } from '@woocommerce/data';
import { decodeEntities } from '@wordpress/html-entities';
import { escapeRegExp } from 'lodash';
import { useEffect, useMemo, useState, useRef } from '@wordpress/element';
import {
	SelectControl,
	TextControl,
	FormContextType,
} from '@woocommerce/components';
import { Spinner } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
⋮----
export type FormValues = {
	addressLine1: string;
	addressLine2: string;
	countryState: string;
	city: string;
	postCode: string;
};
⋮----
type Option = { key: string; label: string };
⋮----
export function getStoreAddressValidator(  )
⋮----
export function getCountryStateOptions( countries: Country[] )
⋮----
export const normalizeState = ( state: string ): string =>
⋮----
/**
... (53 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/components/cart-modal.js">
class CartModal extends Component
⋮----
onClickPurchaseNow()
⋮----
onClickPurchaseLater()
⋮----
onClose()
⋮----
renderProducts()
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/dashboard-charts/block.js">
class ChartBlock extends Component
⋮----
getChartPath( chart )
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/dashboard-charts/config.js">

</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/dashboard-charts/index.js">
const renderChartToggles = (
⋮----
const renderIntervalSelector = ( {
	chartInterval,
	setInterval,
	query,
	defaultDateRange,
} ) =>
⋮----
const renderChartBlocks = (
⋮----
const DashboardCharts = ( props ) =>
⋮----
const handleTypeToggle = ( type ) =>
⋮----
const renderMenu = () => (
		<EllipsisMenu
			label={ __( 'Choose which charts to display', 'woocommerce' ) }
			placement={ 'bottom-end' }
			renderContent={ ( { onToggle } ) => (
				<Fragment>
					<MenuTitle>{ __( 'Charts', 'woocommerce' ) }</MenuTitle>
					{ renderChartToggles( {
						hiddenBlocks,
						onToggleHiddenBlock,
					} ) }
					<Controls
						onToggle={ onToggle }
						onMove={ onMove }
						onRemove={ onRemove }
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/leaderboards/index.js">
const renderLeaderboardToggles = ( {
	allLeaderboards,
	hiddenBlocks,
	onToggleHiddenBlock,
} ) =>
⋮----
const renderLeaderboards = ( {
	allLeaderboards,
	hiddenBlocks,
	query,
	rowsPerTable,
	filters,
} ) =>
⋮----
const Leaderboards = ( props ) =>
⋮----
const setRowsPerTable = ( rows ) =>
⋮----
const renderMenu = () => (
		<EllipsisMenu
			label={ __(
				'Choose which leaderboards to display and other settings',
				'woocommerce'
			) }
			placement={ 'bottom-end' }
			renderContent={ ( { onToggle } ) => (
				<Fragment>
					<MenuTitle>
						{ __( 'Leaderboards', 'woocommerce' ) }
					</MenuTitle>
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/store-performance/index.js">
class StorePerformance extends Component
⋮----
renderMenu()
⋮----
renderList()
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/store-performance/utils.js">
function getReportUrl( href, persistedQuery, primaryItem )
⋮----
export const getIndicatorValues = ( {
	indicator,
	primaryData,
	secondaryData,
	currency,
	formatAmount,
	persistedQuery,
} ) =>
⋮----
export const getIndicatorData = ( select, indicators, query, filters ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/customizable.js">
const isValidSection = ( section )
⋮----
isVisible: ( value )
title: ( value )
⋮----
hiddenBlocks: ()
⋮----
/**
 * Whether an entry of the stored preference carries usable values for the
 * fields the dashboard dereferences. A missing field is fine, the default
 * section provides it.
 *
 * @param {Object} section Well formed entry of the stored preference.
 * @return {boolean} Whether every field the dashboard reads can be used as is.
 */
const hasUsableFields = ( section )
⋮----
/**
 * Whether an entry of the stored preference can be used without patching it up
 * from a default section.
 *
 * @param {*} section Entry of the stored `dashboard_sections` preference.
 * @return {boolean} Whether the entry can be used as is.
 */
const isUsableSection = ( section )
⋮----
/**
 * Whether the stored `dashboard_sections` preference is well formed.
 *
 * @param {*} prefSections Stored `dashboard_sections` preference.
... (97 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/default-sections.js">
const DashboardCharts = ( props ) => (
	<Suspense fallback={ <Spinner /> }>
		<LazyDashboardCharts { ...props } />
	</Suspense>
);
⋮----
const Leaderboards = ( props ) => (
	<Suspense fallback={ <Spinner /> }>
		<LazyLeaderboards { ...props } />
	</Suspense>
);
⋮----
const StorePerformance = ( props ) => (
	<Suspense fallback={ <Spinner /> }>
		<LazyStorePerformance { ...props } />
	</Suspense>
);
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/index.js">
class Dashboard extends Component
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/README.md">
# Dashboard

This folder contains the components used in the Dashboard page.

## Extending the Dashboard

New Dashboard sections can be added by hooking into the filter `woocommerce_dashboard_default_sections`. For example:

```js
import { arrowRight } from '@wordpress/icons';
addFilter( 'woocommerce_dashboard_default_sections', ( sections ) => {
	return [
		...sections,
		{
			key: 'example',
			component: ExampleSection,
			title: 'My Example Dashboard Section',
			isVisible: true,
			icon: arrowRight,
			hiddenBlocks: [],
		},
	];
} );
```

Each section is defined by an object containing the following properties.

-   `key` (string): The key used internally to identify the section.
-   `title` (string): The title shown in the Dashboard. It can be modified by users.
-   `icon` (function|WPComponent|null): Icon to be used to identify the section.
... (20 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/section-controls.js">
class SectionControls extends Component
⋮----
onMoveUp()
⋮----
onMoveDown()
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/section.js">
export default class Section extends Component
⋮----
onTitleChange( updatedTitle )
⋮----
onTitleBlur()
⋮----
onToggleHiddenBlock( key )
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/dashboard/utils.ts">
import { decodeEntities } from '@wordpress/html-entities';
import {
	OnboardingProductType,
	OnboardingProductTypes,
	ProfileItems,
} from '@woocommerce/data';
⋮----
export function getCountryCode( countryState = '' )
⋮----
/**
 * Get the value of a price from a string, removing any non-numeric characters.
 *
 * @param {string} string Price string.
 * @return {number} Number value.
 */
export function getPriceValue( string: string )
⋮----
/**
 * Gets a product list for items based on the product types and theme selected in the onboarding profiler.
 *
 * @param {Object}  profileItems          Onboarding profile.
 * @param {boolean} includeInstalledItems Include installed items in returned product list.
 * @param {Array}   installedPlugins      Installed plugins.
 * @param {Object}  productTypes          Product Types.
 * @return {Array} Products.
 */
export function getProductList(
	profileItems: ProfileItems,
	includeInstalledItems = false,
	installedPlugins: string[],
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/embedded-body-layout/embedded-body-layout.tsx">
import { applyFilters } from '@wordpress/hooks';
import { useEffect } from '@wordpress/element';
import { triggerExitPageCesSurvey } from '@woocommerce/customer-effort-score';
import {
	LayoutContextProvider,
	getLayoutContextValue,
} from '@woocommerce/admin-layout';
import QueryString, { parse } from 'qs';
⋮----
import { PaymentRecommendations } from '../payments';
import { ShippingRecommendations } from '../shipping';
import { TaxRecommendations } from '../tax';
import { EmbeddedBodyProps } from './embedded-body-props';
⋮----
type QueryParams = EmbeddedBodyProps;
⋮----
function isWPPage(
	params: QueryParams | QueryString.ParsedQs
): params is QueryParams
⋮----
export const EmbeddedBodyLayout = () =>
⋮----
/**
	 * Filter an array of body components for WooCommerce non-react pages.
	 *
	 * @filter woocommerce_admin_embedded_layout_components
	 * @param {Array.<Node>} embeddedBodyComponentList Array of body components.
	 * @param {Object}       query                     url query parameters.
	 */
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/embedded-body-layout/embedded-body-props.ts">
export type EmbeddedBodyProps = {
	page: string;
	tab: string;
	zone_id?: string;
	section?: string;
};
</file>

<file path="plugins/woocommerce/client/admin/client/embedded-body-layout/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/embedded-body-layout/render-embedded-layout.tsx">
import {
	withCurrentUserHydration,
	withSettingsHydration,
	WCUser,
} from '@woocommerce/data';
import debugFactory from 'debug';
import { createRoot } from '@wordpress/element';
⋮----
import { PrimaryLayout as NoticeArea } from '../layout/shared';
import { EmbedLayout } from '../layout/embed';
import { EmbeddedBodyLayout } from './embedded-body-layout';
import {
	possiblyRenderOrderAttributionSlot,
	registerOrderAttributionSlotFill,
} from '../order-attribution-install-banner/order-editor/slot';
⋮----
const findWrapElement = ( wpBody: HTMLElement ) =>
⋮----
const renderNotices = ( wpBody: HTMLElement, wrap: Element ) =>
⋮----
const registerSlotFills = () =>
⋮----
export const renderEmbeddedLayout = (
	embeddedRoot: HTMLElement,
	hydrateUser: WCUser,
	settingsGroup: string
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/error-boundary/index.tsx">
import { Component, ReactNode, ErrorInfo } from 'react';
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { captureException } from '@woocommerce/remote-logging';
import { bumpStat } from '@woocommerce/tracks';
⋮----
type ErrorBoundaryProps = {
	children: ReactNode;
};
⋮----
type ErrorBoundaryState = {
	hasError: boolean;
	error: Error | null;
	errorInfo: ErrorInfo | null;
};
⋮----
constructor( props: ErrorBoundaryProps )
⋮----
static getDerivedStateFromError(
		error: Error
): Partial< ErrorBoundaryState >
⋮----
componentDidCatch( error: Error, errorInfo: ErrorInfo )
</file>

<file path="plugins/woocommerce/client/admin/client/guided-tours/add-product-tour/index.tsx">
import { useEffect, useState } from '@wordpress/element';
import { applyFilters } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n';
import { TourKit, TourKitTypes } from '@woocommerce/components';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { useTmceIframeFocusStyle } from './use-tmce-iframe-focus-style';
import { useActiveEditorType } from './use-active-editor-type';
import {
	bindEnableGuideModeClickEvent,
	waitUntilElementTopNotChange,
} from '../utils';
import {
	ProductTourStepName,
	useProductStepChange,
} from './use-product-step-change';
import { useTrackPublishButton } from './use-track-publish-button';
⋮----
const getTourConfig = ( {
	isExcerptEditorTmceActive,
	isContentEditorTmceActive,
	closeHandler,
	onNextStepHandler,
}: {
	isExcerptEditorTmceActive: boolean;
	isContentEditorTmceActive: boolean;
	closeHandler: TourKitTypes.CloseHandler;
onNextStepHandler: ( currentStepIndex: number )
⋮----
export const ProductTour = () =>
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/guided-tours/add-product-tour/use-active-editor-type.ts">
import { useEffect, useRef, useState } from '@wordpress/element';
⋮----
export type EditorType = 'tmce' | 'html';
⋮----
export const useActiveEditorType = ( {
	editorWrapSelector,
}: {
	editorWrapSelector: string;
} ) =>
⋮----
const onClickEditorTab = ( e: MouseEvent ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/guided-tours/add-product-tour/use-product-step-change.ts">
import { useCallback, useEffect, useState } from '@wordpress/element';
⋮----
import { useActiveEditorType } from './use-active-editor-type';
⋮----
export type ProductTourStepName =
	| 'product-name'
	| 'product-description'
	| 'product-data'
	| 'product-short-description'
	| 'product-image'
	| 'product-tags'
	| 'product-categories';
⋮----
const getInputValue = ( id: string ) =>
⋮----
const getTinyMceValue = ( id: string ) =>
⋮----
const getTextareaValue = ( id: string ) =>
⋮----
const getProductDescriptionValue = ( isContentEditorTmceActive: boolean ) =>
⋮----
const getProductShortDescriptionValue = (
	isExcerptEditorTmceActive: boolean
) =>
⋮----
const getProductImageValue = () =>
⋮----
// Parses categories into a string of true/false. Should be enough to catch any change.
const getProductCategoriesValue = () =>
⋮----
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/guided-tours/add-product-tour/use-tmce-iframe-focus-style.ts">
import { useEffect } from '@wordpress/element';
⋮----
type addClassToIframeWhenChildFocusProps = {
	iframeSelector: string;
	childSelector: string;
	className: string;
};
⋮----
const addClassToIframeWhenChildFocus = ( {
	iframeSelector,
	childSelector,
	className,
}: addClassToIframeWhenChildFocusProps ) =>
⋮----
const onFocus = ()
const onBlur = ()
⋮----
export const useTmceIframeFocusStyle = ( {
	iframeSelector,
	isActive,
}: {
	iframeSelector: string;
	isActive: boolean;
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/guided-tours/add-product-tour/use-track-publish-button.ts">
import { useEffect, useRef } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { bindPublishClickEvent } from '../utils';
⋮----
export const useTrackPublishButton = ( showTour: boolean ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/guided-tours/variable-product-tour/index.tsx">
import { useEffect, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { TourKit, TourKitTypes } from '@woocommerce/components';
import { useUserPreferences } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
⋮----
function getStepName(
	steps: TourKitTypes.WooStep[],
	currentStepIndex: number
)
⋮----
export const VariableProductTour = () =>
⋮----
function handleProductTypeChange()
</file>

<file path="plugins/woocommerce/client/admin/client/guided-tours/wc-addons-tour/get-config.ts">
import { TourKitTypes } from '@woocommerce/components';
⋮----
import { scrollPopperToVisibleAreaIfNeeded } from './utils';
⋮----
export const getTourConfig = ( {
	closeHandler,
	onNextStepHandler,
	autoScrollBlock,
	steps,
}: {
	closeHandler: TourKitTypes.CloseHandler;
onNextStepHandler: ( currentStepIndex: number )
⋮----
fn(
</file>

<file path="plugins/woocommerce/client/admin/client/guided-tours/wc-addons-tour/get-steps.ts">
import { __ } from '@wordpress/i18n';
import { createElement, createInterpolateElement } from '@wordpress/element';
import { TourKitTypes } from '@woocommerce/components';
⋮----
export const getSteps = (): TourKitTypes.WooStep[] =>
</file>

<file path="plugins/woocommerce/client/admin/client/guided-tours/wc-addons-tour/index.tsx">
import { useEffect, useState } from '@wordpress/element';
import { TourKit, TourKitTypes } from '@woocommerce/components';
import { recordEvent } from '@woocommerce/tracks';
import { useDispatch } from '@wordpress/data';
import { optionsStore } from '@woocommerce/data';
⋮----
import { observePositionChange, waitUntilElementTopNotChange } from '../utils';
import { getTourConfig } from './get-config';
import { scrollPopperToVisibleAreaIfNeeded } from './utils';
import { getSteps } from './get-steps';
⋮----
const WCAddonsTour = () =>
⋮----
function showPopper()
⋮----
const closeHandler: TourKitTypes.CloseHandler = (
		tourSteps,
		currentStepIndex
) =>
⋮----
const onNextStepHandler = ( newStepIndex: number ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/guided-tours/wc-addons-tour/utils.ts">
export const scrollPopperToVisibleAreaIfNeeded = (
	popperBoundingRect: DOMRect
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/guided-tours/report-date-tour.tsx">
import { TourKit, TourKitTypes } from '@woocommerce/components';
import { __ } from '@wordpress/i18n';
import { optionsStore } from '@woocommerce/data';
import {
	createElement,
	createInterpolateElement,
	useState,
} from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { getAdminLink } from '@woocommerce/settings';
⋮----
export const ReportDateTour = ( {
	optionName,
	headingText,
}: {
	optionName: string;
	headingText: string;
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/guided-tours/shipping-tour.tsx">
import { TourKit, TourKitTypes } from '@woocommerce/components';
import { __ } from '@wordpress/i18n';
import { useDispatch, useSelect } from '@wordpress/data';
import {
	useLayoutEffect,
	useEffect,
	useState,
	useRef,
	createPortal,
} from '@wordpress/element';
import { optionsStore } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { getCountryCode } from '~/dashboard/utils';
⋮----
const useShowShippingTour = () =>
⋮----
type NonEmptySelectorArray = readonly [ string, ...string[] ];
⋮----
const computeDims = ( elementsSelectors: NonEmptySelectorArray ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/guided-tours/utils.ts">
export const waitUntilElementTopNotChange = (
	elSelector: string,
	cb: () => void,
	pollMs: number
) =>
⋮----
export const observePositionChange = (
	selector: string,
	callback: () => void,
	pollMs: number
) =>
⋮----
export const bindEnableGuideModeClickEvent = (
	onClick: EventListenerOrEventListenerObject
) =>
⋮----
export const bindPublishClickEvent = (
	onClick: EventListenerOrEventListenerObject
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/header/embed.tsx">
import clsx from 'clsx';
import { __ } from '@wordpress/i18n';
import { Button, Icon } from '@wordpress/components';
import { cog, help } from '@wordpress/icons';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { BaseHeader } from './shared';
import { useWpAdminChrome } from './use-wp-admin-chrome';
</file>

<file path="plugins/woocommerce/client/admin/client/header/index.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { useEffect } from '@wordpress/element';
import { decodeEntities } from '@wordpress/html-entities';
import { getSetting } from '@woocommerce/settings';
import { getScreenFromPath, isWCAdmin, getPath } from '@woocommerce/navigation';
⋮----
import {
	LaunchYourStoreStatus,
	useLaunchYourStore,
} from '../launch-your-store';
import {
	OrderAttributionInstallBanner,
	BANNER_TYPE_HEADER as ORDER_ATTRIBUTION_INSTALL_BANNER_TYPE_HEADER,
} from '~/order-attribution-install-banner';
import { BaseHeader } from './shared';
⋮----
export const Header = ( {
	sections,
	query,
}: {
	sections: string[];
	query: Record< string, string >;
} ) =>
⋮----
/* translators: 1: document title. 2: page title */
</file>

<file path="plugins/woocommerce/client/admin/client/header/README.md">
Header
======

A basic component for the app header. The header outputs breadcrumbs via the `sections` prop (required) and access to the activity panel. It also sets the document title.

## How to use:

```jsx
import Header from 'header';

render: function() {
	return (
		<Header
			sections={ [
				[ '/analytics', __( 'Analytics', 'woocommerce' ) ],
				__( 'Report Title', 'woocommerce' ),
			] }
		/>
  	);
}
```

## Props

* `sections` (required): Used to generate breadcrumbs. Accepts a single items or an array of items. To make an item a link, wrap it in an array with a relative link (example: `[ '/analytics', __( 'Analytics', 'woocommerce' ) ]` ).
* `isEmbedded`: Boolean describing if the header is embedded on an existing wp-admin page. False if rendered as part of a full react page.

Activity Panel
==============

... (2 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/header/shared.tsx">
import { useSlot, Text } from '@woocommerce/experimental';
import type { ReactNode } from 'react';
import clsx from 'clsx';
import { decodeEntities } from '@wordpress/html-entities';
import {
	WC_HEADER_PAGE_TITLE_SLOT_NAME,
	WooHeaderNavigationItem,
	WooHeaderItem,
	WooHeaderPageTitle,
} from '@woocommerce/admin-layout';
⋮----
export const getPageTitle = ( sections: string[] ) =>
⋮----
className=
</file>

<file path="plugins/woocommerce/client/admin/client/header/use-wp-admin-chrome.ts">
import { useEffect, useState } from '@wordpress/element';
⋮----
type ActiveMetaIcon = 'screen-options' | 'help' | null;
⋮----
type WpAdminChrome = {
	hasH1: boolean;
	hasScreenOptions: boolean;
	hasContextualHelp: boolean;
	activeMetaIcon: ActiveMetaIcon;
	triggerMetaIcon: (
		which: Exclude< ActiveMetaIcon, null >,
		triggerId: string
	) => void;
};
⋮----
export const useWpAdminChrome = (
	query: Record< string, string >
): WpAdminChrome =>
⋮----
const detectWpAdminChrome = () => (
⋮----
const handler = ( e: Event ) =>
⋮----
const sync = () =>
⋮----
const triggerMetaIcon = (
		which: Exclude< ActiveMetaIcon, null >,
		triggerId: string
) =>
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/activity-panel/orders/index.js">
function recordOrderEvent( eventName )
⋮----
const renderEmptyCard = () =>
⋮----
function renderOrders( orders, customers, getFormattedOrderTotal )
⋮----
const getCustomerString = ( name ) =>
⋮----
const orderCardTitle = ( order ) =>
⋮----
const sanitizeName = ( name )
⋮----
/* translators: 1: order number, 2: customer name */
⋮----
function OrdersPanel(
⋮----
const getFormattedOrderTotal = ( total, orderCurrencyCode ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/activity-panel/orders/utils.js">
export function getOrderStatuses( select )
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/activity-panel/reviews/checkmark-circle-icon.js">

</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/activity-panel/reviews/index.js">
class ReviewsPanel extends Component
⋮----
recordReviewEvent( eventName, eventData )
⋮----
deleteReview( reviewId )
⋮----
onClick: () =>
⋮----
updateReviewStatus( reviewId, newStatus, oldStatus )
⋮----
renderReview( review )
⋮----
renderReviews( reviews )
⋮----
render()
⋮----
const clearReviewsCache = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/activity-panel/reviews/utils.js">

</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/activity-panel/stock/card.js">
export class ProductStockCard extends Component
⋮----
recordStockEvent( eventName, eventProps =
⋮----
beginEdit()
⋮----
cancelEdit()
⋮----
handleKeyDown( event )
⋮----
onQuantityChange( event )
⋮----
async onSubmit()
⋮----
onClick: () =>
⋮----
getActions()
⋮----
getBody()
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/activity-panel/stock/index.js">
export class StockPanel extends Component
⋮----
async updateStock( product, quantity )
⋮----
renderProducts()
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/activity-panel/index.js">
export const ActivityPanel = () =>
⋮----
const getInitialOpenState = ( panelId ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/activity-panel/panels.js">
export function getAllPanels( {
	lowStockProductsCount,
	unapprovedReviewsCount,
	unreadOrdersCount,
	manageStock,
	isTaskListHidden,
	orderStatuses,
	publishedProductCount,
	reviewsEnabled,
	totalOrderCount,
} )
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/email-improvements-modal/index.tsx">
import { Guide, Button, Icon } from '@wordpress/components';
import { useState, useEffect } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { closeSmall } from '@wordpress/icons';
import { updateQueryString } from '@woocommerce/navigation';
import { useSearchParams } from 'react-router-dom';
⋮----
import Illustration from './email-improvements.png';
⋮----
interface EmailImprovementsModalProps {
	type: 'enabled' | 'try';
}
⋮----
const clearQueryString = () =>
⋮----
const onFinish = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/header-banner-slot/header-banner-slot.tsx">
import { useSlot } from '@woocommerce/experimental';
import clsx from 'clsx';
⋮----
import {
	EXPERIMENTAL_WC_HOMESCREEN_HEADER_BANNER_SLOT_NAME,
	WooHomescreenHeaderBannerItem,
} from './utils';
⋮----
export const WooHomescreenHeaderBanner = ( {
	className,
}: {
	className: string;
} ) =>
⋮----
<div className=
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/header-banner-slot/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/header-banner-slot/utils.tsx">
import { Slot, Fill } from '@wordpress/components';
import {
	createOrderedChildren,
	sortFillsByOrder,
} from '@woocommerce/components';
⋮----
export const WooHomescreenHeaderBannerItem = ( {
	children,
	order = 1,
}: {
	children: React.ReactNode;
	order?: number;
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/index.tsx">

</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/MobileAppInstallationInfo.tsx">
import { QRCodeSVG } from 'qrcode.react';
⋮----
export const MobileAppInstallationInfo = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/MobileAppLoginInfo.tsx">
import { QRCodeSVG } from 'qrcode.react';
import React from '@wordpress/element';
import interpolateComponents from '@automattic/interpolate-components';
import { __ } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
import { Link } from '@woocommerce/components';
⋮----
recordEvent(
										'onboarding_app_login_faq_click'
									);
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/MobileAppLoginStepper.tsx">
import React, { useState, useEffect } from '@wordpress/element';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { Stepper, StepperProps, Link } from '@woocommerce/components';
import interpolateComponents from '@automattic/interpolate-components';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { SendMagicLinkStates } from './';
import { MobileAppInstallationInfo } from '../components/MobileAppInstallationInfo';
import { QRDirectLoginCode } from '../components/QRDirectLoginCode';
import type { QRLoginConsumedSnapshot } from '../components/QRDirectLoginCode';
import { SendMagicLinkButton } from '../components/SendMagicLinkButton';
import { QRLoginSuccessStep } from '../components/QRLoginSuccessStep';
⋮----
completeInstallationStepHandler();
⋮----
⋮----
recordEvent(
														'onboarding_app_login_faq_click'
													);
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/QRDirectLoginCode.tsx">
import { QRCodeSVG } from 'qrcode.react';
import React, { useEffect, useRef } from '@wordpress/element';
import { Button, Spinner } from '@wordpress/components';
import { sprintf, __ } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { useQRLoginToken, QRLoginTokenStates } from './useQRLoginToken';
import type { QRLoginDeviceInfo } from './useQRLoginToken';
import { useQRLoginAvailability } from './useQRLoginAvailability';
import { QRLoginConsumedPanel } from './QRLoginConsumedPanel';
import { QRLoginRevokedPanel } from './QRLoginRevokedPanel';
import { QRLoginNumberMatchStep } from './QRLoginNumberMatchStep';
import { QRLoginUnavailableCard } from './QRLoginUnavailableCard';
⋮----
export type QRLoginConsumedSnapshot = {
	apUuid: string | null;
	deviceInfo: QRLoginDeviceInfo | null;
};
⋮----
type QRDirectLoginCodeProps = {
	onDone?: () => void;
	onConsumed?: ( snapshot: QRLoginConsumedSnapshot ) => void;
	suppressInlinePanels?: boolean;
};
⋮----
export const QRDirectLoginCode = ( {
	onDone,
	onConsumed,
	suppressInlinePanels = false,
}: QRDirectLoginCodeProps ) =>
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/QRLoginConsumedPanel.tsx">
import React from '@wordpress/element';
import type { ReactNode } from 'react';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import type { QRLoginDeviceInfo } from './useQRLoginToken';
import {
	buildQRLoginDeviceHeadline,
	buildQRLoginDeviceSubline,
} from './qrLoginDeviceCopy';
⋮----
type QRLoginConsumedPanelProps = {
	deviceInfo: QRLoginDeviceInfo | null;
	onRevoke: () => void;
	onDone?: () => void;
	errorMessage?: ReactNode | null;
};
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/qrLoginDeviceCopy.ts">
import { sprintf, __ } from '@wordpress/i18n';
⋮----
import type { QRLoginDeviceInfo } from './useQRLoginToken';
⋮----
export const buildQRLoginDeviceHeadline = (
	device: QRLoginDeviceInfo | null
): string =>
⋮----
export const buildQRLoginDeviceLine = (
	device: QRLoginDeviceInfo | null
): string =>
⋮----
export const buildQRLoginDeviceSubline = (
	device: QRLoginDeviceInfo | null
): string =>
⋮----
/* translators: %s: mobile app version, e.g. "24.7.0". */
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/QRLoginNumberMatchStep.tsx">
import React, { useEffect, useMemo, useState } from '@wordpress/element';
import { Button, Spinner } from '@wordpress/components';
import { sprintf, __ } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
import type { ReactNode } from 'react';
⋮----
import type { QRLoginDeviceInfo } from './useQRLoginToken';
import { buildQRLoginDeviceLine } from './qrLoginDeviceCopy';
⋮----
type QRLoginNumberMatchStepProps = {
	numbers: [ string, string, string ];
	deviceInfo: QRLoginDeviceInfo | null;
	challengeExpiresAt: number;
	onChooseNumber: ( choice: string ) => Promise< void > | void;
	errorMessage?: ReactNode | null;
};
⋮----
const tick = () =>
⋮----
const handleChoose = async ( choice: string ) =>
⋮----
aria-label=
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/QRLoginRevokedPanel.tsx">
import React from '@wordpress/element';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
type QRLoginRevokedPanelProps = {
	onDone?: () => void;
};
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/QRLoginSuccessStep.tsx">
import React, { useState } from '@wordpress/element';
import { Button, Modal } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { useRevokeQRLoginAccess } from './useRevokeQRLoginAccess';
import type { QRLoginDeviceInfo } from './useQRLoginToken';
import { buildQRLoginDeviceLine } from './qrLoginDeviceCopy';
⋮----
type QRLoginSuccessStepProps = {
	apUuid: string | null;
	deviceInfo: QRLoginDeviceInfo | null;
};
⋮----
const openConfirmDialog = () =>
⋮----
const closeConfirmDialog = () =>
⋮----
const confirmRevoke = async () =>
⋮----
title=
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/QRLoginUnavailableCard.tsx">
import { Notice } from '@wordpress/components';
import { createInterpolateElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Link } from '@woocommerce/components';
import type { ReactNode } from 'react';
⋮----
import {
	QRLoginUnavailableReasons,
	type QRLoginUnavailableReason,
} from './useQRLoginAvailability';
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/SendMagicLinkButton.tsx">
import { Button } from '@wordpress/components';
import { Spinner } from '@woocommerce/components';
import { __ } from '@wordpress/i18n';
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/useJetpackPluginState.tsx">
import { useState, useEffect, useCallback } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { pluginsStore, useUser } from '@woocommerce/data';
⋮----
export type JetpackPluginStates =
	( typeof JetpackPluginStates )[ keyof typeof JetpackPluginStates ];
⋮----
export const useJetpackPluginState = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/useQRLoginAvailability.ts">
import { useState, useEffect } from '@wordpress/element';
import { WC_ADMIN_NAMESPACE } from '@woocommerce/data';
import apiFetch from '@wordpress/api-fetch';
⋮----
export type QRLoginUnavailableReason =
	( typeof QRLoginUnavailableReasons )[ keyof typeof QRLoginUnavailableReasons ];
⋮----
type QRLoginAvailabilityResponse = {
	available: boolean;
	reason: QRLoginUnavailableReason | null;
};
⋮----
export const useQRLoginAvailability = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/useQRLoginToken.tsx">
import {
	createInterpolateElement,
	useState,
	useCallback,
	useEffect,
	useRef,
} from '@wordpress/element';
import type { ReactNode } from 'react';
import { __ } from '@wordpress/i18n';
import { WC_ADMIN_NAMESPACE } from '@woocommerce/data';
import apiFetch from '@wordpress/api-fetch';
import { Link } from '@woocommerce/components';
⋮----
export type QRLoginTokenState =
	( typeof QRLoginTokenStates )[ keyof typeof QRLoginTokenStates ];
⋮----
export type QRLoginDeviceInfo = {
	os?: string;
	os_version?: string;
	model?: string;
	brand?: string;
	app_version?: string;
};
⋮----
type QRLoginTokenResponse = {
	qr_url: string;
	expires_at: number;
	ttl: number;
};
⋮----
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/useRevokeQRLoginAccess.ts">
import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { WC_ADMIN_NAMESPACE } from '@woocommerce/data';
import apiFetch from '@wordpress/api-fetch';
⋮----
export const useRevokeQRLoginAccess = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/components/useSendMagicLink.tsx">
import { useState, useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { WC_ADMIN_NAMESPACE } from '@woocommerce/data';
import { useDispatch } from '@wordpress/data';
import apiFetch from '@wordpress/api-fetch';
import { recordEvent } from '@woocommerce/tracks';
⋮----
export type SendMagicLinkStates =
	( typeof SendMagicLinkStates )[ keyof typeof SendMagicLinkStates ];
⋮----
export type MagicLinkResponse = {
	data: unknown;
	code: string;
	message: string;
} & Response;
⋮----
export const sendMagicLink = () =>
⋮----
export const useSendMagicLink = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/layouts/ModalContentLayoutWithTitle.tsx">
import { __ } from '@wordpress/i18n';
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/layouts/ModalIllustrationLayout.tsx">
import { __ } from '@wordpress/i18n';
import { Button, Icon } from '@wordpress/components';
import { closeSmall } from '@wordpress/icons';
⋮----
import Illustration from '../illustrations/intro-devices-desktop.png';
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/pages/EmailSentPage.tsx">
import interpolateComponents from '@automattic/interpolate-components';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
interface EmailSentProps {
	returnToSendLinkPage: () => void;
}
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/pages/index.tsx">

</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/pages/MobileAppLoginStepperPage.tsx">
import { useCallback, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
⋮----
import { ModalContentLayoutWithTitle } from '../layouts/ModalContentLayoutWithTitle';
import { SendMagicLinkStates } from '../components';
import { MobileAppLoginStepper } from '../components/MobileAppLoginStepper';
import type { QRLoginConsumedSnapshot } from '../components/QRDirectLoginCode';
⋮----
interface MobileAppLoginStepperPageProps {
	appInstalledClicked: boolean;
	isJetpackPluginInstalled: boolean;
	wordpressAccountEmailAddress: string | undefined;
	completeInstallationHandler: () => void;
	sendMagicLinkHandler: () => void;
	sendMagicLinkStatus: SendMagicLinkStates;
}
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/declaration.d.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/mobile-app-modal/index.tsx">
import { useState, useEffect, useCallback } from '@wordpress/element';
import { Guide } from '@wordpress/components';
import { useSearchParams } from 'react-router-dom';
import { updateQueryString } from '@woocommerce/navigation';
import { registerPlugin } from '@wordpress/plugins';
import { addFilter, removeFilter } from '@wordpress/hooks';
import { getAdminLink } from '@woocommerce/settings';
import { __ } from '@wordpress/i18n';
import { useDispatch } from '@wordpress/data';
import { optionsStore, onboardingStore } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { ModalIllustrationLayout } from './layouts/ModalIllustrationLayout';
import {
	useJetpackPluginState,
	JetpackPluginStates,
	useSendMagicLink,
	SendMagicLinkStates,
} from './components';
import { EmailSentPage, MobileAppLoginStepperPage } from './pages';
⋮----
import { SETUP_TASK_HELP_ITEMS_FILTER } from '../../activity-panel/panels/help';
⋮----
setHasSentEmail( false );
setIsRetryingMagicLinkSend( true );
recordEvent( 'magic_prompt_retry_send_signin_link' );
⋮----
const onFinish = () =>
⋮----
export const MobileAppHelpMenuEntryLoader = () =>
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/stats-overview/defaults.js">

</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/stats-overview/index.js">
const HeaderText = () => (
	<Text variant="title.small" size="20" lineHeight="28px">
		{ __( 'Stats overview', 'woocommerce' ) }
	</Text>
);
⋮----
export const StatsOverview = () =>
⋮----
const toggleStat = ( stat ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/stats-overview/install-jetpack-cta.js">
const getJetpackInstallText = ( jetpackInstallState ) =>
⋮----
export const JetpackCTA = ( {
	onClickInstall,
	onClickDismiss,
	isBusy,
	jetpackInstallState,
} ) =>
⋮----
export const InstallJetpackCTA = () =>
⋮----
const onClickInstall = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/stats-overview/stats-list.js">
export const StatsList = ( {
	stats,
	primaryData,
	secondaryData,
	primaryRequesting,
	secondaryRequesting,
	primaryError,
	secondaryError,
	query,
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/wcpay-feature-slot/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/wcpay-feature-slot/utils.tsx">
import { Slot, Fill } from '@wordpress/components';
import {
	createOrderedChildren,
	sortFillsByOrder,
} from '@woocommerce/components';
⋮----
export const WooHomescreenWCPayFeatureItem = ( {
	children,
	order = 1,
}: {
	children: React.ReactNode;
	order?: number;
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/wcpay-feature-slot/wcpay-feature-slot.tsx">
import { useSlot } from '@woocommerce/experimental';
import clsx from 'clsx';
⋮----
import {
	EXPERIMENTAL_WC_HOMESCREEN_WC_PAY_FEATURE_SLOT_NAME,
	WooHomescreenWCPayFeatureItem,
} from './utils';
⋮----
export const WooHomescreenWCPayFeature = ( {
	className,
}: {
	className: string;
} ) =>
⋮----
<div className=
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/column.js">
export const Column = (
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/index.tsx">
import { compose } from '@wordpress/compose';
import { withSelect } from '@wordpress/data';
import type { SelectFunction } from '@wordpress/data/build-types/types';
import { useEffect } from '@wordpress/element';
import { onboardingStore, withOnboardingHydration } from '@woocommerce/data';
import { getHistory, getNewPath, useQuery } from '@woocommerce/navigation';
⋮----
import Layout from './layout';
import { getAdminSetting } from '~/utils/admin-settings';
⋮----
type HomescreenProps = ReturnType< typeof withSelectHandler > & {
	hasFinishedResolution: boolean;
};
⋮----
const Homescreen = ( {
	profileItems: {
		completed: profilerCompleted,
		skipped: profilerSkipped,
	} = {},
	hasFinishedResolution,
}: HomescreenProps ) =>
⋮----
const withSelectHandler = ( select: SelectFunction ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/layout.js">
export const Layout = ( {
	defaultHomescreenLayout,
	query,
	hasTaskList,
	hasStaleTask,
	showingProgressHeader,
	isLoadingTaskLists,
} ) =>
⋮----
const renderTaskList = () =>
⋮----
const renderColumns = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/homescreen/utils.tsx">
import { isFeatureEnabled } from '~/utils/features';
⋮----
export const hasTwoColumnLayout = (
	userPrefLayout: string,
	defaultHomescreenLayout: string,
	isSetupTaskListActive: boolean
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/hooks/use-endpoint-dismiss.ts">
import apiFetch from '@wordpress/api-fetch';
import { useState } from '@wordpress/element';
⋮----
import { createNoticesFromResponse } from '../lib/notices';
import type { DismissState } from './use-option-dismiss';
⋮----
export const useEndpointDismiss = (
	path: string,
	initial: boolean
): DismissState =>
⋮----
const onDismiss = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/hooks/use-option-dismiss.ts">
import { useDispatch, useSelect } from '@wordpress/data';
import { optionsStore } from '@woocommerce/data';
⋮----
export type DismissState = {
	isDismissed: boolean;
	hasResolved: boolean;
	onDismiss: () => void;
};
⋮----
export const useOptionDismiss = ( optionName: string ): DismissState =>
⋮----
const onDismiss = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/hooks/use-tasklists-state.ts">
import { useSelect } from '@wordpress/data';
import type { CurriedSelectorsOf } from '@wordpress/data/build-types/types';
import {
	onboardingStore,
	ONBOARDING_STORE_NAME,
	getVisibleTasks,
	TaskListType,
} from '@woocommerce/data';
⋮----
import { getAdminSetting } from '~/utils/admin-settings';
⋮----
type Selectors = CurriedSelectorsOf< typeof onboardingStore >;
⋮----
function getThingsToDoNextCount( extendedTaskList: TaskListType | undefined )
⋮----
export const isTaskListVisible = ( taskListId: string )
⋮----
export const isTaskListCompleted = ( taskListId: string )
⋮----
export const isTaskListActive = ( taskListId: string )
⋮----
const getDefaultState = () =>
⋮----
const getSetupTaskListState = ( selectors: Selectors ) =>
⋮----
const getExtendedTaskListState = ( selectors: Selectors ) =>
⋮----
export const useTaskListsState = (
	{ setupTasklist, extendedTaskList } = {
		setupTasklist: true,
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/hooks/useFocusOnMount.js">
export default function useFocusOnMount( focusOnMount = 'firstElement' )
</file>

<file path="plugins/woocommerce/client/admin/client/hooks/useFocusOutside.js">
function isFocusNormalizedButton( eventTarget )
⋮----
export default function useFocusOutside( onFocusOutside )
</file>

<file path="plugins/woocommerce/client/admin/client/hooks/useIsScrolled.js">
function isAtBottom()
⋮----
export default function useIsScrolled()
⋮----
const updateIsScrolled = () =>
⋮----
const scrollListener = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/inbox-panel/dismiss-all-modal.js">
const DismissAllModal = (
⋮----
const dismissAllNotes = async () =>
⋮----
onClick: () =>
</file>

<file path="plugins/woocommerce/client/admin/client/inbox-panel/index.js">
const renderEmptyCard = () => (
	<ActivityCard
		className="woocommerce-empty-activity-card"
		title={ __( 'Your inbox is empty', 'woocommerce' ) }
		icon={ false }
	>
		{ __(
			'As things begin to happen in your store your inbox will start to fill up. ' +
				'You’ll see things like achievements, new feature announcements, extension recommendations and more!',
			'woocommerce'
		) }
	</ActivityCard>
);
⋮----
const onBodyLinkClick = ( note, innerLink ) =>
⋮----
const renderNotes = ( {
	hasNotes,
	isBatchUpdating,
	notes,
	onDismiss,
	onNoteActionClick,
	onNoteVisible,
	setShowDismissAllModal: onDismissAll,
	showHeader = true,
	loadMoreNotes,
	allNotesFetched,
	notesHaveResolved,
	unreadNotesCount,
} ) =>
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/inbox-panel/utils.js">
export function getUnreadNotesCount( notes, lastRead )
⋮----
export function hasValidNotes( notes )
⋮----
export const truncate = ( letters, limit, separator = ' ' ) =>
⋮----
/**
 * Truncates characters inside of an element.
 * Currently does not count <br> as a character even though it should.
 *
 * @param {HTMLElement} element HTML element
 * @param {number}      limit   number of characters to limit to
 */
const truncateElement = ( element, limit ) =>
⋮----
export const truncateRenderableHTML = ( originalHTML, limit ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/data/setup-payments-context.tsx">
import { createContext, useContext, useState } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { pluginsStore, paymentSettingsStore } from '@woocommerce/data';
import { getNewPath } from '@woocommerce/navigation';
⋮----
import { LYSPaymentsSteps } from '~/settings-payments/onboarding/providers/woopayments/steps';
import { OnboardingProvider } from '~/settings-payments/onboarding/providers/woopayments/data/onboarding-context';
import { isWooPayments } from '~/settings-payments/utils';
import { wooPaymentsExtensionSlug } from '~/settings-payments/constants';
⋮----
interface SetUpPaymentsContextType {
	isWooPaymentsActive: boolean;
	isWooPaymentsInstalled: boolean;
	wooPaymentsRecentlyActivated: boolean;
	setWooPaymentsRecentlyActivated: ( value: boolean ) => void;
}
⋮----
export const useSetUpPaymentsContext = ()
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hooks/use-launch-your-store.tsx">
import { useSelect } from '@wordpress/data';
import { optionsStore } from '@woocommerce/data';
⋮----
type Props = {
	enabled?: boolean;
};
⋮----
export const useLaunchYourStore = (
	{ enabled }: Props = {
		enabled: true,
	}
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/main-content/components/resizable-frame.jsx">
function calculateNewHeight( width, initialAspectRatio )
⋮----
const lerp = ( a, b, amount ) =>
⋮----
function ResizableFrame( {
	isFullWidth,
	isOversized,
	setIsOversized,
	isReady,
	children,
	defaultSize,
	innerContentStyle,
	isHandleVisibleByDefault = false,
} )
⋮----
const handleResizeStart = ( _event, _direction, ref ) =>
⋮----
const handleResize = ( _event, _direction, _ref, delta ) =>
⋮----
const handleResizeStop = ( _event, _direction, ref ) =>
⋮----
const handleResizableHandleKeyDown = ( event ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/main-content/pages/launch-store-success/actions.tsx">
import { DoneActorEvent } from 'xstate5';
import { TaskListType } from '@woocommerce/data';
import apiFetch from '@wordpress/api-fetch';
⋮----
import type { MainContentMachineContext } from '../../../main-content/xstate';
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/main-content/pages/launch-store-success/index.tsx">
import clsx from 'clsx';
import { __ } from '@wordpress/i18n';
import { getSetting } from '@woocommerce/settings';
import { recordEvent } from '@woocommerce/tracks';
import { createInterpolateElement, useState } from '@wordpress/element';
import { ConfettiAnimation } from '@woocommerce/components';
import { useCopyToClipboard } from '@wordpress/compose';
import { Button, Dashicon } from '@wordpress/components';
⋮----
import WooLogo from '~/core-profiler/components/navigation/woologo';
import type { MainContentComponentProps } from '../../xstate';
⋮----
export type CongratsProps = {
	hasCompleteSurvey: boolean;
	isWooExpress: boolean;
	completeSurvey: ( surveyData: SurveyData ) => void;
	children?: React.ReactNode;
	siteIsShowingCachedContent: boolean;
};
⋮----
export type SurveyData = {
	action: 'lys_experience';
	score: number | null;
	comments: string;
};
export type events =
	| {
			type: 'COMPLETE_SURVEY';
			payload: SurveyData;
	  }
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/main-content/pages/launch-store-success/services.tsx">
import { pluginsStore, onboardingStore } from '@woocommerce/data';
import { resolveSelect } from '@wordpress/data';
import { fromPromise } from 'xstate5';
import apiFetch from '@wordpress/api-fetch';
⋮----
type SurveyCompletedResponse = string | null;
⋮----
const fetchSurveyCompletedOption =
async (): Promise< SurveyCompletedResponse > =>
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/main-content/pages/launch-store-success/Survey.tsx">
import { Link } from '@woocommerce/components';
import { createInterpolateElement, useState } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
import { __ } from '@wordpress/i18n';
import { isInteger } from 'lodash';
import { closeSmall } from '@wordpress/icons';
import { CustomerFeedbackSimple } from '@woocommerce/customer-effort-score';
import { Button, TextareaControl, Icon } from '@wordpress/components';
⋮----
import { SurveyData } from '.';
import { isWooExpress } from '~/utils/is-woo-express';
⋮----
const sendData = () =>
⋮----
label=
⋮----
onClick=
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/main-content/pages/launch-store-success/WhatsNext.tsx">
import { __ } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
import { Button } from '@wordpress/components';
import { useMemo } from '@wordpress/element';
import type { TaskListType } from '@woocommerce/data';
⋮----
import { ADMIN_URL } from '~/utils/admin-settings';
⋮----
export type WhatsNextProps = {
	activePlugins: string[];
	allTasklists: TaskListType[];
};
⋮----
type Action = {
	title: string;
	description: string;
	link: string;
	linkText: string;
	trackEvent: string;
};
⋮----
export const getActionsList = ( {
	activePlugins,
	allTasklists,
}: WhatsNextProps ) =>
⋮----
const pick = ( action: Action, condition: boolean ) =>
⋮----
onClick=
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/main-content/pages/loading.tsx">
import { Spinner } from '@woocommerce/components';
⋮----
export const LoadingPage = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/main-content/pages/payments-content.tsx">
import { useCallback } from 'react';
import apiFetch from '@wordpress/api-fetch';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import React, { useEffect, useRef, useState } from '@wordpress/element';
import { pluginsStore, paymentSettingsStore } from '@woocommerce/data';
import { useDispatch, useSelect } from '@wordpress/data';
import { WooPaymentsMethodsLogos } from '@woocommerce/onboarding';
⋮----
import WooPaymentsOnboarding from '~/settings-payments/onboarding/providers/woopayments/components/onboarding';
import { useOnboardingContext } from '~/settings-payments/onboarding/providers/woopayments/data/onboarding-context';
import { WC_ASSET_URL } from '~/utils/admin-settings';
import { createNoticesFromResponse } from '~/lib/notices';
⋮----
import { useSetUpPaymentsContext } from '~/launch-your-store/data/setup-payments-context';
import {
	recordPaymentsEvent,
	isWooPayments,
	recordPaymentsOnboardingEvent,
} from '~/settings-payments/utils';
import {
	wooPaymentsExtensionSlug,
	wooPaymentsProviderId,
	wooPaymentsSuggestionId,
	wooPaymentsOnboardingSessionEntryLYS,
} from '~/settings-payments/constants';
⋮----
const validatePluginSlug = ( slug: unknown ): string | undefined =>
⋮----
export const PaymentsContent = (
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/main-content/pages/site-preview.tsx">
import clsx from 'clsx';
import { useState, useRef, useEffect } from '@wordpress/element';
import { Spinner } from '@woocommerce/components';
import { useResizeObserver } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';
import { __unstableMotion as motion } from '@wordpress/components';
⋮----
import { getAdminSetting } from '~/utils/admin-settings';
import ResizableFrame from '../components/resizable-frame';
import type { MainContentComponentProps } from '../xstate';
⋮----
export const SitePreviewPage = ( props: MainContentComponentProps ) =>
⋮----
const beforeUnloadHandler = () =>
⋮----
className=
⋮----
title=
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/main-content/xstate.tsx">
import { assertEvent, assign, fromCallback, fromPromise, setup } from 'xstate5';
import { getQuery, navigateTo } from '@woocommerce/navigation';
import { onboardingStore, type TaskListType } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { dispatch } from '@wordpress/data';
import { getSetting } from '@woocommerce/settings';
⋮----
import { LoadingPage } from './pages/loading';
import { SitePreviewPage } from './pages/site-preview';
import { PaymentsContent } from './pages/payments-content';
import type {
	LaunchYourStoreComponentProps,
	LaunchYourStoreQueryParams,
} from '..';
import {
	updateQueryParams,
	createQueryParamsListener,
} from '~/utils/xstate/url-handling';
import {
	services as congratsServices,
	events as congratsEvents,
	actions as congratsActions,
	LaunchYourStoreSuccess,
} from './pages/launch-store-success';
import { getSiteCachedStatus } from '../sidebar/xstate';
⋮----
export type MainContentMachineContext = {
	congratsScreen: {
		hasLoadedCongratsData: boolean;
		hasCompleteSurvey: boolean;
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/sidebar/components/mobile-toggle/index.tsx">
import React from 'react';
import { Button } from '@wordpress/components';
import { Icon, menu } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
⋮----
interface MobileSidebarToggleProps {
	onToggle: () => void;
}
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/sidebar/components/payments-icons/active-step.jsx">

</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/sidebar/components/payments-icons/completed-step.jsx">

</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/sidebar/components/step-placeholder/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/sidebar/components/step-placeholder/step-placeholder.tsx">
import React from 'react';
import {
	__unstableMotion as motion,
} from '@wordpress/components';
⋮----
interface StepPlaceholderProps {
	rows: number;
}
⋮----
export const StepPlaceholder = (
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/sidebar/components/icons.tsx">
import {
	percent,
	shipping,
	brush,
	tag,
	payment,
	check,
} from '@wordpress/icons';
⋮----
import CompletedStep from './payments-icons/completed-step';
import ActiveStep from './payments-icons/active-step';
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/sidebar/components/launch-store-hub.tsx">
import clsx from 'clsx';
import {
	createInterpolateElement,
	useEffect,
	useState,
} from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
⋮----
import SidebarNavigationItem from '@wordpress/edit-site/build-module/components/sidebar-navigation-item';
import {
	Button,
	__unstableMotion as motion,
	__experimentalItemGroup as ItemGroup,
	__experimentalHeading as Heading,
	ToggleControl,
	Notice,
	Spinner,
} from '@wordpress/components';
⋮----
import type { SidebarComponentProps } from '../xstate';
import { SidebarContainer } from './sidebar-container';
import { taskCompleteIcon } from './icons';
import { SiteHub } from '~/customize-store/site-hub';
import { CompletedTaskItem, IncompleteTaskItem } from '../tasklist';
⋮----
props.sendEventToSidebar( {
					type: 'POP_BROWSER_STACK',
				} );
⋮----
const launchStoreAction = () =>
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/sidebar/components/mobile-header.tsx">
import { Button } from '@wordpress/components';
import { chevronLeft } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
⋮----
import type { SidebarComponentProps } from '../xstate';
import MobileSidebarToggle from './mobile-toggle';
⋮----
const handleBackClick = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/sidebar/components/payments-mobile-header.tsx">
import { Button } from '@wordpress/components';
import { chevronLeft } from '@wordpress/icons';
import { __, sprintf } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import type { SidebarComponentProps } from '../xstate';
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
import { wooPaymentsOnboardingSessionEntryLYS } from '~/settings-payments/constants';
import { useSetUpPaymentsContext } from '~/launch-your-store/data/setup-payments-context';
import { useOnboardingContext } from '~/settings-payments/onboarding/providers/woopayments/data/onboarding-context';
⋮----
const handleBackClick = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/sidebar/components/payments-sidebar.tsx">
import React, { useState, useEffect } from 'react';
import { __, sprintf } from '@wordpress/i18n';
⋮----
import SidebarNavigationItem from '@wordpress/edit-site/build-module/components/sidebar-navigation-item';
import clsx from 'clsx';
import {
	Button,
	__experimentalItemGroup as ItemGroup,
	__unstableMotion as motion,
} from '@wordpress/components';
import { useOnboardingContext } from '~/settings-payments/onboarding/providers/woopayments/data/onboarding-context';
import { recordEvent } from '@woocommerce/tracks';
import type { TaskType } from '@woocommerce/data';
⋮----
import type { SidebarComponentProps } from '../xstate';
import { SidebarContainer } from './sidebar-container';
import { SiteHub } from '~/customize-store/site-hub';
import { taskIcons, taskCompleteIcon } from './icons';
import { StepPlaceholder } from './step-placeholder';
import { useSetUpPaymentsContext } from '~/launch-your-store/data/setup-payments-context';
import { WooPaymentsProviderOnboardingStep } from '~/settings-payments/onboarding/types';
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
import { wooPaymentsOnboardingSessionEntryLYS } from '~/settings-payments/constants';
import { getPaymentsTaskFromLysTasklist } from '../tasklist';
⋮----
const fetchPaymentsTask = async () =>
⋮----
const isStepCompleted = (
		step: WooPaymentsProviderOnboardingStep
): boolean =>
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/sidebar/components/sidebar-container.tsx">
import clsx from 'clsx';
import { isRTL, __ } from '@wordpress/i18n';
import { Icon, chevronRight, chevronLeft, close } from '@wordpress/icons';
⋮----
import SidebarButton from '@wordpress/edit-site/build-module/components/sidebar-button';
import {
	__experimentalHStack as HStack,
	__experimentalHeading as Heading,
	__experimentalVStack as VStack,
	Button,
} from '@wordpress/components';
import React from 'react';
⋮----
export type SidebarContainerProps = {
	title: React.ReactNode;
	description?: React.ReactNode;
	footer?: React.ReactNode;
	children: React.ReactNode;
	onMobileClose?: () => void;
};
export const SidebarContainer = ( {
	title,
	description,
	footer,
	children,
	onMobileClose,
}: SidebarContainerProps ) =>
⋮----
const hasOnClick = (
		el: React.ReactNode
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/sidebar/tasklist.tsx">
import { onboardingStore, TaskType } from '@woocommerce/data';
import { getNewPath, navigateTo } from '@woocommerce/navigation';
import { resolveSelect } from '@wordpress/data';
import { applyFilters } from '@wordpress/hooks';
import clsx from 'clsx';
⋮----
import SidebarNavigationItem from '@wordpress/edit-site/build-module/components/sidebar-navigation-item';
⋮----
import { taskCompleteIcon, taskIcons } from './components/icons';
import { recordEvent } from '@woocommerce/tracks';
import {
	accessTaskReferralStorage,
	createStorageUtils,
} from '@woocommerce/onboarding';
import { getAdminLink } from '@woocommerce/settings';
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
import { wooPaymentsOnboardingSessionEntryLYS } from '~/settings-payments/constants';
⋮----
export const getLysTasklist = async () =>
⋮----
export const getPaymentsTaskFromLysTasklist = async (): Promise<
	TaskType | undefined
> => {
	try {
		const tasklist = await getLysTasklist();
⋮----
export function taskClickedAction( event: {
	type: 'TASK_CLICKED';
	task: TaskType;
} )
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/sidebar/xstate.tsx">
import {
	ActorRefFrom,
	sendTo,
	setup,
	fromCallback,
	fromPromise,
	assign,
	spawnChild,
	enqueueActions,
} from 'xstate5';
import clsx from 'clsx';
import { getQuery, navigateTo } from '@woocommerce/navigation';
import {
	optionsStore,
	settingsStore,
	TaskListType,
	TaskType,
	PaymentGateway,
	paymentGatewaysStore,
} from '@woocommerce/data';
import { dispatch, resolveSelect } from '@wordpress/data';
import { recordEvent } from '@woocommerce/tracks';
import apiFetch from '@wordpress/api-fetch';
⋮----
import { LaunchYourStoreHubSidebar } from './components/launch-store-hub';
import { PaymentsSidebar } from './components/payments-sidebar';
import { LaunchStoreHubMobileHeader } from './components/mobile-header';
import { PaymentsMobileHeader } from './components/payments-mobile-header';
import type {
	LaunchYourStoreComponentProps,
... (88 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/hub/index.tsx">
import { useMachine } from '@xstate5/react';
import { useEffect, useState } from 'react';
import { useDispatch } from '@wordpress/data';
import { onboardingStore } from '@woocommerce/data';
import clsx from 'clsx';
⋮----
import { useFullScreen } from '~/utils';
import { useComponentFromXStateService } from '~/utils/xstate/useComponentFromService';
import { useMobileHeaderFromXStateService } from '~/utils/xstate/useMobileHeaderFromService';
⋮----
import {
	SidebarMachineEvents,
	sidebarMachine,
	SidebarComponentProps,
	SidebarContainer,
} from './sidebar/xstate';
import {
	MainContentMachineEvents,
	mainContentMachine,
	MainContentComponentProps,
	MainContentContainer,
} from './main-content/xstate';
import { useXStateInspect } from '~/xstate';
export type LaunchYourStoreComponentProps = {
	sendEventToSidebar: ( arg0: SidebarMachineEvents ) => void;
	sendEventToMainContent: ( arg0: MainContentMachineEvents ) => void;
	className?: string;
};
import { SetUpPaymentsProvider } from '../data/setup-payments-context';
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/settings/components/confirmation-modal.jsx">
export const ConfirmationModal = ( {
	formRef,
	saveButtonRef,
	currentSetting,
} ) =>
⋮----
const handleFormSubmit = ( event ) =>
⋮----
const cancelSubmit = () =>
⋮----
const confirmSubmit = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/settings/slotfill.js">
const SiteVisibility = () =>
⋮----
const getPrivateLink = () =>
⋮----
const SiteVisibilitySlotFill = () =>
⋮----
export const registerSiteVisibilitySlotFill = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/status/index.tsx">
import { SiteVisibilityTour } from '../tour';
import { useSiteVisibilityTour } from '../tour/use-site-visibility-tour';
⋮----
export const LaunchYourStoreStatus = () =>
⋮----
onClose();
setShowTour( false );
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/tour/index.tsx">
import { __ } from '@wordpress/i18n';
import { TourKit } from '@woocommerce/components';
import { createInterpolateElement } from '@wordpress/element';
⋮----
export const SiteVisibilityTour = (
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/tour/use-site-visibility-tour.tsx">
import { optionsStore, useUserPreferences } from '@woocommerce/data';
import { useSelect } from '@wordpress/data';
import { useState } from 'react';
⋮----
export const useSiteVisibilityTour = () =>
⋮----
const onClose = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/constants.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/launch-your-store/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/layout/footer/footer.tsx">
import { WC_FOOTER_SLOT_NAME, WooFooterItem } from '@woocommerce/admin-layout';
import { useSlot } from '@woocommerce/experimental';
import clsx from 'clsx';
⋮----
import useIsScrolled from '~/hooks/useIsScrolled';
⋮----
export const Footer = () =>
⋮----
className=
</file>

<file path="plugins/woocommerce/client/admin/client/layout/footer/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/layout/hooks/use-page-classes.ts">
import { useEffect } from '@wordpress/element';
import { Params } from 'react-router-dom';
⋮----
export type Page = {
	container?: JSX.Element;
	path?: string;
	breadcrumbs:
		| string[]
		| ( ( {
				match,
		  }: {
				match: {
					params: Params;
					url?: string;
				};
		  } ) => string[] );
	wpOpenMenu?: string;
	navArgs?: {
		id: string;
	};
	capability?: string;
	layout?: {
		header: boolean;
		footer: boolean;
		showNotices: boolean;
		showStoreAlerts: boolean;
		showPluginArea: boolean;
	};
};
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/layout/store-alerts/index.js">
function getUnactionedVisibleAlerts( alerts )
⋮----
export const StoreAlerts = () =>
⋮----
function previousAlert( event )
⋮----
function nextAlert( event )
⋮----
function renderActions( alert )
⋮----
const setReminderDate = ( snoozeOption ) =>
⋮----
const onDismiss = async ( note ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/layout/store-alerts/placeholder.js">
class StoreAlertsPlaceholder extends Component
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/layout/transient-notices/snackbar/index.js">
function useSpokenMessage( message, politeness )
⋮----
function Snackbar(
	{
		className,
		children,
		spokenMessage = children,
		politeness = 'polite',
		actions = [],
		onRemove = noop,
		icon = null,
		explicitDismiss = false,
		onDismiss = null,
		__unstableHTML = false,
	},
	ref
)
⋮----
function dismissMe( event )
⋮----
function onActionClick( event, onClick )
</file>

<file path="plugins/woocommerce/client/admin/client/layout/transient-notices/snackbar/list.js">
function SnackbarList( {
	notices,
	className,
	children,
	onRemove = noop,
	onRemove2 = noop,
} )
⋮----
keys: ( notice )
⋮----
enter: ( item )
leave: () => async ( next ) =>
⋮----
const removeNotice = ( notice ) => () =>
</file>

<file path="plugins/woocommerce/client/admin/client/layout/transient-notices/index.js">
export function TransientNotices( props )
⋮----
const getCurrentUserNotices = () =>
⋮----
const dequeueNotice = ( id ) =>
⋮----
onDismiss: () =>
⋮----
const getNotices = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/layout/controller.js">
export const getPages = ( reports = [] ) =>
⋮----
breadcrumbs: (
⋮----
export function usePages()
⋮----
function usePrevious( value )
⋮----
export const Controller = (
⋮----
function getFallback()
⋮----
export function updateLinkHref(
	item,
	nextQuery,
	excludedScreens,
	excludedScreensUrlUpdate = []
)
⋮----
item.onclick = ( e ) =>
⋮----
const getCustomSVGMenuItems = () =>
⋮----
submenu.style.marginTop = ''; // Reset margin-top
</file>

<file path="plugins/woocommerce/client/admin/client/layout/embed.tsx">
import { compose } from '@wordpress/compose';
import { withPluginsHydration, withOptionsHydration } from '@woocommerce/data';
⋮----
import { identity, isFunction } from 'lodash';
import { SlotFillProvider } from '@wordpress/components';
import { useEffect } from '@wordpress/element';
import { CustomerEffortScoreModalContainer } from '@woocommerce/customer-effort-score';
import { getQuery } from '@woocommerce/navigation';
import { recordPageView } from '@woocommerce/tracks';
import {
	LayoutContextProvider,
	getLayoutContextValue,
} from '@woocommerce/admin-layout';
import { PluginArea } from '@wordpress/plugins';
⋮----
import { EmbedHeader } from '../header/embed';
import { TransientNotices } from './transient-notices';
import { usePageClasses } from './hooks/use-page-classes';
import { getAdminSetting } from '~/utils/admin-settings';
import { Footer } from './footer';
⋮----
<LayoutContextProvider value=
⋮----
? breadcrumbs(
</file>

<file path="plugins/woocommerce/client/admin/client/layout/index.tsx">
import { compose } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import {
	unstable_HistoryRouter as HistoryRouter,
	Route,
	Routes,
	useLocation,
	useMatch,
	useParams,
} from 'react-router-dom';
import { identity, isFunction } from 'lodash';
import {
	getHistory,
	getQuery,
	getNewPath,
	navigateTo,
} from '@woocommerce/navigation';
import {
	pluginsStore,
	useUser,
	withPluginsHydration,
	withOptionsHydration,
} from '@woocommerce/data';
⋮----
import { SlotFillProvider } from '@wordpress/components';
import { useEffect } from '@wordpress/element';
import {
	CustomerEffortScoreModalContainer,
	triggerExitPageCesSurvey,
} from '@woocommerce/customer-effort-score';
... (29 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/layout/NoMatch.tsx">
import { useState, useEffect } from '@wordpress/element';
⋮----
import { __ } from '@wordpress/i18n';
import { Card, CardBody } from '@wordpress/components';
import { Spinner } from '@woocommerce/components';
import { Text } from '@woocommerce/experimental';
import { WooHeaderPageTitle } from '@woocommerce/admin-layout';
</file>

<file path="plugins/woocommerce/client/admin/client/layout/notices.js">
class Notices extends Component
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/layout/shared.tsx">
import { lazy, Suspense } from '@wordpress/element';
⋮----
import Notices from './notices';
⋮----
export const PrimaryLayout = ( {
	children,
	showStoreAlerts = true,
	showNotices = true,
}: {
	children?: React.ReactNode;
	showStoreAlerts?: boolean;
	showNotices?: boolean;
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/CardHeaderDescription/CardHeaderDescription.tsx">
export const CardHeaderDescription = ( {
	children,
}: React.PropsWithChildren ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/CardHeaderDescription/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/CardHeaderTitle/CardHeaderTitle.tsx">
export const CardHeaderTitle = (
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/CardHeaderTitle/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/CenteredSpinner/CenteredSpinner.tsx">
import { Spinner } from '@woocommerce/components';
⋮----
export const CenteredSpinner = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/CenteredSpinner/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/CollapsibleCard/CollapsibleCard.tsx">
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import {
	Card,
	CardBody,
	CardDivider,
	CardHeader,
	CardFooter,
	Button,
} from '@wordpress/components';
import { chevronUp, chevronDown } from '@wordpress/icons';
import clsx from 'clsx';
⋮----
import { CardHeaderTitle } from '~/marketing/components';
⋮----
type CollapsibleCardProps = {
	header: string;
	children: React.ReactNode;
	className?: string;
	footer?: React.ReactNode;
	initialCollapsed?: boolean;
};
⋮----
const handleClick = () =>
⋮----
<Card className=
⋮----
collapsed
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/CollapsibleCard/index.tsx">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/CreateNewCampaignModal/CreateNewCampaignModal.tsx">
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import {
	Button,
	Modal,
	Icon,
	Flex,
	FlexBlock,
	FlexItem,
} from '@wordpress/components';
import { chevronUp, chevronDown, external } from '@wordpress/icons';
import clsx from 'clsx';
⋮----
import {
	useRecommendedChannels,
	useCampaignTypes,
	useRegisteredChannels,
	useInstalledPluginsWithoutChannels,
} from '~/marketing/hooks';
import { SmartPluginCardBody } from '~/marketing/components';
⋮----
const isExternalURL = ( url: string )
⋮----
type CreateCampaignModalProps = Omit<
	React.ComponentProps< typeof Modal >,
	'title' | 'children'
>;
⋮----
const onInstalledAndActivated = ( pluginSlug: string ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/CreateNewCampaignModal/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/PluginCardBody/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/PluginCardBody/PluginCardBody.tsx">
import clsx from 'clsx';
⋮----
import { CardBody } from '~/marketing/components';
⋮----
type PluginCardBodyProps = {
	className?: string;
	icon: JSX.Element;
	name: string;
	pills?: Array< JSX.Element >;
	description: React.ReactNode;
	button?: JSX.Element;
};
⋮----
export const PluginCardBody = ( {
	className,
	icon,
	name,
	pills,
	description,
	button,
}: PluginCardBodyProps ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/PluginCardBody/SmartPluginCardBody.tsx">
import { useState } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import { Button } from '@wordpress/components';
import { Pill } from '@woocommerce/components';
import { __ } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
import { pluginsStore } from '@woocommerce/data';
⋮----
import { PluginCardBody } from '~/marketing/components';
import { RecommendedPlugin } from '~/marketing/types';
import { getRecommendationSource } from '~/marketing/utils';
import { getInAppPurchaseUrl } from '~/lib/in-app-purchase';
import { createNoticesFromResponse } from '~/lib/notices';
⋮----
type SmartPluginCardBodyProps = {
	plugin: RecommendedPlugin;
	onInstalledAndActivated?: ( pluginSlug: string ) => void;
};
⋮----
const installAndActivate = async () =>
⋮----
href=
⋮----
button=
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/amazon-ebay.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/automatewoo-alt.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/automatewoo.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/blank.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/creative-mail.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/currency-dollar.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/facebook.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/gift.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/google.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/hubspot.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/jetpack-crm.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/klaviyo.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/link.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/mailchimp.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/mailpoet.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/people.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/pinterest.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/salesforce.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/tiktok.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/tip.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/trustpilot.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/vimeo.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/library/zapier.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/icons/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/index.js">
class ProductIcon extends Component
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/product-icon/README.md">
Product Icon
===

This component creates simple styled `<img />` element for displaying product icons.

## Usage

```jsx
<ProductIcon src={ icon } />
```

### Props

Name | Type | Default | Description
--- | --- | --- | ---
`src` | String | `null` | (required) URL for icon image
`className` | String | `null` | Additional class name to style the component
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/components/ReadBlogMessage.js">
const ReadBlogMessage = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/coupons/card/index.js">
const Card = ( props ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/coupons/card/README.md">
Card
===

This component is a simple wrapper around the Card component from `@wordpress/components`. It supports `title` and `description` props to be displayed in the card header.

## Usage

```jsx
<Card
  title="Title"
  description="Description goes here."
  className="className"
>
  <div>
    Any card content goes here.
  </div>
</Card>
```
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/coupons/knowledge-base/index.js">
const KnowledgeBase = ( {
	posts,
	isLoading,
	error,
	title = __( 'WooCommerce knowledge base', 'woocommerce' ),
	description = __(
		'Learn the ins and outs of successful marketing from the experts at WooCommerce.',
		'woocommerce'
	),
	category,
} ) =>
⋮----
const onPaginationPageChange = ( newPage ) =>
⋮----
const onPostClick = ( post ) =>
⋮----
const getCurrentSlide = () =>
⋮----
const renderEmpty = () =>
⋮----
const renderError = () =>
⋮----
const renderPosts = () =>
⋮----
const renderPlaceholder = () =>
⋮----
const renderCardBody = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/coupons/knowledge-base/placeholder.js">
const KnowledgebaseCardPostPlaceholder = ( index ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/coupons/recommended-extensions/index.js">
const RecommendedExtensions = ( {
	extensions,
	isLoading,
	title = __( 'Recommended extensions', 'woocommerce' ),
	description = __(
		'Great marketing requires the right tools. Take your marketing to the next level with our recommended marketing extensions.',
		'woocommerce'
	),
	category,
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/coupons/recommended-extensions/item.js">
const RecommendedExtensionsItem = ( {
	title,
	description,
	url,
	product,
	category,
} ) =>
⋮----
const onProductClick = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/coupons/recommended-extensions/placeholder.js">
const RecommendedExtensionsPlaceholder = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/coupons/slider/index.js">
const Slider = (
⋮----
const updateSliderHeight = () =>
⋮----
const onEnter = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/coupons/index.js">
const CouponsOverview = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data/action-types.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data/actions.js">
export function receiveInstalledPlugins( plugins )
⋮----
export function receiveActivatingPlugin( pluginSlug )
⋮----
export function removeActivatingPlugin( pluginSlug )
⋮----
export function receiveRecommendedPlugins( plugins, category )
⋮----
export function receiveMiscRecommendations( miscRecommendations )
⋮----
export function receiveBlogPosts( posts, category )
⋮----
export function handleFetchError( error, message )
⋮----
export function setError( category, error )
⋮----
export function* loadInstalledPluginsAfterActivation( activatedPluginSlug )
⋮----
export function* activateInstalledPlugin( pluginSlug )
⋮----
export function* installAndActivateRecommendedPlugin(
	recommendedPluginSlug,
	category
)
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data/constants.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data/reducer.js">
const reducer = ( state = DEFAULT_STATE, action ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data/resolvers.js">
export function* getRecommendedPlugins( category )
⋮----
export function* getMiscRecommendations()
⋮----
export function* getBlogPosts( category )
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data/selectors.js">
export function getInstalledPlugins( state )
⋮----
export function getActivatingPlugins( state )
⋮----
export function getRecommendedPlugins( state, category )
⋮----
export function getMiscRecommendations( state )
⋮----
export function getBlogPosts( state, category )
⋮----
export function getBlogPostsError( state, category )
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data-multichannel/action-types.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data-multichannel/actions.ts">
import { TYPES } from './action-types';
import { isApiFetchError } from './guards';
import {
	ApiFetchError,
	RegisteredChannel,
	RecommendedChannel,
	Campaign,
	CampaignType,
} from './types';
⋮----
export const receiveRegisteredChannelsSuccess = (
	channels: Array< RegisteredChannel >
) =>
⋮----
export const receiveRegisteredChannelsError = ( error: ApiFetchError ) =>
⋮----
export const receiveRecommendedChannelsSuccess = (
	channels: Array< RecommendedChannel >
) =>
⋮----
export const receiveRecommendedChannelsError = ( error: ApiFetchError ) =>
⋮----
type CampaignsSuccessResponse = {
	payload: Array< Campaign >;
	error: false;
	meta: {
		page: number;
		perPage: number;
		total?: number;
	};
... (29 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data-multichannel/constants.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data-multichannel/controls.ts">
import { controls as dataControls } from '@wordpress/data-controls';
import { AnyAction } from 'redux';
⋮----
export const awaitResponseJson = (
	response: Response
): AnyAction &
⋮----
AWAIT_RESPONSE_JSON( action: AnyAction )
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data-multichannel/guards.ts">
import { ApiFetchError } from './types';
⋮----
export const isObject = ( obj: unknown ): obj is Record< string, unknown > =>
⋮----
export const isApiFetchError = ( obj: unknown ): obj is ApiFetchError =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data-multichannel/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { Reducer, AnyAction } from 'redux';
⋮----
import { State } from './types';
import { STORE_KEY } from './constants';
import { reducer } from './reducer';
import controls from './controls';
⋮----
interface StoreRegistry {
		[ STORE_KEY ]: typeof store;
	}
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data-multichannel/reducer.ts">
import type { Reducer } from 'redux';
⋮----
import { State } from './types';
import { Action } from './actions';
import { TYPES } from './action-types';
⋮----
export const reducer: Reducer< State, Action > = (
	state = initialState,
	action
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data-multichannel/resolvers.ts">
import { apiFetch } from '@wordpress/data-controls';
⋮----
import {
	receiveRegisteredChannelsSuccess,
	receiveRegisteredChannelsError,
	receiveRecommendedChannelsSuccess,
	receiveRecommendedChannelsError,
	receiveCampaigns,
	receiveCampaignTypes,
} from './actions';
import { awaitResponseJson } from './controls';
import {
	RegisteredChannel,
	RecommendedChannel,
	Campaign,
	CampaignType,
	ApiFetchError,
} from './types';
import { API_NAMESPACE } from './constants';
import { isApiFetchError } from './guards';
⋮----
const getTotalFromResponse = ( response: Response ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data-multichannel/selectors.ts">
import type { WPDataSelector, WPDataSelectors } from '@woocommerce/data';
⋮----
import { State } from './types';
⋮----
export const getRegisteredChannels = ( state: State ) =>
⋮----
export const getRecommendedChannels = ( state: State ) =>
⋮----
export const getCampaigns = ( state: State, page: number, perPage: number ) =>
⋮----
export const getCampaignTypes = ( state: State ) =>
⋮----
export type Selectors = {
	getRegisteredChannels: WPDataSelector< typeof getRegisteredChannels >;
	getRecommendedChannels: WPDataSelector< typeof getRecommendedChannels >;
	getCampaigns: WPDataSelector< typeof getCampaigns >;
	getCampaignTypes: WPDataSelector< typeof getCampaignTypes >;
} & WPDataSelectors;
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/data-multichannel/types.ts">
export type ApiFetchError = {
	code: string;
	data: {
		status: number;
	};
	message: string;
};
⋮----
export type RegisteredChannel = {
	slug: string;
	is_setup_completed: boolean;
	settings_url: string;
	name: string;
	description: string;
	product_listings_status: string;
	errors_count: number;
	icon: string;
};
⋮----
export type RegisteredChannelsState = {
	data?: Array< RegisteredChannel >;
	error?: ApiFetchError;
};
⋮----
type Subcategory = {
	slug: string;
	name: string;
};
⋮----
type Tag = {
... (77 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/hooks/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/hooks/useCampaigns.ts">
import { useSelect } from '@wordpress/data';
⋮----
import { Campaign } from '~/marketing/types';
import { STORE_KEY } from '~/marketing/data-multichannel/constants';
import {
	Campaign as APICampaign,
	ApiFetchError,
} from '~/marketing/data-multichannel/types';
import { useRegisteredChannels } from '~/marketing/hooks';
⋮----
type UseCampaignsType = {
	loading: boolean;
	data?: Array< Campaign >;
	error?: ApiFetchError;
	meta?: {
		total?: number;
	};
};
⋮----
export const useCampaigns = ( page = 1, perPage = 5 ): UseCampaignsType =>
⋮----
const convert = ( campaign: APICampaign ): Campaign =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/hooks/useCampaignTypes.ts">
import { useDispatch, useSelect } from '@wordpress/data';
import { useCallback } from '@wordpress/element';
⋮----
import { STORE_KEY } from '~/marketing/data-multichannel/constants';
import {
	CampaignType as APICampaignType,
	ApiFetchError,
} from '~/marketing/data-multichannel/types';
import { CampaignType } from '~/marketing/types/CampaignType';
⋮----
type UseCampaignTypes = {
	loading: boolean;
	data?: Array< CampaignType >;
	error?: ApiFetchError;
	refetch: () => void;
};
⋮----
const convert = ( campaignType: APICampaignType ): CampaignType =>
⋮----
export const useCampaignTypes = (): UseCampaignTypes =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/hooks/useInstalledPluginsWithoutChannels.ts">
import { useSelect, useDispatch } from '@wordpress/data';
import { chain } from 'lodash';
⋮----
import { store as marketingStore } from '~/marketing/data';
import { InstalledPlugin } from '~/marketing/types';
import { useRecommendedChannels } from './useRecommendedChannels';
import { useRegisteredChannels } from './useRegisteredChannels';
⋮----
export type UseInstalledPluginsWithoutChannels = {
	data: InstalledPlugin[];
	activatingPlugins: string[];
	activateInstalledPlugin: ( slug: string ) => void;
	loadInstalledPluginsAfterActivation: ( slug: string ) => void;
};
⋮----
export const useInstalledPluginsWithoutChannels =
(): UseInstalledPluginsWithoutChannels =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/hooks/useIntroductionBanner.ts">
import { useDispatch, useSelect } from '@wordpress/data';
import { optionsStore } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
⋮----
type UseIntroductionBanner = {
	loading: boolean;
	isIntroductionBannerDismissed: boolean;
	dismissIntroductionBanner: () => void;
};
⋮----
export const useIntroductionBanner = (): UseIntroductionBanner =>
⋮----
const dismissIntroductionBanner = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/hooks/useRecommendedChannels.ts">
import { useSelect } from '@wordpress/data';
import { pluginsStore } from '@woocommerce/data';
import { differenceWith } from 'lodash';
⋮----
import { STORE_KEY } from '~/marketing/data-multichannel/constants';
import type { RecommendedChannel } from '~/marketing/data-multichannel/types';
⋮----
type UseRecommendedChannels = {
	loading: boolean;
	data?: Array< RecommendedChannel >;
};
⋮----
export const useRecommendedChannels = (): UseRecommendedChannels =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/hooks/useRegisteredChannels.ts">
import { useDispatch, useSelect } from '@wordpress/data';
import { __, sprintf } from '@wordpress/i18n';
import { useCallback } from '@wordpress/element';
⋮----
import { RegisteredChannel, SyncStatusType } from '~/marketing/types';
import { STORE_KEY } from '~/marketing/data-multichannel/constants';
import {
	ApiFetchError,
	RegisteredChannel as APIRegisteredChannel,
} from '~/marketing/data-multichannel/types';
⋮----
type UseRegisteredChannels = {
	loading: boolean;
	data?: Array< RegisteredChannel >;
	error?: ApiFetchError;
	refetch: () => void;
};
⋮----
const convert = ( data: APIRegisteredChannel ): RegisteredChannel =>
⋮----
export const useRegisteredChannels = (): UseRegisteredChannels =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/Campaigns/Campaigns.tsx">
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import {
	Button,
	Card,
	CardHeader,
	CardBody,
	CardFooter,
	Flex,
	FlexItem,
	FlexBlock,
} from '@wordpress/components';
import { Icon, megaphone, cancelCircleFilled } from '@wordpress/icons';
import {
	Pagination,
	Table,
	TablePlaceholder,
	Link,
} from '@woocommerce/components';
import { isWCAdmin } from '@woocommerce/navigation';
⋮----
import {
	CardHeaderTitle,
	CreateNewCampaignModal,
} from '~/marketing/components';
import { useCampaignTypes, useCampaigns } from '~/marketing/hooks';
⋮----
isWCAdmin(
⋮----
onRequestClose=
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/Campaigns/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/Channels/Channels.tsx">
import {
	Fragment,
	useState,
	forwardRef,
	useImperativeHandle,
	useRef,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import {
	Card,
	CardHeader,
	CardBody,
	CardDivider,
	Button,
	Icon,
} from '@wordpress/components';
import { chevronUp, chevronDown } from '@wordpress/icons';
⋮----
import { RecommendedChannel } from '~/marketing/data-multichannel/types';
import {
	CardHeaderTitle,
	CardHeaderDescription,
	SmartPluginCardBody,
} from '~/marketing/components';
import { RegisteredChannel } from '~/marketing/types';
import { RegisteredChannelCardBody } from './RegisteredChannelCardBody';
⋮----
type ChannelsProps = {
	registeredChannels: Array< RegisteredChannel >;
	recommendedChannels: Array< RecommendedChannel >;
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/Channels/iconSize.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/Channels/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/Channels/IssueStatus.tsx">
import GridiconNotice from 'gridicons/dist/notice';
import clsx from 'clsx';
⋮----
import { RegisteredChannel } from '~/marketing/types';
import { iconSize } from './iconSize';
⋮----
type IssueStatusPropsType = {
	registeredChannel: RegisteredChannel;
};
⋮----
export const IssueStatus = (
⋮----
className=
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/Channels/RegisteredChannelCardBody.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
import { PluginCardBody } from '~/marketing/components';
import { RegisteredChannel } from '~/marketing/types';
import { SyncStatus } from './SyncStatus';
import { IssueStatus } from './IssueStatus';
⋮----
type RegisteredChannelCardBodyProps = {
	registeredChannel: RegisteredChannel;
};
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/Channels/SyncStatus.tsx">
import { __ } from '@wordpress/i18n';
import GridiconCheckmarkCircle from 'gridicons/dist/checkmark-circle';
import GridiconSync from 'gridicons/dist/sync';
import GridiconNotice from 'gridicons/dist/notice';
import clsx from 'clsx';
⋮----
import { SyncStatusType } from '~/marketing/types';
import { iconSize } from './iconSize';
⋮----
type SyncStatusPropsType = {
	status: SyncStatusType;
};
⋮----
<div className=
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/DiscoverTools/DiscoverTools.tsx">
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { Icon, trendingUp } from '@wordpress/icons';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import {
	CollapsibleCard,
	CardBody,
	CenteredSpinner,
} from '~/marketing/components';
import { useRecommendedPluginsWithoutChannels } from './useRecommendedPluginsWithoutChannels';
import { PluginsTabPanel } from './PluginsTabPanel';
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/DiscoverTools/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/DiscoverTools/PluginsTabPanel.tsx">
import { Fragment, useState } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { TabPanel, Button } from '@wordpress/components';
import { recordEvent } from '@woocommerce/tracks';
import { Pill } from '@woocommerce/components';
import { pluginsStore } from '@woocommerce/data';
import { flatMapDeep, uniqBy } from 'lodash';
⋮----
import { CardDivider, PluginCardBody } from '~/marketing/components';
import { useInstalledPluginsWithoutChannels } from '~/marketing/hooks';
import { RecommendedPlugin } from '~/marketing/types';
import { getRecommendationSource } from '~/marketing/utils/getRecommendationSource';
import { getInAppPurchaseUrl } from '~/lib/in-app-purchase';
import { createNoticesFromResponse } from '~/lib/notices';
⋮----
const getTabs = ( plugins: RecommendedPlugin[] ) =>
⋮----
type PluginsTabPanelType = {
	isLoading: boolean;
	plugins: RecommendedPlugin[];
	onInstallAndActivate: ( pluginSlug: string ) => void;
};
⋮----
const installAndActivate = async ( plugin: RecommendedPlugin ) =>
⋮----
<TabPanel tabs=
⋮----
href=
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/DiscoverTools/useRecommendedPluginsWithoutChannels.ts">
import { useSelect, useDispatch } from '@wordpress/data';
import { differenceWith } from 'lodash';
⋮----
import { store as marketingStore } from '~/marketing/data';
import { useRecommendedChannels } from '~/marketing/hooks';
import { RecommendedPlugin } from '~/marketing/types';
⋮----
type UseRecommendedPluginsWithoutChannels = {
	isInitializing: boolean;
	isLoading: boolean;
	data: RecommendedPlugin[];
	installAndActivate: ( slug: string ) => void;
};
⋮----
export const useRecommendedPluginsWithoutChannels =
(): UseRecommendedPluginsWithoutChannels =>
⋮----
const installAndActivate = ( slug: string ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/InstalledExtensions/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/InstalledExtensions/InstalledExtensions.tsx">
import { Fragment } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import {
	CollapsibleCard,
	CardDivider,
	ProductIcon,
	PluginCardBody,
} from '~/marketing/components';
import { InstalledPlugin } from '~/marketing/types';
import { useInstalledPluginsWithoutChannels } from '~/marketing/hooks';
⋮----
onClick=
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/IntroductionBanner/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/IntroductionBanner/IntroductionBanner.tsx">
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import { Card, Flex, FlexItem, FlexBlock, Button } from '@wordpress/components';
import { Icon, trendingUp, megaphone, closeSmall } from '@wordpress/icons';
⋮----
import { CreateNewCampaignModal } from '~/marketing/components';
import {
	useRegisteredChannels,
	useRecommendedChannels,
	useCampaignTypes,
} from '~/marketing/hooks';
⋮----
import wooIconUrl from './woo.svg';
import illustrationUrl from './illustration.svg';
⋮----
type IntroductionBannerProps = {
	onDismissClick: () => void;
	onAddChannelsClick: () => void;
};
⋮----
onRequestClose=
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/LearnMarketing/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/LearnMarketing/LearnMarketing.tsx">
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Pagination, EmptyContent } from '@woocommerce/components';
⋮----
import { CollapsibleCard, ReadBlogMessage } from '~/marketing/components';
import { PlaceholderPostTile } from './PlaceholderPostTile';
import { PostTile } from './PostTile';
import { useBlogPosts } from './useBlogPosts';
⋮----
if ( isLoading )
⋮----
title=
⋮----
footer=
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/LearnMarketing/PlaceholderPostTile.tsx">
export const PlaceholderPostTile = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/LearnMarketing/PostTile.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { Post } from './types';
⋮----
type PostTileProps = {
	post: Post;
};
⋮----
export const PostTile = (
⋮----
recordEvent( 'marketing_knowledge_article', {
					title: post.title,
				} );
⋮----
sprintf( __( 'By %s', 'woocommerce' ), post.author_name )
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/LearnMarketing/types.ts">
export type Post = {
	author_avatar: string;
	author_name: string;
	date: string;
	image: string;
	link: string;
	title: string;
};
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/LearnMarketing/useBlogPosts.ts">
import { useSelect } from '@wordpress/data';
⋮----
import { store as marketingStore } from '~/marketing/data';
import { Post } from './types';
⋮----
export const useBlogPosts = ( category: string ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/overview-multichannel/MarketingOverviewMultichannel.tsx">
import { useRef } from '@wordpress/element';
import { useUser } from '@woocommerce/data';
⋮----
import { CenteredSpinner } from '~/marketing/components';
import {
	useIntroductionBanner,
	useCampaigns,
	useRegisteredChannels,
	useRecommendedChannels,
	useCampaignTypes,
	useInstalledPluginsWithoutChannels,
} from '~/marketing/hooks';
import { getAdminSetting } from '~/utils/admin-settings';
import { IntroductionBanner } from './IntroductionBanner';
import { Campaigns } from './Campaigns';
import { Channels, ChannelsRef } from './Channels';
import { InstalledExtensions } from './InstalledExtensions';
import { DiscoverTools } from './DiscoverTools';
import { LearnMarketing } from './LearnMarketing';
import Promotions from '~/marketplace/components/promotions/promotions';
⋮----
export const MarketingOverviewMultichannel = () =>
⋮----
const onInstalledAndActivated = ( pluginSlug: string ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/types/Campaign.ts">
export type Campaign = {
	id: string;
	title: string;
	description: string;
	cost: string;
	sales: string;
	manageUrl: string;
	icon: string;
	channelName: string;
	channelSlug: string;
};
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/types/CampaignType.ts">
export type CampaignType = {
	id: string;
	icon: string;
	name: string;
	description: string;
	createUrl: string;
	channelName: string;
	channelSlug: string;
};
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/types/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/types/InstalledPlugin.ts">
export type InstalledPlugin = {
	slug: string;
	icon: string;
	name: string;
	description: string;
	status: 'installed' | 'activated' | 'configured';
	docsUrl?: string;
	supportUrl?: string;
	settingsUrl?: string;
	dashboardUrl?: string;
};
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/types/RecommendedPlugin.ts">
type Subcategory = {
	slug: string;
	name: string;
};
⋮----
type Tag = {
	slug: string;
	name: string;
};
⋮----
export type RecommendedPlugin = {
	title: string;
	description: string;
	url: string;
	direct_install: boolean;
	icon: string;
	product: string;
	plugin: string;
	categories: Array< string >;
	subcategories: Array< Subcategory >;
	tags: Array< Tag >;
};
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/types/RegisteredChannel.ts">
export type SyncStatusType = 'synced' | 'syncing' | 'failed';
export type IssueTypeType = 'error' | 'warning' | 'none';
⋮----
export type RegisteredChannel = {
	slug: string;
	title: string;
	description: string;
	icon: string;
	isSetupCompleted: boolean;
	setupUrl: string;
	manageUrl: string;
	syncStatus: SyncStatusType;
	issueType: IssueTypeType;
	issueText: string;
};
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/utils/getRecommendationSource.ts">
import { getAdminSetting } from '~/utils/admin-settings';
⋮----
export const getRecommendationSource = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketing/utils/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketing/README.md">
Marketing
=========

This folder contains the components used in the Marketing page.
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/banner/banner.tsx">
import { __ } from '@wordpress/i18n';
import { useState, useEffect, useRef } from '@wordpress/element';
import { Button, Icon } from '@wordpress/components';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import {
	refundPolicyTitle,
	supportTitle,
	paymentTitle,
} from '../footer/footer';
import trustProducts from '../../assets/images/trust-products.svg';
import supportEcosystem from '../../assets/images/support-ecosystem.svg';
import moneyBack from '../../assets/images/money-back.svg';
import getHelp from '../../assets/images/get-help.svg';
⋮----
const handleDismiss = () =>
⋮----
const handlePause = ()
const handleResume = ()
⋮----
const handleKeyPress = ( event: React.KeyboardEvent< HTMLLIElement > ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/category-selector/category-dropdown.tsx">
import { Dropdown } from '@wordpress/components';
import { chevronDown, chevronUp, Icon } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
import { navigateTo, getNewPath } from '@woocommerce/navigation';
import clsx from 'clsx';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { Category } from './types';
import { ProductType } from '../product-list/types';
⋮----
function updateCategorySelection(
		event: React.MouseEvent< HTMLButtonElement >
)
⋮----
function dropDownTracksEvent()
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/category-selector/category-link.tsx">
import clsx from 'clsx';
import { navigateTo, getNewPath } from '@woocommerce/navigation';
⋮----
import { Category } from './types';
⋮----
export default function CategoryLink( props: Category ): React.JSX.Element
⋮----
function updateCategorySelection(
		event: React.MouseEvent< HTMLButtonElement >
)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/category-selector/category-selector.tsx">
import { useState, useEffect, useRef } from '@wordpress/element';
import { useQuery } from '@woocommerce/navigation';
import { Icon } from '@wordpress/components';
import { useDebounce } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';
⋮----
import CategoryLink from './category-link';
import { Category, CategoryAPIItem } from './types';
import { fetchCategories } from '../../utils/functions';
import { ProductType } from '../product-list/types';
import CategoryDropdown from './category-dropdown';
⋮----
interface CategorySelectorProps {
	type: ProductType;
}
⋮----
function checkOverflow()
⋮----
function checkScrollPosition()
⋮----
function scrollCategories( scrollAmount: number )
⋮----
function scrollToNextCategories()
⋮----
function scrollToPrevCategories()
⋮----
function mobileCategoryDropdownLabel()
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/category-selector/types.ts">
export type Category = {
	readonly slug: string;
	readonly label: string;
	selected: boolean;
};
⋮----
export type CategoryAPIItem = {
	readonly slug: string;
	readonly label: string;
};
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/connect-notice/connect-notice.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { appendURLParams, connectUrl } from '~/marketplace/utils/functions';
import Notice from '~/marketplace/components/notice/notice';
import { getAdminSetting } from '~/utils/admin-settings';
⋮----
// try to re-show the notice if it was dismissed more than a month ago.
// removing these 2 local storage items will make the notice reappear.
⋮----
const handleClick = () =>
⋮----
const handleLearnMoreClick = () =>
⋮----
const handleClose = () =>
⋮----
const handleLoad = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/content/content.tsx">
import {
	useContext,
	useEffect,
	useState,
	useCallback,
} from '@wordpress/element';
import { useQuery } from '@woocommerce/navigation';
import { speak } from '@wordpress/a11y';
import { __, sprintf } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { Product, ProductType } from '../product-list/types';
import { getAdminSetting } from '~/utils/admin-settings';
import Discover from '../discover/discover';
import Products from '../products/products';
import MySubscriptions from '../my-subscriptions/my-subscriptions';
import { MarketplaceContext } from '../../contexts/marketplace-context';
import { isQualityBadgeFilterActive } from '../quality-badge/quality-badge-filter';
import { fetchSearchResults, getProductType } from '../../utils/functions';
import { SubscriptionsContextProvider } from '../../contexts/subscriptions-context';
import { SearchResultsCountType } from '../../contexts/types';
import {
	recordMarketplaceView,
	recordLegacyTabView,
} from '../../utils/tracking';
import InstallNewProductModal from '../install-flow/install-new-product-modal';
import Promotions from '../promotions/promotions';
import ConnectNotice from '~/marketplace/components/connect-notice/connect-notice';
import PluginInstallNotice from '../woo-update-manager-plugin/plugin-install-notice';
import SubscriptionsExpiredExpiringNotice from '~/marketplace/components/my-subscriptions/subscriptions-expired-expiring-notice';
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/discover/discover.tsx">
import { useContext, useEffect, useRef, useState } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import ProductList from '../product-list/product-list';
import { fetchDiscoverPageData, ProductGroup } from '../../utils/functions';
import ProductLoader from '../product-loader/product-loader';
import { MarketplaceContext } from '../../contexts/marketplace-context';
import { ProductCardType, ProductType } from '../product-list/types';
⋮----
import { recordMarketplaceView } from '~/marketplace/utils/tracking';
⋮----
export default function Discover(): React.JSX.Element | null
⋮----
function recordTracksEvent( products: ProductGroup[] )
⋮----
function recordGroupViewedTrackEvent( group: ProductGroup )
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/footer/footer.tsx">
import { __ } from '@wordpress/i18n';
import { check, commentContent, shield, people } from '@wordpress/icons';
⋮----
import IconWithText from '../icon-with-text/icon-with-text';
import { MARKETPLACE_HOST } from '../constants';
import { TrackedLink } from '../../../components/tracked-link/tracked-link';
⋮----
export const refundPolicyTitle = ( location: string ) =>
⋮----
description=
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/header/header.tsx">
import HeaderTitle from '../header-title/header-title';
import HeaderAccount from '../header-account/header-account';
import Tabs from '../tabs/tabs';
import Search from '../search/search';
⋮----
export default function Header()
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/header-account/header-account-modal.tsx">
import { useState } from '@wordpress/element';
import { Button, ButtonGroup, Modal } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
export interface HeaderAccountModalProps {
	setIsModalOpen: ( value: boolean ) => void;
	disconnectURL: string;
}
⋮----
const toggleIsBusy = ()
const closeModal = ()
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/header-account/header-account.tsx">
import { ComponentProps } from 'react';
import { useState } from '@wordpress/element';
import {
	DropdownMenu,
	MenuGroup,
	MenuItem as OriginalMenuItem,
	VisuallyHidden,
} from '@wordpress/components';
import {
	Icon,
	commentAuthorAvatar,
	external,
	linkOff,
	chevronDown,
} from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { getAdminSetting } from '../../../utils/admin-settings';
import HeaderAccountModal from './header-account-modal';
import { MARKETPLACE_MY_ACCOUNT_PATH } from '../constants';
import { connectUrl } from '../../utils/functions';
⋮----
interface MenuItemProps extends ComponentProps< typeof OriginalMenuItem > {
	href?: string;
	target?: string;
	rel?: string;
}
⋮----
const MenuItem = ( props: MenuItemProps ) => <OriginalMenuItem
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/header-title/header-title.tsx">
import { __ } from '@wordpress/i18n';
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/icon-with-text/icon-with-text.tsx">
import { Icon } from '@wordpress/icons';
import { ReactElement } from 'react';
⋮----
export interface IconWithTextProps {
	icon: React.JSX.Element;
	title: ReactElement | string;
	description: string;
}
⋮----
export default function IconWithText(
	props: IconWithTextProps
): React.JSX.Element
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/install-flow/create-order.tsx">
import apiFetch from '@wordpress/api-fetch';
⋮----
type CreateOrderSuccessResponse = {
	success: true;
	data: {
		product_id: number;
		zip_slug: string;
		product_type: string;
		documentation_url: string;
	};
};
⋮----
type CreateOrderErrorResponse = {
	success: false;
	data: {
		code: string;
		message: string;
		redirect_location?: string;
	};
};
⋮----
type CreateOrderResponse =
	| CreateOrderSuccessResponse
	| CreateOrderErrorResponse;
⋮----
function createOrder( productId: number ): Promise< CreateOrderResponse >
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/install-flow/install-new-product-modal.tsx">
import { ButtonGroup, Button, Modal, Notice } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { dispatch } from '@wordpress/data';
import { useState, useEffect, useContext } from '@wordpress/element';
import { navigateTo, getNewPath, useQuery } from '@woocommerce/navigation';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import type { NoticeStatus } from '~/lib/notices/types';
import ProductCard from '../product-card/product-card';
import { Product } from '../product-list/types';
import ConnectAccountButton from '../my-subscriptions/table/actions/connect-account-button';
import { installingStore } from '../../contexts/install-store';
import { downloadProduct } from '../../utils/functions';
import { createOrder } from './create-order';
import { MARKETPLACE_PATH, WP_ADMIN_PLUGIN_LIST_URL } from '../constants';
import { getAdminSetting } from '../../../utils/admin-settings';
import { MarketplaceContext } from '../../contexts/marketplace-context';
⋮----
enum InstallFlowStatus {
	'notConnected',
	'notInstalled',
	'installing',
	'installedCanActivate',
	'installedCannotActivate',
	'installFailed',
	'activating',
	'activated',
	'activationFailed',
}
⋮----
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/likert-scale/likert-scale.tsx">
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
⋮----
export interface LikertScaleProps {
	title: string;
	fieldName: string;
	onValueChange: ( value: number ) => void;
	validationFailed?: boolean;
}
⋮----
export interface LikertChangeEvent {
	target: {
		value: number;
	};
}
⋮----
export default function LikertScale(
	props: LikertScaleProps
): React.JSX.Element
⋮----
function valueChanged( e: React.ChangeEvent< HTMLInputElement > )
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/load-more-button/load-more-button.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { speak } from '@wordpress/a11y';
import { queueRecordEvent } from '@woocommerce/tracks';
⋮----
interface LoadMoreProps {
	onLoadMore: () => void;
	isBusy: boolean;
	disabled: boolean;
}
⋮----
function handleClick()
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/actions/auto-renew-button.tsx">
import { ComponentProps } from 'react';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { queueRecordEvent } from '@woocommerce/tracks';
⋮----
import { enableAutorenewalUrl } from '../../../../utils/functions';
import { Subscription } from '../../types';
⋮----
type ButtonProps = ComponentProps< typeof Button >;
⋮----
interface AutoRenewProps {
	subscription: Subscription;
	variant?: ButtonProps[ 'variant' ];
}
⋮----
export default function AutoRenewButton( props: AutoRenewProps )
⋮----
function recordTracksEvent()
⋮----
href=
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/actions/connect-account-button.tsx">
import { ComponentProps } from 'react';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
import { connectUrl } from '../../../../utils/functions';
⋮----
type ButtonProps = ComponentProps< typeof Button >;
⋮----
interface RenewProps {
	variant?: ButtonProps[ 'variant' ];
	install?: string;
}
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/actions/connect-button.tsx">
import { ComponentProps } from 'react';
import { Button, ButtonGroup, Modal } from '@wordpress/components';
import { useContext, useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { SubscriptionsContext } from '../../../../contexts/subscriptions-context';
import {
	activateProductPlugin,
	addNotice,
	connectProduct,
	removeNotice,
} from '../../../../utils/functions';
import {
	getConnectionErrorMessage,
	getConnectionErrorAction,
	trackConnectErrorActionClicked,
	type ConnectError,
} from '../../error-utils';
import { Subscription } from '../../types';
import { NoticeStatus } from '../../../../contexts/types';
import sanitizeHTML from '~/lib/sanitize-html';
⋮----
type ButtonProps = ComponentProps< typeof Button >;
⋮----
interface ConnectProps {
	subscription: Subscription;
	onClose?: () => void;
	variant?: ButtonProps[ 'variant' ];
}
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/actions/connect-modal.tsx">
import { Button, ButtonGroup, Modal } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
⋮----
import { Subscription } from '../../types';
import ConnectButton from './connect-button';
⋮----
interface ConnectProps {
	subscription: Subscription;
	onClose: () => void;
}
⋮----
title=
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/actions/install-modal.tsx">
import { Button, ButtonGroup, Modal, Notice } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { getNewPath, navigateTo, useQuery } from '@woocommerce/navigation';
import {
	useCallback,
	useContext,
	useEffect,
	useState,
} from '@wordpress/element';
⋮----
import { Subscription } from '../../types';
import { getAdminSetting } from '../../../../../utils/admin-settings';
import Install from './install';
import { SubscriptionsContext } from '../../../../contexts/subscriptions-context';
import { MARKETPLACE_PATH, WP_ADMIN_PLUGIN_LIST_URL } from '../../../constants';
import ConnectAccountButton from './connect-account-button';
import ProductCard from '../../../product-card/product-card';
import { addNotice, subscriptionToProduct } from '../../../../utils/functions';
import { NoticeStatus } from '../../../../contexts/types';
⋮----
const onClose = () =>
⋮----
const modalTitle = () =>
⋮----
product=
⋮----
title=
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/actions/install.tsx">
import { ComponentProps } from 'react';
import { Button } from '@wordpress/components';
import { dispatch, useSelect } from '@wordpress/data';
import { useContext } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { SubscriptionsContext } from '../../../../contexts/subscriptions-context';
import {
	addNotice,
	getInstallUrl,
	installProduct,
	removeNotice,
} from '../../../../utils/functions';
import { Subscription } from '../../types';
import { installingStore } from '../../../../contexts/install-store';
import { NoticeStatus } from '../../../../contexts/types';
⋮----
type ButtonProps = ComponentProps< typeof Button >;
⋮----
interface InstallProps {
	subscription: Subscription;
	variant?: ButtonProps[ 'variant' ];
	onSuccess?: () => void;
	onError?: () => void;
}
⋮----
export default function Install( props: InstallProps )
⋮----
const startInstall = () =>
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/actions/refresh-button.tsx">
import { Button } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { useContext, useState } from '@wordpress/element';
⋮----
import RefreshIcon from '../../../../assets/images/refresh.svg';
import { SubscriptionsContext } from '../../../../contexts/subscriptions-context';
import {
	addNotice,
	getRefreshErrorMessage,
	removeNotice,
} from '../../../../utils/functions';
import {
	NoticeStatus,
	REFRESH_SUBSCRIPTIONS_NOTICE_ID as NOTICE_ID,
} from '../../../../contexts/types';
⋮----
const refresh = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/actions/renew-button.tsx">
import { ComponentProps } from 'react';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { queueRecordEvent } from '@woocommerce/tracks';
⋮----
import { renewUrl } from '../../../../utils/functions';
import { Subscription } from '../../types';
⋮----
type ButtonProps = ComponentProps< typeof Button >;
⋮----
interface RenewProps {
	subscription: Subscription;
	variant?: ButtonProps[ 'variant' ];
}
⋮----
export default function RenewButton( props: RenewProps )
⋮----
function recordTracksEvent()
⋮----
href=
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/actions/renew-modal.tsx">
import { Button, ButtonGroup, Modal } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
⋮----
import { Subscription } from '../../types';
import RenewButton from './renew-button';
⋮----
interface RenewProps {
	subscription: Subscription;
	onClose: () => void;
}
⋮----
title=
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/actions/subscribe-button.tsx">
import { ComponentProps } from 'react';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { queueRecordEvent } from '@woocommerce/tracks';
⋮----
import { subscribeUrl } from '../../../../utils/functions';
import { Subscription } from '../../types';
⋮----
type ButtonProps = ComponentProps< typeof Button >;
⋮----
interface SubscribeProps {
	subscription: Subscription;
	variant?: ButtonProps[ 'variant' ];
}
⋮----
export default function SubscribeButton( props: SubscribeProps )
⋮----
function recordTracksEvent()
⋮----
href=
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/actions/subscribe-modal.tsx">
import { Button, ButtonGroup, Modal } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
⋮----
import { Subscription } from '../../types';
import SubscribeButton from './subscribe-button';
⋮----
interface SubscribeProps {
	subscription: Subscription;
	onClose: () => void;
}
⋮----
title=
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/actions/update.tsx">
import { Button } from '@wordpress/components';
import { useContext, useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { SubscriptionsContext } from '../../../../contexts/subscriptions-context';
import { Subscription } from '../../types';
import ConnectModal from './connect-modal';
import RenewModal from './renew-modal';
import SubscribeModal from './subscribe-modal';
import {
	addNotice,
	removeNotice,
	updateProduct,
} from '../../../../utils/functions';
import { NoticeStatus } from '../../../../contexts/types';
import InstallWooConnectModal from '../../../woo-update-manager-plugin/install-woo-connect-modal';
⋮----
interface UpdateProps {
	subscription: Subscription;
	wooUpdateManagerActive: boolean;
}
⋮----
export default function Update( props: UpdateProps )
⋮----
function update()
⋮----
// translators: %s is the product name.
⋮----
const modal = () =>
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/rows/actions-dropdown-menu.tsx">
import { DropdownMenu } from '@wordpress/components';
import { moreVertical } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
⋮----
import { Subscription } from '../../types';
import { ADMIN_URL } from '../../../../../utils/admin-settings';
⋮----
export default function ActionsDropdownMenu( props: {
	subscription: Subscription;
} )
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/rows/auto-update-status.tsx">
import { Button } from '@wordpress/components';
import { useContext, useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { speak } from '@wordpress/a11y';
import { Icon, info } from '@wordpress/icons';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import RefreshIcon from '../../../../assets/images/refresh.svg';
import { SubscriptionsContext } from '../../../../contexts/subscriptions-context';
import { NoticeStatus } from '../../../../contexts/types';
import {
	addNotice,
	removeNotice,
	setProductAutoUpdate,
} from '../../../../utils/functions';
import { StatusLevel, Subscription } from '../../types';
import StatusPopover from './status-popover';
import { getAdminSetting } from '../../../../../utils/admin-settings';
⋮----
export function getAutoUpdateBlockers( subscription: Subscription ): string[]
⋮----
function setAutoUpdate( enabled: boolean )
⋮----
text=
⋮----
⋮----
? __( 'On', 'woocommerce' )
⋮----
explanation=
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/rows/functions.tsx">
import type { TableRow } from '@woocommerce/components/build-types/table/types';
import { gmdateI18n } from '@wordpress/date';
import { __, sprintf, TranslatableText } from '@wordpress/i18n';
import { Icon, plugins } from '@wordpress/icons';
import { createInterpolateElement } from '@wordpress/element';
⋮----
import { StatusLevel, Subscription, MySubscriptionsTable } from '../../types';
import ConnectButton from '../actions/connect-button';
import Install from '../actions/install';
import RenewButton from '../actions/renew-button';
import AutoRenewButton from '../actions/auto-renew-button';
import SubscribeButton from '../actions/subscribe-button';
import Update from '../actions/update';
import StatusPopover from './status-popover';
import AutoUpdateStatus from './auto-update-status';
import ActionsDropdownMenu from './actions-dropdown-menu';
import Version from './version';
import {
	appendURLParams,
	renewUrl,
	subscribeUrl,
	enableAutorenewalUrl,
} from '../../../../utils/functions';
import {
	MARKETPLACE_COLLABORATION_PATH,
	MARKETPLACE_SHARING_PATH,
} from '../../../constants';
import { getAdminSetting } from '../../../../../utils/admin-settings';
⋮----
type StatusBadge = {
... (27 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/rows/status-popover.tsx">
import { Popover } from '@wordpress/components';
import { useState, useRef, useEffect } from '@wordpress/element';
import clsx from 'clsx';
⋮----
import { StatusLevel } from '../../types';
⋮----
export default function StatusPopover( props: {
	text: string;
	level: StatusLevel;
	explanation: string | React.JSX.Element;
	explanationOnHover?: boolean;
	icon?: React.JSX.Element;
} )
⋮----
const startHover = () =>
⋮----
const endHover = () =>
⋮----
function shouldShowExplanation()
⋮----
onClick=
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/rows/version.tsx">
interface VersionProps {
	span: string;
}
⋮----
export default function Version( props: VersionProps )
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/table-rows.tsx">
import type { TableRow } from '@woocommerce/components/build-types/table/types';
⋮----
import { Subscription, MySubscriptionsTable } from '../types';
import {
	actions,
	autoUpdates,
	subscriptionStatus,
	expiry,
	nameAndStatus,
	version,
} from './rows/functions';
⋮----
export function subscriptionRow(
	item: Subscription,
	table: MySubscriptionsTable
): TableRow[]
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/table/table.tsx">
import { EmptyTable, Table, TablePlaceholder } from '@woocommerce/components';
import type {
	TableHeader,
	TableRow,
} from '@woocommerce/components/build-types/table/types';
import { getNewPath } from '@woocommerce/navigation';
import { createInterpolateElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
⋮----
import { MARKETPLACE_PATH } from '../../constants';
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/constants.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/error-utils.ts">
import { __, sprintf, _n } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import type { NoticeAction } from '~/lib/notices/types';
import {
	MARKETPLACE_RENEW_SUBSCRIPTION_PATH,
	MARKETPLACE_SUPPORT_PATH,
} from '../constants';
import { ERROR_CODES_WITH_MESSAGES } from './constants';
⋮----
type ConnectError = {
	data?: {
		message?: string;
		code?: string;
		data?: {
			sites_list?: string[];
			total_domains?: number;
		};
	};
};
⋮----
type StoreAction = NoticeAction;
⋮----
function trackConnectErrorActionClicked(
	action: 'manage_subscriptions' | 'contact_support' | 'try_again',
	errorCode: string
)
⋮----
function getConnectionErrorMessage(
	error: ConnectError,
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/my-subscriptions-account.tsx">
import { Button } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { createInterpolateElement, useState } from '@wordpress/element';
import { Icon, closeSmall, link } from '@wordpress/icons';
import { speak } from '@wordpress/a11y';
import apiFetch from '@wordpress/api-fetch';
⋮----
import { getAdminSetting } from '~/utils/admin-settings';
import { MARKETPLACE_MY_ACCOUNT_PATH } from '../constants';
import { connectUrl } from '../../utils/functions';
import HeaderAccountModal from '../header-account/header-account-modal';
⋮----
interface MySubscriptionsAccountProps {
	onDismiss?: () => void;
}
⋮----
const handleDismiss = () =>
⋮----
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/my-subscriptions.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import {
	createInterpolateElement,
	useContext,
	useEffect,
	useRef,
} from '@wordpress/element';
import { Icon, external } from '@wordpress/icons';
import apiFetch from '@wordpress/api-fetch';
⋮----
import { getAdminSetting } from '../../../utils/admin-settings';
import { SubscriptionsContext } from '../../contexts/subscriptions-context';
⋮----
import {
	AvailableSubscriptionsTable,
	InstalledSubscriptionsTable,
} from './table/table';
import { subscriptionRow } from './table/table-rows';
import { Subscription } from './types';
import { RefreshButton } from './table/actions/refresh-button';
import Notices from './notices';
import InstallModal from './table/actions/install-modal';
import { addNotice, connectUrl } from '../../utils/functions';
import {
	NoticeStatus,
	REFRESH_SUBSCRIPTIONS_NOTICE_ID,
} from '../../contexts/types';
import Notice from '../notice/notice';
import MySubscriptionsAccount from './my-subscriptions-account';
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/notices.tsx">
import { ComponentProps } from 'react';
import { Notice } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
⋮----
import Alert from '../../assets/images/alert.svg';
import { Notice as NoticeType } from '../../contexts/types';
import { noticeStore } from '../../contexts/notice-store';
import { removeNotice } from '../../utils/functions';
⋮----
type NoticeActions = ComponentProps< typeof Notice >[ 'actions' ];
⋮----
const actions = ( notice: NoticeType ): NoticeActions =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/subscriptions-expired-expiring-notice.tsx">
import { Button } from '@wordpress/components';
import apiFetch from '@wordpress/api-fetch';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import Notice from '~/marketplace/components/notice/notice';
import { getAdminSetting } from '~/utils/admin-settings';
⋮----
export interface SubscriptionsExpiredExpiringNoticeProps {
	type: string;
}
⋮----
export interface TrackEvents {
	shown: string;
	clicked: string;
	dismissed: string;
}
⋮----
export default function SubscriptionsExpiredExpiringNotice(
	props: SubscriptionsExpiredExpiringNoticeProps
): React.JSX.Element | null
⋮----
const handleClose = () =>
⋮----
function handleClick()
⋮----
function handleLoad()
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/my-subscriptions/types.ts">
export type Subscription = {
	product_key: string;
	product_id: number;
	product_name: string;
	product_url: string;
	product_icon: string;
	product_slug: string;
	product_type: string;
	documentation_url: string;
	zip_slug: string;
	key_type: string;
	key_type_label: string;
	autorenew: boolean;
	connections: string[];
	legacy_connections: string[];
	shares: SubscriptionShare[];
	lifetime: boolean;
	expires: number;
	expired: boolean;
	expiring: boolean;
	sites_max: number;
	sites_active: number;
	maxed: boolean;
	order_id: number;
	product_keys_all: string[];
	product_status: string;
	active: boolean;
	local: SubscriptionLocal;
	has_updates: boolean;
	version: string;
... (40 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/notice/notice.tsx">
import clsx from 'clsx';
import { useEffect, useState } from '@wordpress/element';
import { Icon, check, closeSmall, info, percent } from '@wordpress/icons';
⋮----
import sanitizeHTML from '../../../lib/sanitize-html';
⋮----
export interface NoticeProps {
	id: string;
	children?: React.ReactNode;
	description: string;
	icon?: string;
	isDismissible: boolean;
	variant: string;
	className?: string;
	onClose?: () => void;
	onLoad?: () => void;
}
⋮----
type IconKey = keyof typeof iconMap;
⋮----
const handleClose = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/notice/README.md">
# Notice Component

The `Notice` component is a versatile notification UI element designed for use within the WooCommerce in-app marketplace.
It leverages the `@wordpress/icons` for displaying various icons and provides customizable options for content, appearance, and behavior.

## Usage

To use the Notice component, import it into your React component file and include it in your component's render method. Here is a basic example:

```jsx
import Notice from '../notice/notice';

function MyComponent() {
	return (
		<Notice
			id="unique-notice-id"
			description="This is a notice description."
			icon="info"
			isDismissible={true}
			variant="info"
		>
			<p>Additional content can go here.</p>
		</Notice>
	);
}

export default MyComponent;
```

## Props
... (121 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/product-card/product-card-footer.tsx">
import { Button, Icon } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { useContext } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
import { navigateTo, getNewPath } from '@woocommerce/navigation';
import { useUser } from '@woocommerce/data';
⋮----
import { Product } from '../product-list/types';
import { MarketplaceContext } from '../../contexts/marketplace-context';
⋮----
function openInstallModal()
⋮----
function shouldShowAddToStore( productToCheck: Product )
⋮----
const getCurrencyFormat = ( currencyCode: string ) =>
⋮----
function getPriceLabel(): string
⋮----
function getPriceSuffix(): string
⋮----
function getBillingText(): string
⋮----
const getReaderPriceLabel = () =>
⋮----
//translators: %1$s is the sale price of the product, %2$s is the regular price of the product, %3$s is the billing period
⋮----
const isInstalled = () =>
⋮----
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/product-card/product-card.tsx">
import { __ } from '@wordpress/i18n';
import { Card } from '@wordpress/components';
import clsx from 'clsx';
import { ExtraProperties, queueRecordEvent } from '@woocommerce/tracks';
import { useQuery } from '@woocommerce/navigation';
import { decodeEntities } from '@wordpress/html-entities';
import { useState, useContext, useRef } from '@wordpress/element';
⋮----
import ProductCardFooter from './product-card-footer';
import QualityBadge from '../quality-badge/quality-badge';
import {
	Product,
	ProductCardType,
	ProductTracksData,
	ProductType,
} from '../product-list/types';
import { appendURLParams } from '../../utils/functions';
import ProductPreviewModal from '../product-preview-modal/product-preview-modal';
import { MarketplaceContext } from '../../contexts/marketplace-context';
export interface ProductCardProps {
	type?: string;
	product?: Product;
	isLoading?: boolean;
	tracksData: ProductTracksData;
	small?: boolean;
	cardType?: ProductCardType;
}
⋮----
// Business service cards can be mixed with extensions. Check product type to properly set the card type.
// For extensions and themes, type is not set on product object.
... (24 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/product-list/product-list.tsx">
import ProductListContent from '../product-list-content/product-list-content';
import ProductListHeader from '../product-list-header/product-list-header';
import { Product, ProductCardType, ProductType } from './types';
⋮----
interface ProductListProps {
	title: string;
	description: string;
	productGroup?: string;
	products: Product[];
	groupURL: string;
	type: ProductType;
	cardType?: ProductCardType;
	groupURLText: string | null;
	groupURLType: 'wc-admin' | 'wp-admin' | 'external' | undefined;
	groupId?: string;
	containerRef?: ( element: HTMLDivElement | null ) => void;
}
⋮----
export default function ProductList(
	props: ProductListProps
): React.JSX.Element
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/product-list/types.ts">
export type SearchAPIJSONType = {
	products: Array< SearchAPIProductType >;
	total_pages: number;
	total_products: number;
};
⋮----
export type SearchAPIProductType = {
	title: string;
	image: string;
	type: ProductType;
	freemium_type: 'unset' | 'primary';
	excerpt: string;
	link: string;
	demo_url: string;
	price: string;
	raw_price: number;
	hash: string;
	slug: string;
	id: number;
	rating: number | null;
	reviews_count: number | null;
	vendor_name: string;
	vendor_url: string;
	icon: string;
	is_installable: boolean;
	featured_image: string;
	product_category: string;
	color: string;
	billing_period: string;
	billing_period_interval: number;
... (67 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/product-list-content/no-results.tsx">
import { __ } from '@wordpress/i18n';
import { useEffect, useState } from '@wordpress/element';
⋮----
import { fetchDiscoverPageData, ProductGroup } from '../../utils/functions';
import ProductLoader from '../product-loader/product-loader';
import ProductList from '../product-list/product-list';
import { ProductType, SearchResultType } from '../product-list/types';
import CategorySelector from '../category-selector/category-selector';
⋮----
function productListTitle( groupId: string )
⋮----
title=
⋮----
if (
			props.showCategorySelector === false ||
			props.type === SearchResultType.all
)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/product-list-content/product-list-content.tsx">
import { Fragment, useEffect, useState } from '@wordpress/element';
import clsx from 'clsx';
⋮----
import ProductCard from '../product-card/product-card';
import { Product, ProductCardType, ProductType } from '../product-list/types';
import { appendURLParams } from '../../utils/functions';
import { getAdminSetting } from '~/utils/admin-settings';
⋮----
const updateColumns = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/product-list-header/product-list-header.tsx">
import clsx from 'clsx';
import { Link } from '@woocommerce/components';
import { __ } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
interface ProductListHeaderProps {
	title: string;
	description: string;
	groupURL: string | null;
	groupURLText: string | null;
	groupURLType: 'wc-admin' | 'wp-admin' | 'external' | undefined;
}
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/product-loader/product-loader.tsx">
import ProductListHeader from '../product-list-header/product-list-header';
import ProductCard from '../product-card/product-card';
⋮----
interface ProductLoaderProps {
	hasTitle?: boolean;
	placeholderCount?: number;
	type: string;
}
⋮----
export default function ProductLoader(
	props: ProductLoaderProps
): React.JSX.Element
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/product-preview-modal/product-preview-modal.tsx">
import { Modal } from '@wordpress/components';
import { useEffect, useState, useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Spinner } from '@woocommerce/components';
⋮----
import { fetchProductPreview } from '../../utils/functions';
import sanitizeHtmlExtended from '~/lib/sanitize-html/sanitize-html-extended.js';
import sanitizeHtmlConfig from './product-preview-sanitize-html-config';
⋮----
interface ProductPreviewModalProps {
	productTitle: string;
	productVendor: React.JSX.Element | string | null;
	productIcon: string;
	productId: number;
	triggerRef: React.RefObject< HTMLAnchorElement | null >;
	onOpen?: () => void;
	onClose?: ( closeType?: string ) => void;
}
⋮----
// Return focus to the triggering element after a small delay
// to ensure layout shifts have completed
⋮----
// Add event listener for content interactions
⋮----
const handleContentInteraction = ( event: Event ) =>
⋮----
const loadPreview = async () =>
⋮----
closeModal( 'marketplace_product_preview_modal_dismissed' )
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/product-preview-modal/product-preview-sanitize-html-config.tsx">
import {
	EXTENDED_ALLOWED_TAGS,
	EXTENDED_ALLOWED_ATTR,
} from '~/lib/sanitize-html/sanitize-html-extended.js';
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/products/products.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { createInterpolateElement, useContext } from '@wordpress/element';
import { getNewPath, navigateTo, useQuery } from '@woocommerce/navigation';
import { Button } from '@wordpress/components';
import clsx from 'clsx';
⋮----
import { MarketplaceContext } from '../../contexts/marketplace-context';
import CategorySelector from '../category-selector/category-selector';
import ProductListContent from '../product-list-content/product-list-content';
import ProductLoader from '../product-loader/product-loader';
import QualityBadgeFilter from '../quality-badge/quality-badge-filter';
import NoResults from '../product-list-content/no-results';
import { Product, ProductType, SearchResultType } from '../product-list/types';
import { ADMIN_URL } from '~/utils/admin-settings';
⋮----
interface ProductsProps {
	categorySelector?: boolean;
	products?: Product[];
	perPage?: number;
	type: ProductType;
	searchTerm?: string;
	showAllButton?: boolean;
}
⋮----
export default function Products( props: ProductsProps )
⋮----
function showSection( section: ProductType )
⋮----
// The sub-header stays mounted across the loading/empty/loaded states so
// the filter toggle keeps keyboard focus while toggling triggers a refetch.
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/promo-card/images/percent.tsx">
export default function PercentSVG()
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/promo-card/promo-card.tsx">
import { Button, Card, CardBody } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { createElement, useEffect, useState } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { Promotion } from '../promotions/types';
import sanitizeHTML from '../../../lib/sanitize-html';
import PercentSVG from './images/percent';
⋮----
interface PromoCardProps {
	promotion: Promotion;
	eventProperties?: Record< string, unknown >;
	onDismiss?: () => void;
}
⋮----
const getDismissedURIs = ()
⋮----
const handleDismiss = () =>
⋮----
const handleClick = () =>
⋮----
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/promotions/promotions.tsx">
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { LOCALE } from '../../../utils/admin-settings';
import Notice from '../notice/notice';
import { Page, Promotion } from './types';
import PromoCard from '../promo-card/promo-card';
⋮----
interface Window {
		wcMarketplace?: {
			promotions?: Promotion[];
		};
	}
⋮----
const handleLoad = () =>
⋮----
const handleClose = () =>
⋮----
const normalize = ( path: string )
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/promotions/types.ts">
export type Page = {
	page?: string;
	path?: string;
	tab?: string;
	pathname?: string;
};
⋮----
export type Promotion = {
	date_from_gmt: string;
	date_to_gmt: string;
	format: string;
	style?: string;
	pages: Page[];
	content: { [ locale: string ]: string };
	icon?: string;
	title?: { [ locale: string ]: string };
	is_dismissible?: boolean;
	menu_item_id?: string;
	cta_label?: {
		[ locale: string ]: string;
	};
	cta_link?: string;
};
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/quality-badge/quality-badge-filter.tsx">
import { __, sprintf } from '@wordpress/i18n';
import {
	createInterpolateElement,
	useContext,
	useState,
} from '@wordpress/element';
import { FormToggle, Icon } from '@wordpress/components';
import { info } from '@wordpress/icons';
import { useInstanceId } from '@wordpress/compose';
import { recordEvent } from '@woocommerce/tracks';
import { getNewPath, navigateTo, useQuery } from '@woocommerce/navigation';
⋮----
import { QualityBadgeIcon, QualityBadgePopover } from './quality-badge';
import { MarketplaceContext } from '../../contexts/marketplace-context';
import { MarketplaceContextType } from '../../contexts/types';
⋮----
onClick=
⋮----
if ( event.key === 'Escape' && isOpen )
⋮----
const onChange = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/quality-badge/quality-badge.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { useContext, useEffect, useState } from '@wordpress/element';
import { Popover } from '@wordpress/components';
import { speak } from '@wordpress/a11y';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { Product } from '../product-list/types';
import { MarketplaceContext } from '../../contexts/marketplace-context';
⋮----
export function QualityBadgeIcon(
⋮----
function getSafeDocsUrl( value?: string ): string | undefined
⋮----
/**
 * Popover with the badge explanation and, when the WooCommerce.com API
 * provides a docs URL, a "Learn more" link. Shared by the card chip and the
 * filter's info button; a popover (not a tooltip) so the link stays reachable
 * by pointer and keyboard.
 */
⋮----
const onFocusin = ( event: FocusEvent ) =>
⋮----
aria-label=
⋮----
onKeyDown=
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/search/search.tsx">
import { __ } from '@wordpress/i18n';
import { useEffect, useState } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
import { navigateTo, getNewPath, useQuery } from '@woocommerce/navigation';
import { SearchControl } from '@wordpress/components';
⋮----
import { MARKETPLACE_PATH } from '../constants';
⋮----
function Search(): React.JSX.Element
⋮----
const runSearch = ( term?: string ) =>
⋮----
// If we're on 'Discover' or 'My subscriptions' when a search is initiated, move to the extensions tab
⋮----
const handleKeyUp = ( event:
⋮----
// SearchControl only shows its reset button while the field has text,
// and reset empties the field through onChange. When a search is active,
// emptying the field also clears the results.
const onChange = ( value: string ) =>
⋮----
const onFocus = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/tabs/tabs.tsx">
import { __, _n, sprintf } from '@wordpress/i18n';
import { useContext, useEffect, useMemo } from '@wordpress/element';
import { Button } from '@wordpress/components';
import clsx from 'clsx';
import { getNewPath, navigateTo, useQuery } from '@woocommerce/navigation';
⋮----
import { DEFAULT_TAB_KEY, MARKETPLACE_PATH } from '../constants';
import { MarketplaceContext } from '../../contexts/marketplace-context';
import { MarketplaceContextType } from '../../contexts/types';
import { getAdminSetting } from '../../../utils/admin-settings';
⋮----
export interface TabsProps {
	additionalClassNames?: Array< string > | undefined;
}
⋮----
interface Tab {
	name: string;
	title: string;
	href?: string;
	showUpdateCount: boolean;
	updateCount: number;
}
⋮----
interface Tabs {
	[ key: string ]: Tab;
}
⋮----
const setUrlTabParam = ( tabKey: string, query: Record< string, string > ) =>
⋮----
const onTabClick = ( tabKey: string ) =>
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/woo-update-manager-plugin/install-woo-connect-modal.tsx">
import { Button, ButtonGroup, Modal } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
⋮----
import sanitizeHTML from '../../../lib/sanitize-html';
import { Subscription } from '../my-subscriptions/types';
import {
	WOO_CONNECT_PLUGIN_DOWNLOAD_URL,
	WP_ADMIN_PLUGIN_LIST_URL,
} from '../constants';
import { getAdminSetting } from '../../../utils/admin-settings';
⋮----
interface ConnectProps {
	subscription: Subscription;
	onClose: () => void;
}
⋮----
title=
⋮----
dangerouslySetInnerHTML=
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/woo-update-manager-plugin/plugin-install-notice.tsx">
import { Button, Notice } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
import sanitizeHTML from '../../../lib/sanitize-html';
import { getAdminSetting } from '../../../utils/admin-settings';
import {
	WP_ADMIN_PLUGIN_LIST_URL,
	WOO_CONNECT_PLUGIN_DOWNLOAD_URL,
} from '../constants';
⋮----
dangerouslySetInnerHTML=
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/components/constants.ts">
import { ADMIN_URL } from '../../utils/admin-settings';
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/contexts/install-store.tsx">
import { createReduxStore, register } from '@wordpress/data';
⋮----
import { InstallingState } from './types';
⋮----
export interface InstallingStateErrorAction {
	label: string;
	onClick: () => void;
}
⋮----
reducer( state: InstallingState | undefined = DEFAULT_STATE, action )
⋮----
startInstalling( productKey: string )
stopInstalling( productKey: string )
⋮----
isInstalling(
			state: InstallingState | undefined,
			productKey: string
): boolean
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/contexts/marketplace-context.tsx">
import {
	useState,
	useEffect,
	useCallback,
	createContext,
} from '@wordpress/element';
⋮----
import { SearchResultsCountType, MarketplaceContextType } from './types';
import { LOCALE, getAdminSetting } from '../../utils/admin-settings';
import { createStorageUtils } from '../../utils/localStorage';
import {
	MARKETPLACE_HOST,
	MARKETPLACE_IAM_SETTINGS_API_PATH,
} from '../components/constants';
⋮----
export function MarketplaceContextProvider( props: {
	children: React.JSX.Element;
} ): React.JSX.Element
⋮----
function isProductInstalled( slug: string ): boolean
⋮----
function addInstalledProduct( slug: string )
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/contexts/notice-store.tsx">
import { createReduxStore, register } from '@wordpress/data';
⋮----
import { NoticeState, Notice, NoticeStatus, NoticeOptions } from './types';
⋮----
reducer( state: NoticeState | undefined = DEFAULT_STATE, action )
⋮----
addNotice(
			productKey: string,
			message: string,
			status: NoticeStatus,
			options?: Partial< NoticeOptions >
)
removeNotice( productKey: string )
⋮----
notices( state: NoticeState | undefined ): Notice[]
getNotice(
			state: NoticeState | undefined,
			productKey: string
): Notice | undefined
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/contexts/subscriptions-context.tsx">
import { useState, createContext, useEffect } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
⋮----
import {
	SubscriptionsContextType,
	NoticeStatus,
	REFRESH_SUBSCRIPTIONS_NOTICE_ID,
} from './types';
import { Subscription } from '../components/my-subscriptions/types';
import {
	addNotice,
	fetchSubscriptions,
	getRefreshErrorMessage,
	refreshSubscriptions as fetchSubscriptionsFromWooCom,
} from '../utils/functions';
⋮----
export function SubscriptionsContextProvider( props: {
	children: React.JSX.Element;
} ): React.JSX.Element
⋮----
const loadSubscriptions = ( toggleLoading?: boolean ) =>
⋮----
const refreshSubscriptions = ( toggleLoading?: boolean ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/contexts/types.ts">
import type { NoticeOptions } from '~/lib/notices/types';
import { Subscription } from '../components/my-subscriptions/types';
⋮----
export interface SearchResultsCountType {
	extensions: number;
	themes: number;
	'business-services': number;
}
⋮----
export type MarketplaceContextType = {
	isLoading: boolean;
	setIsLoading: ( isLoading: boolean ) => void;
	selectedTab: string;
	setSelectedTab: ( tab: string ) => void;
	isProductInstalled: ( slug: string ) => boolean;
	addInstalledProduct: ( slug: string ) => void;
	searchResultsCount: SearchResultsCountType;
	setSearchResultsCount: (
		updatedCounts: Partial< SearchResultsCountType >
	) => void;
	iamSettings: {
		product_previews?: 'modal' | 'none';
		quality_badge?: {
			enabled?: boolean;
			label?: string;
			tooltip?: string;
			docs_url?: string;
		};
	};
};
... (32 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/utils/functions.tsx">
import apiFetch from '@wordpress/api-fetch';
import { __, sprintf } from '@wordpress/i18n';
import { dispatch } from '@wordpress/data';
import { store as coreNoticesStore } from '@wordpress/notices';
import { Icon } from '@wordpress/components';
⋮----
import { LOCALE, getAdminSetting } from '../../utils/admin-settings';
import { CategoryAPIItem } from '../components/category-selector/types';
import {
	MARKETPLACE_CART_PATH,
	MARKETPLACE_CATEGORY_API_PATH,
	MARKETPLACE_HOST,
	MARKETPLACE_SEARCH_API_PATH,
	MARKETPLACE_RENEW_SUBSCRIPTION_PATH,
} from '../components/constants';
import { Subscription } from '../components/my-subscriptions/types';
import {
	Product,
	ProductCardType,
	ProductType,
	SearchAPIJSONType,
	SearchAPIProductType,
} from '../components/product-list/types';
import { NoticeOptions, NoticeStatus } from '../contexts/types';
import { noticeStore } from '../contexts/notice-store';
⋮----
interface ProductGroup {
	id: string;
	title: string;
	description: string;
... (105 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/utils/tracking.ts">
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { getAdminSetting } from '~/utils/admin-settings';
⋮----
interface MarketplaceViewProps {
	view?: string;
	search_term?: string;
	product_type?: string;
	category?: string;
}
⋮----
function isWCComConnected(): boolean
⋮----
function recordMarketplaceView( props: MarketplaceViewProps )
⋮----
function recordLegacyTabView( props: MarketplaceViewProps )
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/index.tsx">
import { useContext } from '@wordpress/element';
⋮----
import {
	MarketplaceContextProvider,
	MarketplaceContext,
} from './contexts/marketplace-context';
import Header from './components/header/header';
import Content from './components/content/content';
import Footer from './components/footer/footer';
⋮----
function MarketplaceComponents()
⋮----
export default function Marketplace()
</file>

<file path="plugins/woocommerce/client/admin/client/marketplace/README.md">
# Marketplace

This folder contains the components used in the Marketplace page found in `WooCommerce > Extensions`.

The page contains two parts, the WooCommerce.com marketplace and a list of products the user purchased.

## Marketplace Tabs

- **Discover**: A curated list of extensions and themes.
- **Browse**: All extensions.
- **Themes**: All themes.
- **Business Services**: All business services.
- **Search**: Search results.

### Marketplace API

The Marketplace API handles interactions with WooCommerce.com and local product data. Here are the main endpoints:

1. **Product Discovery**:
   - `/wc/v3/marketplace/featured`: Gets curated extensions and themes for the Discover page.
     (Source: `class-wc-helper-admin.php` → `class-wc-admin-addons.php`)
   - `/wp-json/wccom-extensions/1.0/search`: Searches WooCommerce.com products.
     (Source: `fetchSearchResults()` in `./utils/functions.tsx`)
   - `wp-json/wccom-extensions/1.0/categories`: Returns a list of categories.
     (Source: `fetchCategories()` in `./utils/functions.tsx`)

API responses are cached locally for performance, with automatic cache invalidation on product updates and user activity.

### Discover page

... (32 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/mobile-app-login/index.tsx">
import { __ } from '@wordpress/i18n';
import { Card, CardBody } from '@wordpress/components';
import { useEffect } from '@wordpress/element';
import interpolateComponents from '@automattic/interpolate-components';
import { Link } from '@woocommerce/components';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { QRDirectLoginCode } from '~/homescreen/mobile-app-modal/components/QRDirectLoginCode';
import WooLogo from '~/core-profiler/components/navigation/woologo';
⋮----
recordEvent(
												'mobile_app_qr_login_page_faq_click'
											);
</file>

<file path="plugins/woocommerce/client/admin/client/mobile-app-login/README.md">
# Mobile app login

Standalone wc-admin page that lets a logged-in merchant sign in to the Woo
mobile app on their phone by scanning a QR code.

## Audience

Merchants who already have the Woo mobile app installed on their phone and
want a direct, one-shot way to sign in — without going through the onboarding
modal on the wc-admin home screen.

## Route

`/wp-admin/admin.php?page=wc-admin&path=/mobile-app-login`

Registered in `client/admin/client/layout/controller.js` with capability
`manage_woocommerce`, so admins and shop managers can reach it.

## Scope

Application Password flow only. The WordPress.com multi-store flow is deferred
to a future task. The page's single-column layout leaves room below the QR for
a future secondary CTA, so adding that flow later does not require a
structural rewrite.

## Reused components

- `<QRDirectLoginCode />` from
  `client/admin/client/homescreen/mobile-app-modal/components/QRDirectLoginCode.tsx`
  renders the QR, countdown, and in-QR FAQ link.
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/mobile-banner/app-icon.js">
export const AppIcon = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/mobile-banner/banner.js">
export const Banner = (
</file>

<file path="plugins/woocommerce/client/admin/client/mobile-banner/constants.js">

</file>

<file path="plugins/woocommerce/client/admin/client/mobile-banner/index.js">
export const MobileAppBanner = () =>
⋮----
const onClick = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/order-attribution-install-banner/order-editor/slot.js">
export const possiblyRenderOrderAttributionSlot = () =>
⋮----
const OrderAttributionInstallBannerSlotFill = () =>
⋮----
export const registerOrderAttributionSlotFill = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/order-attribution-install-banner/constants.js">

</file>

<file path="plugins/woocommerce/client/admin/client/order-attribution-install-banner/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/order-attribution-install-banner/order-attribution-install-banner-image.js">
export const OrderAttributionInstallBannerImage = () => (
	<svg
		width="156"
		height="159"
		viewBox="0 0 156 159"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<rect width="156" height="159" fill="white" />
		<rect width="156" height="156" fill="white" />
		<g clipPath="url(#clip0_3975_26572)">
			<rect
				width="142"
				height="142"
				transform="translate(7 7)"
				fill="white"
			/>
			<path
				fillRule="evenodd"
				clipRule="evenodd"
				d="M20.0991 114.984C4.18584 87.4212 6.33794 56.3867 24.906 45.6664C34.5846 40.0785 46.813 41.1129 58.557 47.2877C58.4049 35.8334 62.3217 26.3004 70.1893 21.7581C79.375 16.4547 91.7594 19.2167 103.018 27.7644C101.3 19.4633 103.235 11.9843 108.645 8.86056C116.336 4.42016 128.137 10.4618 135.004 22.3549C141.87 34.248 141.202 47.4889 133.511 51.9293C130.493 53.6717 126.842 53.8001 123.105 52.5943C134.129 74.6404 132.449 97.8323 118.695 105.773C112.642 109.268 105.2 109.26 97.606 106.402C99.5298 123.573 94.3634 138.649 82.5332 145.48C63.9651 156.2 36.0124 142.546 20.0991 114.984Z"
				fill="#F2EDFF"
			/>
			<path
				d="M128.714 49.074C131.36 49.074 133.785 49.7708 136 50.7838V41.1364C136 35.1926 132.613 31.8589 126.634 31.8589H29.3611C23.3874 31.8535 20 35.1872 20 41.1311V99.2724H65.7462C63.4879 102.638 61.3157 106.62 61.3157 111.283C61.3157 120.604 68.6067 128.161 77.957 128.161C87.3073 128.161 94.5983 120.604 94.5983 111.283C94.5983 106.62 92.4261 102.638 90.1678 99.2724H136V80.3582C133.785 81.3712 131.36 82.0679 128.714 82.0679C119.412 82.0679 111.869 74.8432 111.869 65.5656C111.869 56.2881 119.412 49.0633 128.714 49.0633V49.074Z"
				fill="#B999FF"
			/>
			<path
				d="M68.268 75.1548H29.5547V79.9785H68.268V75.1548Z"
				fill="#6108CE"
... (31 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/order-attribution-install-banner/order-attribution-install-banner.js">
export const OrderAttributionInstallBanner = ( {
	bannerImage = null,
	bannerType = BANNER_TYPE_BIG,
	eventContext = 'analytics-overview',
	dismissable = false,
	badgeText = '',
	title = '',
	description = '',
	buttonText = '',
} ) =>
⋮----
const onButtonClick = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/order-attribution-install-banner/use-order-attribution-install-banner.js">
const getThreshold = ( percentages ) =>
⋮----
const shouldPromoteOrderAttribution = (
	remoteVariantAssignment,
	percentages
) =>
⋮----
export const useOrderAttributionInstallBanner = (
⋮----
const dismiss = ( eventContext = 'analytics-overview' ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/payments/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/payments/payment-recommendations-wrapper.tsx">
import { EmbeddedBodyProps } from '../embedded-body-layout/embedded-body-props';
⋮----
export const PaymentRecommendations = (
</file>

<file path="plugins/woocommerce/client/admin/client/payments/payment-recommendations.tsx">
import { __ } from '@wordpress/i18n';
import { useSelect, useDispatch } from '@wordpress/data';
import { decodeEntities } from '@wordpress/html-entities';
import { Card, CardHeader, CardFooter, Button } from '@wordpress/components';
import { useEffect, useRef, useState } from '@wordpress/element';
import { EllipsisMenu, List, Pill } from '@woocommerce/components';
import { Text } from '@woocommerce/experimental';
import {
	onboardingStore,
	PAYMENT_GATEWAYS_STORE_NAME,
	pluginsStore,
	Plugin,
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { getAdminLink } from '@woocommerce/settings';
⋮----
import { createNoticesFromResponse } from '~/lib/notices';
import { getPluginSlug } from '~/utils';
import { isWcPaySupported } from './utils';
import { TrackedLink } from '~/components/tracked-link/tracked-link';
⋮----
const dismissPaymentRecommendations = async () =>
⋮----
const setupPlugin = ( plugin: Plugin ) =>
⋮----
onClick=
⋮----
label=
</file>

<file path="plugins/woocommerce/client/admin/client/payments/payment-settings-banner.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { getAdminLink } from '@woocommerce/settings';
import { paymentSettingsStore } from '@woocommerce/data';
import {
	WCPayBanner,
	WCPayBannerBody,
	WCPayBannerFooter,
} from '@woocommerce/onboarding';
import { recordEvent } from '@woocommerce/tracks';
import { useSelect } from '@wordpress/data';
⋮----
import { getAdminSetting } from '~/utils/admin-settings';
import { usePaymentsBanner } from './use-payments-banner';
⋮----
const recordTrack = () =>
⋮----
const WCPaySettingBanner = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/payments/payments-settings-banner-slotfill.js">
const PaymentsBannerFill = () =>
⋮----
export const registerPaymentsSettingsBannerFill = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/payments/use-payments-banner.ts">
import { useSelect } from '@wordpress/data';
import {
	onboardingStore,
	PAYMENT_GATEWAYS_STORE_NAME,
	PaymentGateway,
} from '@woocommerce/data';
⋮----
import { isWcPaySupported } from './utils';
⋮----
export const usePaymentsBanner = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/payments/utils.ts">
import { Plugin } from '@woocommerce/data';
⋮----
export const isWcPaySupported = ( paymentGatewaySuggestions: Plugin[] )
</file>

<file path="plugins/woocommerce/client/admin/client/payments-welcome/apms.tsx">
import { List } from '@woocommerce/components';
import { download, Icon } from '@wordpress/icons';
⋮----
import {
	Card,
	CardBody,
	CardFooter,
	CardHeader,
	ExternalLink,
	Notice,
	ToggleControl,
} from '@wordpress/components';
⋮----
import strings from './strings';
import { WC_ASSET_URL } from '~/utils/admin-settings';
⋮----
export interface Apm {
	id: string;
	title: string;
	icon: string;
	description: string;
	link: string;
	extension: string;
}
⋮----
interface ApmListProps {
	enabledApms: Set< Apm >;
	setEnabledApms: ( value: Set< Apm > ) => void;
}
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/payments-welcome/banner.tsx">
import { Card, CardBody, Button, CardDivider } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { WooPaymentsMethodsLogos } from '@woocommerce/onboarding';
import { useSelect } from '@wordpress/data';
import { paymentSettingsStore } from '@woocommerce/data';
⋮----
import { getAdminSetting } from '~/utils/admin-settings';
import sanitizeHTML from '~/lib/sanitize-html';
import WooPaymentsLogo from './woopayments.svg';
import ExitSurveyModal from './exit-survey-modal';
import strings from './strings';
⋮----
interface Props {
	isSubmitted: boolean;
	handleSetup: () => void;
}
⋮----
const handleNoThanks = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/payments-welcome/exit-survey-modal.tsx">
import { useState } from '@wordpress/element';
import {
	Button,
	Modal,
	CheckboxControl,
	TextareaControl,
} from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { optionsStore } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { getAdminSetting } from '~/utils/admin-settings';
import strings from './strings';
⋮----
function ExitSurveyModal( {}: {
	setExitSurveyModalOpen: Function;
} ): JSX.Element | null
⋮----
const closeModal = async () =>
⋮----
const exitSurvey = () =>
⋮----
const sendFeedback = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/payments-welcome/faq-simple.tsx">
import { Card } from '@wordpress/components';
import { Icon, help } from '@wordpress/icons';
⋮----
import strings from './strings';
⋮----
const FrequentlyAskedQuestionsSimple = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/payments-welcome/index.tsx">
import { Notice } from '@wordpress/components';
import { useState, useEffect } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
import { useDispatch, useSelect } from '@wordpress/data';
import { optionsStore, pluginsStore } from '@woocommerce/data';
import apiFetch from '@wordpress/api-fetch';
⋮----
import Banner from './banner';
import ApmList, { Apm } from './apms';
⋮----
import { getAdminSetting } from '~/utils/admin-settings';
import FrequentlyAskedQuestionsSimple from './faq-simple';
⋮----
interface activatePromoResponse {
	success: boolean;
}
⋮----
const determineTrackingSource = () =>
⋮----
// Determine where the user came from.
⋮----
const activatePromo = async () =>
⋮----
const trackConnectAccountClicked = () =>
⋮----
const handleSetup = async () =>
</file>

<file path="plugins/woocommerce/client/admin/client/payments-welcome/strings.tsx">
import { __, _n, sprintf } from '@wordpress/i18n';
import { createInterpolateElement } from '@wordpress/element';
</file>

<file path="plugins/woocommerce/client/admin/client/settings/conflict-error-slotfill.js">
const LearnMore = () => (
	<Button
		href="https://woocommerce.com/document/setting-up-taxes-in-woocommerce/"
		target="_blank"
	>
		{ __( 'Learn more', 'woocommerce' ) }
	</Button>
);
⋮----
const SettingsErrorFill = () =>
⋮----
const handleApplyRecommendedSettings = () =>
⋮----
const ApplyRecommendedSettingsButton = () => (
		<Button variant="primary" onClick={ handleApplyRecommendedSettings }>
			{ __( 'Use recommended settings', 'woocommerce' ) }
		</Button>
	);
⋮----
export const registerTaxSettingsConflictErrorFill = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings/settings-slots.js">
export const possiblyRenderSettingsSlots = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings/settings-ui-registry.tsx">
import { createElement, createRoot } from '@wordpress/element';
import type { ComponentType, ReactNode } from 'react';
import type { SettingsUISchema } from '@woocommerce/settings-ui';
⋮----
import { getAdminSetting } from '~/utils/admin-settings';
⋮----
interface Window {
		wc?: {
			settingsUi?: {
				SettingsUIErrorBoundary: ComponentType< {
					children: ReactNode;
				} >;
				SettingsUIPage: ( props: {
					schema: SettingsUISchema;
					page: string;
					section?: string;
				} ) => JSX.Element | null;
			};
		};
	}
⋮----
const getSchema = (
	page: string,
	section: string
): SettingsUISchema | undefined =>
⋮----
export const registerSettingsUIScreens = () =>
⋮----
// eslint-disable-next-line no-console
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/build-email-editor-review-url.ts">
export function buildEmailEditorReviewUrl( postId: number ): string
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/icon-feedback.tsx">
import { SVG } from '@wordpress/primitives';
⋮----
const FeedbackIcon = ( { size = 12 }: { size?: number } ) => (
	<SVG
		width={ size }
		height={ size + 1 }
		viewBox="0 -1 12 12"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<path
			fillRule="evenodd"
			clipRule="evenodd"
			d="M2.45865 9.08341L1.6665 9.87639L1.6665 1.66675L10.3332 1.66675L10.3332 9.08341L2.45865 9.08341ZM2.87317 10.0834L10.6665 10.0834C11.0347 10.0834 11.3332 9.78494 11.3332 9.41675L11.3332 1.33342C11.3332 0.965226 11.0347 0.666748 10.6665 0.666748H1.33317C0.964982 0.666748 0.666504 0.965225 0.666504 1.33341V11.0166C0.666504 11.2116 0.773993 11.3907 0.946074 11.4825C1.15124 11.5919 1.40385 11.5543 1.56818 11.3898L2.87317 10.0834ZM8.6665 4.66673H3.33317V3.66673H8.6665V4.66673ZM3.33317 7.33339H6.6665V6.33339H3.33317V7.33339Z"
			fill="currentColor"
		/>
	</SVG>
);
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-ces-feedback.tsx">
import { Button, TextareaControl, TextControl } from '@wordpress/components';
import { isEmail } from '@wordpress/url';
import { __ } from '@wordpress/i18n';
import { useDispatch } from '@wordpress/data';
import { useCallback, useEffect, useRef } from '@wordpress/element';
import { STORE_KEY as CES_STORE_KEY } from '@woocommerce/customer-effort-score';
⋮----
import FeedbackIcon from './icon-feedback';
⋮----
interface EmailCesFeedbackProps {
	action: string;
	description?: string;
	question: string;
	showOnLoad?: boolean;
}
⋮----
label=
⋮----
setExtraFieldsValues(
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-color-palette-control.tsx">
import { Button, ToggleControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useEffect, useState } from '@wordpress/element';
⋮----
import { DefaultColors } from './settings-email-color-palette-slotfill';
import {
	setColors,
	getColors,
	areColorsChanged,
	addListeners,
	removeListeners,
} from './settings-email-color-palette-functions';
⋮----
type ResetStylesControlProps = {
	defaultColors: DefaultColors;
	hasThemeJson: boolean;
	autoSync: boolean;
	autoSyncInput: HTMLInputElement;
};
⋮----
const handleAutoSyncToggle = ( newValue: boolean ) =>
⋮----
const handleInputChange = () =>
⋮----
const handleReset = () =>
⋮----
const handleUndo = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-color-palette-functions.tsx">
import { DefaultColors } from './settings-email-color-palette-slotfill';
⋮----
const setColor = ( inputId: string, color: string ) =>
⋮----
const getColor = ( inputId: string ): string =>
⋮----
export const setColors = ( colors: DefaultColors ) =>
⋮----
export const getColors = (): DefaultColors =>
⋮----
export const areColorsChanged = ( colors: DefaultColors ): boolean =>
⋮----
export const addListeners = ( listener: () => void ) =>
⋮----
export const removeListeners = ( listener: () => void ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-color-palette-slotfill.tsx">
import { createSlotFill } from '@wordpress/components';
import { registerPlugin } from '@wordpress/plugins';
⋮----
import { SETTINGS_SLOT_FILL_CONSTANT } from '~/settings/settings-slots';
import { ResetStylesControl } from './settings-email-color-palette-control';
⋮----
export type DefaultColors = {
	baseColor: string;
	bgColor: string;
	bodyBgColor: string;
	bodyTextColor: string;
	footerTextColor: string;
};
⋮----
type EmailColorPaletteFillProps = {
	defaultColors: DefaultColors;
	hasThemeJson: boolean;
	autoSync: boolean;
	autoSyncInput: HTMLInputElement;
};
⋮----
const EmailColorPaletteFill = ( {
	defaultColors,
	hasThemeJson,
	autoSync,
	autoSyncInput,
}: EmailColorPaletteFillProps ) =>
⋮----
export const registerSettingsEmailColorPaletteFill = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-feedback-slotfill.tsx">
import { createSlotFill } from '@wordpress/components';
import { registerPlugin } from '@wordpress/plugins';
import { __ } from '@wordpress/i18n';
⋮----
import { SETTINGS_SLOT_FILL_CONSTANT } from '~/settings/settings-slots';
import { EmailCesFeedback } from './settings-email-ces-feedback';
⋮----
const EmailFeedbackFill = () =>
⋮----
export const registerSettingsEmailFeedbackFill = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-image-url-existing-image.tsx">
import { Button } from '@wordpress/components';
import { useEffect, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
⋮----
import { selectImage, removeImage } from './settings-email-image-url-handlers';
⋮----
type ExistingImageProps = {
	inputId: string;
	setImageUrl: ( imageUrl: string ) => void;
	imageUrl: string;
};
⋮----
const handleChange = ( jqEvent: JQuery.Event ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-image-url-handlers.tsx">
export const selectImage = (
	inputId: string,
	setImageUrl: ( imageUrl: string ) => void
) =>
⋮----
const select_image = () =>
⋮----
export const removeImage = (
	inputId: string,
	setImageUrl: ( imageUrl: string ) => void
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-image-url-new-image.tsx">
import { __ } from '@wordpress/i18n';
⋮----
import imageUploadIcon from './icon-image-upload.svg';
import { selectImage } from './settings-email-image-url-handlers';
⋮----
type NewImageProps = {
	inputId: string;
	setImageUrl: ( imageUrl: string ) => void;
};
⋮----
onClick=
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-image-url-slotfill.tsx">
import { createSlotFill } from '@wordpress/components';
import { registerPlugin } from '@wordpress/plugins';
import { useState } from '@wordpress/element';
⋮----
import { SETTINGS_SLOT_FILL_CONSTANT } from '~/settings/settings-slots';
import { ExistingImage } from './settings-email-image-url-existing-image';
import { NewImage } from './settings-email-image-url-new-image';
⋮----
type EmailImageUrlFillProps = {
	inputId: string;
	initImageUrl: string;
};
⋮----
const EmailImageUrlFill = ( {
	inputId,
	initImageUrl,
}: EmailImageUrlFillProps ) =>
⋮----
export const registerSettingsEmailImageUrlFill = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-listing-data.ts">
import { Post, useEntityRecords } from '@wordpress/core-data';
import { useDispatch, select, subscribe } from '@wordpress/data';
import { settingsStore } from '@woocommerce/data';
import { useState, useCallback, useMemo } from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';
⋮----
import type { View } from '@wordpress/dataviews/wp';
⋮----
import {
	EmailType,
	EmailStatus,
	TemplateStatus,
} from './settings-email-listing-slotfill';
import { shouldShowReviewUpdate } from './settings-email-listing-update-state';
import { getAdminSetting } from '~/utils/admin-settings';
⋮----
type EmailListingRecreateEmailPostResponse = {
	message: string;
	post_id: string;
};
⋮----
type WPError = {
	message: string;
	code: string;
	data: {
		status: number;
	};
};
⋮----
const emailListingNonce = () =>
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-listing-listview.tsx">
import { useState, useMemo } from '@wordpress/element';
import { dispatch } from '@wordpress/data';
import { pencil, external } from '@wordpress/icons';
import { Icon } from '@wordpress/components';
import { getAdminLink } from '@woocommerce/settings';
import { __ } from '@wordpress/i18n';
⋮----
import { DataViews, View } from '@wordpress/dataviews/wp';
⋮----
import { EmailType } from './settings-email-listing-slotfill';
import { useTransactionalEmails } from './settings-email-listing-data';
import { shouldShowReviewUpdate } from './settings-email-listing-update-state';
import { Status, EMAIL_STATUSES } from './settings-email-listing-status';
import { RecipientsList } from './settings-email-listing-recipients';
import { UpdatesCell } from './settings-email-listing-update-cell';
import {
	SendTestEmailForm,
	useSendTestEmail,
} from './settings-email-send-test';
⋮----
const SendTestEmailModalContent = ( {
	email,
	onClose,
}: {
	email: EmailType;
onClose: ()
⋮----
getItemId=
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-listing-recipients.tsx">
import { __ } from '@wordpress/i18n';
import { Tooltip, Button } from '@wordpress/components';
⋮----
import { Recipients } from './settings-email-listing-slotfill';
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-listing-slotfill.tsx">
import { createSlotFill, Button, Notice } from '@wordpress/components';
import { registerPlugin } from '@wordpress/plugins';
import { lazy, Suspense, useEffect, useState } from '@wordpress/element';
import { dispatch } from '@wordpress/data';
import { __, isRTL } from '@wordpress/i18n';
import { getAdminLink } from '@woocommerce/settings';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { SETTINGS_SLOT_FILL_CONSTANT } from '~/settings/settings-slots';
import type { ListView as ListViewComponent } from './settings-email-listing-listview';
import { recreateEmailPostRequest } from './settings-email-listing-data';
import { shouldShowReviewUpdate } from './settings-email-listing-update-state';
import { VIEWED_FROM_EMAIL_LIST } from '../wp-admin-scripts/email-editor-integration/tracks/build-shared-payload';
⋮----
export const registerSettingsEmailListingFill = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-listing-status.tsx">
import { __ } from '@wordpress/i18n';
import { scheduled, published, cancelCircleFilled } from '@wordpress/icons';
import { __experimentalHStack as HStack, Icon } from '@wordpress/components';
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-listing-update-cell.story.tsx">
import type { EmailType } from './settings-email-listing-slotfill';
import { UpdatesCell } from './settings-email-listing-update-cell';
⋮----
export const CoreUpdatedCustomized = () => (
	<UpdatesCell
		post={ {
			...baseEmail,
			templateStatus: 'core_updated_customized',
			templateVersion: '10.6.0',
			currentVersion: '10.7.0',
		} }
	/>
);
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-listing-update-cell.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { getAdminLink } from '@woocommerce/settings';
⋮----
import type { EmailType } from './settings-email-listing-slotfill';
import { buildEmailEditorReviewUrl } from './build-email-editor-review-url';
import { shouldShowReviewUpdate } from './settings-email-listing-update-state';
⋮----
export interface UpdatesCellProps {
	post: EmailType;
}
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-listing-update-state.ts">
import type { EmailType } from './settings-email-listing-slotfill';
⋮----
export function compareTemplateVersions( a: string, b: string ): number
⋮----
export function shouldShowReviewUpdate( post: EmailType ): boolean
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-preview-device-type.tsx">
import { __ } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import desktopIcon from './icon-desktop.svg';
import desktopActiveIcon from './icon-desktop-active.svg';
import mobileIcon from './icon-mobile.svg';
import mobileActiveIcon from './icon-mobile-active.svg';
⋮----
type EmailPreviewDeviceTypeProps = {
	deviceType: string;
	setDeviceType: ( deviceType: string ) => void;
};
⋮----
const setDesktop = () =>
const setMobile = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-preview-header.tsx">
import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
⋮----
import avatarIcon from './icon-avatar.svg';
import { emailPreviewNonce } from './settings-email-preview-nonce';
⋮----
type EmailPreviewHeaderProps = {
	emailType: string;
};
⋮----
type EmailPreviewSubjectResponse = {
	subject: string;
};
⋮----
export const EmailPreviewHeader = ( {
	emailType,
}: EmailPreviewHeaderProps ) =>
⋮----
const handleFromNameChange = ( event: Event ) =>
const handleFromAddressChange = ( event: Event ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-preview-iframe.tsx">
import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
import { useEffect, useRef, useState } from '@wordpress/element';
import { debounce } from 'lodash';
⋮----
import { emailPreviewNonce } from './settings-email-preview-nonce';
⋮----
type EmailPreviewIframeProps = {
	src: string;
	isLoading: boolean;
	setIsLoading: ( isLoading: boolean ) => void;
	settingsIds: string[];
};
⋮----
export const EmailPreviewIframe = ( {
	src,
	isLoading,
	setIsLoading,
	settingsIds,
}: EmailPreviewIframeProps ) =>
⋮----
const handleFieldChange = async ( jqEvent: JQuery.Event ) =>
⋮----
onLoad=
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-preview-nonce.tsx">
import { getAdminSetting } from '~/utils/admin-settings';
⋮----
export const emailPreviewNonce = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-preview-send.tsx">
import { Button, Modal } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
⋮----
import {
	SendTestEmailForm,
	useSendTestEmail,
} from './settings-email-send-test';
⋮----
type EmailPreviewSendProps = {
	type: string;
};
⋮----
const closeModal = () =>
⋮----
title=
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-preview-slotfill.tsx">
import { createSlotFill, Spinner } from '@wordpress/components';
import { SelectControlSingleSelectionProps } from '@wordpress/components/build-types/select-control/types';
import { registerPlugin } from '@wordpress/plugins';
import { useEffect, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { debounce } from 'lodash';
⋮----
import { SETTINGS_SLOT_FILL_CONSTANT } from '~/settings/settings-slots';
import {
	EmailPreviewDeviceType,
	DEVICE_TYPE_DESKTOP,
} from './settings-email-preview-device-type';
import { EmailPreviewHeader } from './settings-email-preview-header';
import { EmailPreviewIframe } from './settings-email-preview-iframe';
import { EmailPreviewSend } from './settings-email-preview-send';
import { EmailPreviewType } from './settings-email-preview-type';
import { EmailCesFeedback } from './settings-email-ces-feedback';
⋮----
export type EmailTypes = NonNullable<
	SelectControlSingleSelectionProps[ 'options' ]
>;
⋮----
type EmailPreviewFillProps = {
	emailTypes: EmailTypes;
	previewUrl: string;
	settingsIds: string[];
};
⋮----
export const registerSettingsEmailPreviewFill = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-preview-type.tsx">
import { SelectControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
import { EmailTypes } from './settings-email-preview-slotfill';
⋮----
type EmailPreviewTypeProps = {
	emailTypes: EmailTypes;
	emailType: string;
	setEmailType: ( emailType: string ) => void;
};
</file>

<file path="plugins/woocommerce/client/admin/client/settings-email/settings-email-send-test.tsx">
import { Button, TextControl } from '@wordpress/components';
import { Icon, check, cautionFilled } from '@wordpress/icons';
import apiFetch from '@wordpress/api-fetch';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { emailPreviewNonce } from './settings-email-preview-nonce';
⋮----
export const isValidEmail = ( email: string ) =>
⋮----
type SendTestEmailResponse = {
	message: string;
};
⋮----
export type WPError = {
	message: string;
	code: string;
	data: {
		status: number;
	};
};
⋮----
export function friendlyEmailSendError( wpError: WPError ): string
⋮----
// Covers both WP core (rest_cookie_invalid_nonce) and Woo's own
⋮----
export type SendTestEmailSource = 'email_preview' | 'email_listing';
⋮----
export type SendTestEmailTarget =
... (32 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/bank-accounts-list/bank-account-modal.tsx">
import {
	Modal,
	TextControl,
	SelectControl,
	Button,
} from '@wordpress/components';
import { decodeEntities } from '@wordpress/html-entities';
import { useState } from 'react';
import { __ } from '@wordpress/i18n';
⋮----
import { BankAccount } from './types';
import {
	formatSortCode,
	getSortCodeLabel,
	shouldDisplaySortCode,
} from './utils';
import { validateRequiredField } from './validation';
⋮----
interface Props {
	account: BankAccount | null;
	onClose: () => void;
	onSave: ( account: BankAccount ) => void;
	defaultCountry: string;
}
⋮----
/**
	 * Validates the form fields and sets error messages accordingly.
	 *
	 * @return {boolean} True if the form is valid, false otherwise.
	 */
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/bank-accounts-list/bank-accounts-list.tsx">
import { Button, MenuGroup, MenuItem, Modal } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { EllipsisMenu } from '@woocommerce/components';
import { useState, useEffect } from 'react';
⋮----
import { BankAccount } from './types';
import { BankAccountModal } from './bank-account-modal';
import { generateId } from './utils';
import {
	DefaultDragHandle,
	SortableContainer,
	SortableItem,
} from '~/settings-payments/components/sortable';
⋮----
interface BankAccountItem extends BankAccount {
	id: string;
}
⋮----
interface Props {
	accounts: BankAccount[];
	onChange: ( accounts: BankAccount[] ) => void;
	defaultCountry: string;
}
⋮----
const openModal = ( account: BankAccountItem | null = null ) =>
⋮----
const handleSave = ( updated: BankAccount ) =>
⋮----
const confirmDelete = () =>
⋮----
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/bank-accounts-list/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/bank-accounts-list/types.ts">
export interface BankAccount {
	account_name: string;
	account_number: string;
	bank_name: string;
	sort_code: string;
	iban: string;
	bic: string;
	country_code?: string;
}
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/bank-accounts-list/utils.ts">
import { __ } from '@wordpress/i18n';
⋮----
export const getSortCodeLabel = ( country: string ): string =>
⋮----
export const shouldDisplaySortCode = ( country: string ): boolean =>
⋮----
export const formatSortCode = ( sortCode: string, country: string ): string =>
⋮----
.replace( /\D/g, '' ) // Remove non-digit characters
.substring( 0, 6 ) // Take only first 6 digits
⋮----
export const generateId = (): string
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/bank-accounts-list/validation.ts">
export const validateRequiredField = ( value: string ): string | undefined =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/buttons/activate-payments-button.tsx">
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { PaymentsProviderIncentive } from '@woocommerce/data';
import apiFetch from '@wordpress/api-fetch';
⋮----
import {
	getWooPaymentsSetupLiveAccountLink,
	recordPaymentsEvent,
	recordPaymentsOnboardingEvent,
} from '~/settings-payments/utils';
import {
	wooPaymentsExtensionSlug,
	wooPaymentsOnboardingSessionEntrySettings,
	wooPaymentsProviderId,
	wooPaymentsSuggestionId,
} from '~/settings-payments/constants';
⋮----
interface ActivatePaymentsButtonProps {
	acceptIncentive: ( id: string ) => void;
	buttonText?: string;
	incentive?: PaymentsProviderIncentive | null;
	installingPlugin: string | null;
	setOnboardingModalOpen: ( isOnboardingModalOpen: boolean ) => void;
	onboardingType?: string;
	disableTestAccountUrl?: string;
}
⋮----
export const ActivatePaymentsButton = ( {
	acceptIncentive,
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/buttons/back-button.tsx">
import { type ReactNode } from 'react';
import { __, isRTL } from '@wordpress/i18n';
import { Button, Tooltip } from '@wordpress/components';
import clsx from 'clsx';
import { chevronLeft, chevronRight } from '@wordpress/icons';
import { getHistory } from '@woocommerce/navigation';
⋮----
import { recordPaymentsEvent } from '~/settings-payments/utils';
⋮----
interface BackButtonProps {
	href: string;
	tooltipText?: string;
	isRoute?: boolean;
	from?: string;
	children?: ReactNode;
}
⋮----
const onGoBack = () =>
⋮----
// Record the event when the user clicks the button.
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/buttons/complete-setup-button.tsx">
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { useState, useEffect } from '@wordpress/element';
import {
	PaymentGatewayProvider,
	PaymentsProviderIncentive,
	woopaymentsOnboardingStore,
} from '@woocommerce/data';
import { useSelect } from '@wordpress/data';
⋮----
import {
	isWooPayments,
	recordPaymentsOnboardingEvent,
	recordPaymentsProviderEvent,
} from '~/settings-payments/utils';
import { wooPaymentsOnboardingSessionEntrySettings } from '~/settings-payments/constants';
import { WooPaymentsUpdateRequiredModal } from '~/settings-payments/components/modals';
⋮----
interface CompleteSetupButtonProps {
	gatewayProvider: PaymentGatewayProvider;
	settingsHref: string;
	onboardingHref: string;
	gatewayHasRecommendedPaymentMethods: boolean;
	buttonText?: string;
	installingPlugin: string | null;
	setOnboardingModalOpen: ( isOnboardingModalOpen: boolean ) => void;
	onboardingType?: string;
	acceptIncentive?: ( id: string ) => void;
	incentive?: PaymentsProviderIncentive | null;
	disabled?: boolean;
... (20 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/buttons/enable-gateway-button.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { dispatch, useDispatch } from '@wordpress/data';
import {
	EnableGatewayResponse,
	paymentSettingsStore,
	PaymentsProviderIncentive,
	PaymentGatewayProvider,
	OfflinePaymentMethodProvider,
} from '@woocommerce/data';
import { getHistory, getNewPath } from '@woocommerce/navigation';
⋮----
import {
	recordPaymentsOnboardingEvent,
	recordPaymentsProviderEvent,
} from '~/settings-payments/utils';
import { wooPaymentsOnboardingSessionEntrySettings } from '~/settings-payments/constants';
⋮----
interface EnableGatewayButtonProps {
	gatewayProvider: PaymentGatewayProvider | OfflinePaymentMethodProvider;
	settingsHref: string;
	onboardingHref: string;
	isOffline: boolean;
	acceptIncentive?: ( id: string ) => void;
	gatewayHasRecommendedPaymentMethods: boolean;
	installingPlugin?: string | null;
	buttonText?: string;
	incentive?: PaymentsProviderIncentive | null;
	setOnboardingModalOpen?: ( isOnboardingModalOpen: boolean ) => void;
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/buttons/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/buttons/reactivate-live-payments-button.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { dispatch, useDispatch } from '@wordpress/data';
import { paymentSettingsStore } from '@woocommerce/data';
import apiFetch from '@wordpress/api-fetch';
⋮----
import { recordPaymentsEvent } from '~/settings-payments/utils';
import {
	wooPaymentsExtensionSlug,
	wooPaymentsProviderId,
	wooPaymentsSuggestionId,
} from '~/settings-payments/constants';
⋮----
interface ReactivateLivePaymentsButtonProps {
	buttonText?: string;
	settingsHref: string;
}
⋮----
export const ReactivateLivePaymentsButton = ( {
	buttonText = __( 'Reactivate payments', 'woocommerce' ),
	settingsHref,
}: ReactivateLivePaymentsButtonProps ) =>
⋮----
const disableTestModePayments = ( e: React.MouseEvent ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/buttons/settings-button.tsx">
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import {
	OfflinePaymentMethodProvider,
	PaymentGatewayProvider,
	paymentGatewaysStore,
} from '@woocommerce/data';
import { useNavigate } from 'react-router-dom';
import { useDispatch } from '@wordpress/data';
import { getQueryArg } from '@wordpress/url';
import { MouseEvent } from 'react';
⋮----
import {
	recordPaymentsProviderEvent,
	removeOriginFromURL,
} from '~/settings-payments/utils';
⋮----
interface SettingsButtonProps {
	gatewayProvider: PaymentGatewayProvider | OfflinePaymentMethodProvider;
	settingsHref: string;
	buttonText?: string;
	isInstallingPlugin?: boolean;
}
⋮----
export const SettingsButton = ( {
	gatewayProvider,
	settingsHref,
	isInstallingPlugin,
	buttonText = __( 'Manage', 'woocommerce' ),
}: SettingsButtonProps ) =>
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/country-selector/country-selector.tsx">
import { useRef, useState } from 'react';
import clsx from 'clsx';
import { useSelect } from 'downshift';
import { Button } from '@wordpress/components';
import { useThrottle } from '@wordpress/compose';
import { useCallback, useEffect } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { check, chevronDown, Icon } from '@wordpress/icons';
⋮----
import { WC_ASSET_URL } from '~/utils/admin-settings';
import { Item, ControlProps } from './types';
⋮----
const getOptionLabel = ( value: string, options: Item[] ) =>
⋮----
/**
 * Removes accents and diacritical marks from a given string.
 *
 * This function uses Unicode normalization to decompose accented characters into their base characters
 * and diacritical marks, then removes the diacritical marks. It is commonly used for case-insensitive
 * and accent-insensitive text searches or comparisons.
 *
 * @example
 * // Returns 'Cafe'
 * removeAccents('Café');
 *
 *
 * removeAccents('áèêíòóú');
 */
const removeAccents = ( str: string ) =>
⋮----
... (35 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/country-selector/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/country-selector/types.ts">
export interface Item {
	key: string;
	name?: string;
	className?: string;
	style?: React.CSSProperties;
}
⋮----
export interface ControlProps< ItemType > {
	name?: string;
	className?: string;
	label: string;
	describedBy?: string;
	options: ItemType[];
	value: ItemType;
	placeholder?: string;
	onChange: ( value: string ) => void;
	children?: ( item: ItemType ) => JSX.Element;
}
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/ellipsis-menu-content/ellipsis-menu-content.tsx">
import { Button, CardDivider } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import {
	pluginsStore,
	paymentSettingsStore,
	PaymentsProviderLink,
	PaymentsProvider,
} from '@woocommerce/data';
import { useDispatch } from '@wordpress/data';
import { useState } from '@wordpress/element';
⋮----
import { recordPaymentsProviderEvent } from '~/settings-payments/utils';
⋮----
interface EllipsisMenuContentProps {
	provider: PaymentsProvider;
	pluginFile: string;
	isSuggestion: boolean;
	onToggle: () => void;
	links?: PaymentsProviderLink[];
	canResetAccount?: boolean;
	setResetAccountModalVisible?: ( isVisible: boolean ) => void;
	isEnabled?: boolean;
	canResetOnboarding?: boolean;
}
⋮----
const deactivateProviderExtension = () =>
⋮----
const disableProvider = () =>
⋮----
const hideSuggestion = () =>
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/ellipsis-menu-content/ellipsis-menu.tsx">
import { EllipsisMenu } from '@woocommerce/components';
import { PaymentsProvider } from '@woocommerce/data';
import { useState } from '@wordpress/element';
⋮----
import { EllipsisMenuContent } from '~/settings-payments/components/ellipsis-menu-content';
import { isWooPayments } from '~/settings-payments/utils';
import { WooPaymentsResetAccountModal } from '~/settings-payments/components/modals';
⋮----
interface EllipsisMenuProps {
	label: string;
	provider: PaymentsProvider;
}
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/ellipsis-menu-content/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/field-placeholder/field-placeholder.tsx">
import { Placeholder } from '@wordpress/components';
⋮----
export type FieldPlaceholderSize = 'small' | 'medium' | 'large';
⋮----
export const FieldPlaceholder = ( {
	size = 'medium',
}: {
	size?: FieldPlaceholderSize;
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/field-placeholder/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/grid-item-placeholder/grid-item-placeholder.tsx">
export const GridItemPlaceholder = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/grid-item-placeholder/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/header/header.tsx">
import {
	unregisterPlugin,
	registerPlugin,
	getPlugins,
} from '@wordpress/plugins';
import { WooHeaderPageTitle, WooHeaderItem } from '@woocommerce/admin-layout';
import { Button } from '@wordpress/components';
⋮----
interface HeaderProps {
	title: string;
	description?: string;
	hasButton?: boolean;
	buttonLabel?: string;
	onButtonClick?: () => void;
}
⋮----
const unRegisterHeaderItems = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/incentive-banner/incentive-banner.tsx">
import { useEffect } from 'react';
import { Button, Card, CardBody } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { createInterpolateElement, useState } from '@wordpress/element';
import { Link } from '@woocommerce/components';
import {
	PaymentsProviderIncentive,
	PaymentsProvider,
	PaymentsEntity,
} from '@woocommerce/data';
⋮----
import { WC_ASSET_URL } from '~/utils/admin-settings';
⋮----
import { StatusBadge } from '~/settings-payments/components/status-badge';
import {
	isIncentiveDismissedInContext,
	recordPaymentsEvent,
} from '~/settings-payments/utils';
⋮----
interface IncentiveBannerProps {
	incentive: PaymentsProviderIncentive;
	provider: PaymentsProvider;
	onboardingUrl: string | null;
	onAccept: ( id: string ) => void;
	onDismiss: (
		dismissUrl: string,
		context: string,
		doNotTrack?: boolean
	) => void;
	setUpPlugin: (
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/incentive-banner/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/incentive-modal/incentive-modal.tsx">
import { useEffect } from 'react';
import {
	Button,
	Card,
	CardBody,
	CardMedia,
	Modal,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { createInterpolateElement, useState } from '@wordpress/element';
import { Link } from '@woocommerce/components';
import {
	PaymentsProviderIncentive,
	PaymentsProvider,
	PaymentsEntity,
} from '@woocommerce/data';
⋮----
import { StatusBadge } from '~/settings-payments/components/status-badge';
import { WC_ASSET_URL } from '~/utils/admin-settings';
import {
	isIncentiveDismissedInContext,
	recordPaymentsEvent,
} from '~/settings-payments/utils';
⋮----
interface IncentiveModalProps {
	incentive: PaymentsProviderIncentive;
	provider: PaymentsProvider;
	onboardingUrl: string | null;
	onAccept: ( id: string ) => void;
	onDismiss: (
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/incentive-modal/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/incentive-status-badge/incentive-status-badge.tsx">
import { createInterpolateElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Link } from '@woocommerce/components';
import { PaymentsProviderIncentive } from '@woocommerce/data';
⋮----
import { StatusBadge } from '~/settings-payments/components/status-badge';
⋮----
interface IncentiveStatusBadgeProps {
	incentive: PaymentsProviderIncentive;
}
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/incentive-status-badge/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/list-placeholder/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/list-placeholder/list-placeholder.tsx">
import { List } from '@woocommerce/components';
⋮----
import { DefaultDragHandle } from '~/settings-payments/components/sortable';
⋮----
interface ListPlaceholderProps {
	rows: number;
	hasDragIcon?: boolean;
}
⋮----
export const ListPlaceholder = ( {
	rows,
	hasDragIcon = true,
}: ListPlaceholderProps ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/modals/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/modals/woo-payments-post-sandbox-account-setup-modal.tsx">
import { __ } from '@wordpress/i18n';
import { Button, Modal } from '@wordpress/components';
import { Link } from '@woocommerce/components';
import { getAdminLink } from '@woocommerce/settings';
import interpolateComponents from '@automattic/interpolate-components';
import { useState } from '@wordpress/element';
⋮----
import {
	getWooPaymentsSetupLiveAccountLink,
	recordPaymentsEvent,
} from '~/settings-payments/utils';
import { WC_ASSET_URL } from '~/utils/admin-settings';
import {
	wooPaymentsExtensionSlug,
	wooPaymentsProviderId,
	wooPaymentsSuggestionId,
} from '~/settings-payments/constants';
⋮----
interface WooPaymentsReadyToTestModalProps {
	isOpen: boolean;
	devMode: boolean;
	onClose: () => void;
}
⋮----
const handleActivatePayments = () =>
⋮----
const handleContinueStoreSetup = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/modals/woo-payments-reset-account-modal.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { Button, Modal } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import {
	paymentSettingsStore,
	woopaymentsOnboardingStore,
} from '@woocommerce/data';
import apiFetch from '@wordpress/api-fetch';
⋮----
import { recordPaymentsEvent } from '~/settings-payments/utils';
import {
	wooPaymentsExtensionSlug,
	wooPaymentsProviderId,
	wooPaymentsSuggestionId,
} from '~/settings-payments/constants';
⋮----
interface WooPaymentsResetAccountModalProps {
	isOpen: boolean;
	onClose: () => void;
	hasAccount?: boolean;
	isTestMode?: boolean;
	isEmbeddedResetFlow?: boolean;
	resetUrl?: string;
}
⋮----
const handleResetAccount = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/modals/woo-payments-update-required-modal.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { Button, Modal } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { getAdminLink } from '@woocommerce/settings';
⋮----
interface WooPaymentsUpdateRequiredModalProps {
	isOpen: boolean;
	onClose: () => void;
}
⋮----
const handleUpdateWooPayments = () =>
⋮----
title=
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/official-badge/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/official-badge/official-badge.tsx">
import { __ } from '@wordpress/i18n';
import { Popover } from '@wordpress/components';
import { Link, Pill } from '@woocommerce/components';
import { createInterpolateElement, useRef, useState } from '@wordpress/element';
⋮----
import { WC_ASSET_URL } from '~/utils/admin-settings';
import { recordPaymentsEvent } from '~/settings-payments/utils';
⋮----
interface OfficialBadgeProps {
	variant: 'expanded' | 'compact';
	suggestionId: string;
}
⋮----
const handleClick = ( event: React.MouseEvent | React.KeyboardEvent ) =>
⋮----
const handleFocusOutside = () =>
⋮----
const handleKeyDown = ( event: React.KeyboardEvent ) =>
⋮----
recordPaymentsEvent(
														'official_badge_learn_more_click',
														{
															suggestion_id:
																suggestionId,
														}
													);
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/offline-payment-gateway-list/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/offline-payment-gateway-list/offline-payment-gateway-list.tsx">
import { decodeEntities } from '@wordpress/html-entities';
import { type OfflinePaymentMethodProvider } from '@woocommerce/data';
⋮----
import sanitizeHTML from '~/lib/sanitize-html';
import {
	DefaultDragHandle,
	SortableContainer,
	SortableItem,
} from '../sortable';
import {
	EnableGatewayButton,
	SettingsButton,
} from '~/settings-payments/components/buttons';
⋮----
type OfflinePaymentGatewayListItemProps = {
	gateway: OfflinePaymentMethodProvider;
	className?: string;
};
⋮----
{ /* Left section with drag handle and icon */ }
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/other-payment-gateways/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/other-payment-gateways/other-payment-gateways.tsx">
import React from 'react';
import { Gridicon } from '@automattic/components';
import { Button, Popover } from '@wordpress/components';
import { useState, useMemo, useRef } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { decodeEntities } from '@wordpress/html-entities';
import {
	PaymentsEntity,
	SuggestedPaymentsExtension,
	SuggestedPaymentsExtensionCategory,
} from '@woocommerce/data';
⋮----
import { GridItemPlaceholder } from '~/settings-payments/components/grid-item-placeholder';
import { OfficialBadge } from '../official-badge';
import { IncentiveStatusBadge } from '~/settings-payments/components/incentive-status-badge';
import { recordPaymentsEvent } from '~/settings-payments/utils';
⋮----
interface OtherPaymentGatewaysProps {
	suggestions: SuggestedPaymentsExtension[];
	suggestionCategories: SuggestedPaymentsExtensionCategory[];
	installingPlugin: string | null;
	setUpPlugin: (
		provider: PaymentsEntity,
		onboardingUrl: string | null,
		attachUrl: string | null,
		context?: string
	) => void;
	isFetching: boolean;
	morePaymentOptionsLink: JSX.Element;
}
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/payment-extension-suggestion-list-item/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/payment-extension-suggestion-list-item/payment-extension-suggestion-list-item.tsx">
import { decodeEntities } from '@wordpress/html-entities';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { WooPaymentsMethodsLogos } from '@woocommerce/onboarding';
import {
	PaymentsExtensionSuggestionProvider,
	PaymentsEntity,
} from '@woocommerce/data';
⋮----
import sanitizeHTML from '~/lib/sanitize-html';
import { EllipsisMenuWrapper as EllipsisMenu } from '~/settings-payments/components/ellipsis-menu-content';
import {
	isWooPayments,
	hasIncentive,
	isWooPayEligible,
	recordPaymentsProviderEvent,
} from '~/settings-payments/utils';
import { DefaultDragHandle } from '~/settings-payments/components/sortable';
import { StatusBadge } from '~/settings-payments/components/status-badge';
import { IncentiveStatusBadge } from '~/settings-payments/components/incentive-status-badge';
import { OfficialBadge } from '~/settings-payments/components/official-badge';
⋮----
type PaymentExtensionSuggestionListItemProps = {
	suggestion: PaymentsExtensionSuggestionProvider;
	installingPlugin: string | null;
	setUpPlugin: (
		provider: PaymentsEntity,
		onboardingUrl: string | null,
		attachUrl: string | null,
		context?: string
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list/payment-gateway-list.tsx">
import {
	PaymentsEntity,
	PaymentsProvider,
	PaymentsProviderType,
	PaymentGatewayProvider,
	OfflinePmsGroupProvider,
	PaymentsExtensionSuggestionProvider,
} from '@woocommerce/data';
import { Gridicon } from '@automattic/components';
import { useNavigate } from 'react-router-dom';
import { isRTL } from '@wordpress/i18n';
⋮----
import {
	DefaultDragHandle,
	SortableContainer,
	SortableItem,
} from '~/settings-payments/components/sortable';
import { PaymentExtensionSuggestionListItem } from '~/settings-payments/components/payment-extension-suggestion-list-item';
import { PaymentGatewayListItem } from '~/settings-payments/components/payment-gateway-list-item';
⋮----
import { removeOriginFromURL } from '~/settings-payments/utils';
⋮----
interface PaymentGatewayListProps {
	providers: PaymentsProvider[];
	installedPluginSlugs: string[];
	installingPlugin: string | null;
	setUpPlugin: (
		provider: PaymentsEntity,
		onboardingUrl: string | null,
		attachUrl: string | null,
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list-item/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateway-list-item/payment-gateway-list-item.tsx">
import { WooPaymentsMethodsLogos } from '@woocommerce/onboarding';
import { __ } from '@wordpress/i18n';
import { decodeEntities } from '@wordpress/html-entities';
import { PaymentGatewayProvider } from '@woocommerce/data';
import { Tooltip } from '@wordpress/components';
⋮----
import sanitizeHTML from '~/lib/sanitize-html';
import { StatusBadge } from '~/settings-payments/components/status-badge';
import { EllipsisMenuWrapper as EllipsisMenu } from '~/settings-payments/components/ellipsis-menu-content';
import {
	hasIncentive,
	isWooPayEligible,
	isWooPayments,
} from '~/settings-payments/utils';
import { DefaultDragHandle } from '~/settings-payments/components/sortable';
import { WC_ASSET_URL } from '~/utils/admin-settings';
import {
	ActivatePaymentsButton,
	CompleteSetupButton,
	EnableGatewayButton,
	SettingsButton,
} from '~/settings-payments/components/buttons';
import { ReactivateLivePaymentsButton } from '~/settings-payments/components/buttons/reactivate-live-payments-button';
import { IncentiveStatusBadge } from '~/settings-payments/components/incentive-status-badge';
import { OfficialBadge } from '~/settings-payments/components/official-badge';
⋮----
type PaymentGatewayItemProps = {
	gateway: PaymentGatewayProvider;
	installingPlugin: string | null;
	acceptIncentive: ( id: string ) => void;
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateways/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/payment-gateways/payment-gateways.tsx">
import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
import clsx from 'clsx';
import {
	PaymentsEntity,
	PaymentsProvider,
	paymentSettingsStore,
	WC_ADMIN_NAMESPACE,
	woopaymentsOnboardingStore,
} from '@woocommerce/data';
import { useDispatch } from '@wordpress/data';
import { useEffect, useMemo, useRef, useState } from '@wordpress/element';
import { decodeEntities } from '@wordpress/html-entities';
import { Popover } from '@wordpress/components';
import { Link } from '@woocommerce/components';
import { getAdminLink } from '@woocommerce/settings';
import InfoOutline from 'gridicons/dist/info-outline';
import interpolateComponents from '@automattic/interpolate-components';
⋮----
import { CountrySelector } from '~/settings-payments/components/country-selector';
import { ListPlaceholder } from '~/settings-payments/components/list-placeholder';
import { PaymentGatewayList } from '~/settings-payments/components/payment-gateway-list';
import { recordPaymentsEvent } from '~/settings-payments/utils';
⋮----
interface PaymentGatewaysProps {
	providers: PaymentsProvider[];
	installedPluginSlugs: string[];
	installingPlugin: string | null;
	setUpPlugin: (
		provider: PaymentsEntity,
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/settings/index.tsx">
import { Card, CardBody } from '@wordpress/components';
import { useEffect } from 'react';
⋮----
type SettingsProps = {
	children: React.ReactNode;
};
⋮----
const Layout = (
⋮----
const Section = ( {
	title,
	description,
	children,
	id,
}: {
	title: string;
	description: string;
	children?: React.ReactNode;
	id?: string;
} ) => (
	<div className="settings-section" id={ id }>
		<div className="settings-section__details">
			<h2>{ title }</h2>
			<p>{ description }</p>
		</div>
		<div className="settings-section__controls">{ children }</div>
	</div>
);
⋮----
const Actions = ( { children }: SettingsProps ) => (
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/sortable/index.tsx">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/sortable/sortable-container.tsx">
import {
	type DragEndEvent,
	type DragStartEvent,
	closestCenter,
	DndContext,
	KeyboardSensor,
	MouseSensor,
	TouchSensor,
	useSensor,
	useSensors,
} from '@dnd-kit/core';
import {
	SortableContext,
	verticalListSortingStrategy,
	horizontalListSortingStrategy,
	arrayMove,
} from '@dnd-kit/sortable';
import {
	restrictToHorizontalAxis,
	restrictToVerticalAxis,
} from '@dnd-kit/modifiers';
import clsx from 'clsx';
import { useState } from '@wordpress/element';
⋮----
export const SortableContainer = < T extends { id: string } >( {
	items,
	setItems,
	children,
	sorting = 'vertical',
	onDragStart = () => {},
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/sortable/sortable-drag-handle.tsx">
import {
	type DraggableSyntheticListeners,
	type DraggableAttributes,
} from '@dnd-kit/core';
import { createContext, useContext } from '@wordpress/element';
import { dragHandle, Icon } from '@wordpress/icons';
⋮----
type DragHandleContextType = {
	attributes: DraggableAttributes | null;
	listeners: DraggableSyntheticListeners | null;
};
⋮----
export const useDragHandle = ()
⋮----
export const DefaultDragHandle = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/sortable/sortable-item.tsx">
import { useSortable } from '@dnd-kit/sortable';
import clsx from 'clsx';
⋮----
import { DragHandleContext } from './sortable-drag-handle';
⋮----
export const SortableItem = ( {
	id,
	className = '',
	children,
	...props
}: {
	id: string;
	className?: string;
	children: React.ReactNode;
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/status-badge/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/components/status-badge/status-badge.tsx">
import { __ } from '@wordpress/i18n';
import { Pill } from '@woocommerce/components';
import { Popover } from '@wordpress/components';
import { useState, useRef } from '@wordpress/element';
import { Icon, info } from '@wordpress/icons';
⋮----
interface StatusBadgeProps {
	status:
		| 'active'
		| 'inactive'
		| 'needs_setup'
		| 'test_mode'
		| 'test_account'
		| 'recommended'
		| 'has_incentive'
		| 'not_supported';
	message?: string;
	popoverContent?: React.ReactElement;
}
⋮----
const handleClick = ( event: React.MouseEvent | React.KeyboardEvent ) =>
⋮----
const handleFocusOutside = () =>
⋮----
const handleKeyDown = ( event: React.KeyboardEvent ) =>
⋮----
const getStatusClass = () =>
⋮----
/**
	 * Get the default message for the badge based on the status.
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/offline/dataform-controls.tsx">
import {
	CheckboxControl,
	TextControl,
	TextareaControl,
} from '@wordpress/components';
import type { DataFormControlProps } from '@wordpress/dataviews';
⋮----
export type OfflineFormValues = Record< string, string | boolean | string[] >;
⋮----
/**
 * A DataForm edit control that renders a `TextareaControl`, preserving the
 * markup of the previous hand-rolled offline payment method forms.
 */
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/offline/settings-payments-bacs.tsx">
import { __ } from '@wordpress/i18n';
import { useDispatch, useSelect } from '@wordpress/data';
import { Button } from '@wordpress/components';
import { useState, useEffect, useMemo } from '@wordpress/element';
import {
	paymentGatewaysStore,
	optionsStore,
	paymentSettingsStore,
} from '@woocommerce/data';
import { DataForm } from '@wordpress/dataviews';
import type { Field } from '@wordpress/dataviews';
⋮----
import { Settings } from '~/settings-payments/components/settings';
import { FieldPlaceholder } from '~/settings-payments/components/field-placeholder';
import { BankAccountsList } from '~/settings-payments/components/bank-accounts-list';
import { BankAccount } from '~/settings-payments/components/bank-accounts-list/types';
import {
	CheckboxEdit,
	TextEdit,
	TextareaEdit,
	type OfflineFormValues,
} from './dataform-controls';
⋮----
const toCountryCode = ( value: unknown ): string
⋮----
/**
 * This page is used to manage the settings for the BACS (Direct bank transfer) payment gateway.
 */
⋮----
// The Payments settings header lets the merchant set a business location
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/offline/settings-payments-cheque.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useDispatch, useSelect } from '@wordpress/data';
import { paymentGatewaysStore, paymentSettingsStore } from '@woocommerce/data';
import { useState, useEffect, useMemo } from '@wordpress/element';
import { DataForm } from '@wordpress/dataviews';
import type { Field } from '@wordpress/dataviews';
⋮----
import { Settings } from '~/settings-payments/components/settings';
import { FieldPlaceholder } from '~/settings-payments/components/field-placeholder';
import {
	CheckboxEdit,
	TextEdit,
	TextareaEdit,
	type OfflineFormValues,
} from './dataform-controls';
⋮----
const saveSettings = () =>
⋮----
e.preventDefault();
saveSettings();
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/offline/settings-payments-cod.tsx">
import { Button } from '@wordpress/components';
import { TreeSelectControl } from '@woocommerce/components';
import { __ } from '@wordpress/i18n';
import { useDispatch, useSelect } from '@wordpress/data';
import { paymentGatewaysStore, paymentSettingsStore } from '@woocommerce/data';
import { useState, useEffect, useMemo } from '@wordpress/element';
import { DataForm } from '@wordpress/dataviews';
import type { Field } from '@wordpress/dataviews';
⋮----
import { mapShippingMethodsOptions } from '~/settings-payments/offline/utils';
import { Settings } from '~/settings-payments/components/settings';
import { FieldPlaceholder } from '~/settings-payments/components/field-placeholder';
import {
	CheckboxEdit,
	TextEdit,
	TextareaEdit,
	type OfflineFormValues,
} from './dataform-controls';
⋮----
onChange=
⋮----
const saveSettings = () =>
⋮----
e.preventDefault();
saveSettings();
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/offline/utils.ts">
export function decodeHtmlEntities( text: string )
⋮----
export function mapShippingMethodsOptions(
	options: Record< string, Record< string, string > >
)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/components/modal/index.tsx">
import { Modal } from '@wordpress/components';
⋮----
import { OnboardingModalProps } from '../../types';
⋮----
export default function OnboardingModal( {
	setIsOpen,
	children,
}: OnboardingModalProps )
⋮----
onRequestClose=
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/components/stepper/index.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { useEffect } from '@wordpress/element';
⋮----
import SidebarItem from './sidebar-item';
import { WooPaymentsProviderOnboardingStep } from '~/settings-payments/onboarding/types';
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
⋮----
const isStepCompleted = (
		step: WooPaymentsProviderOnboardingStep
): boolean =>
⋮----
isCompleted=
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/components/stepper/sidebar-item.tsx">
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
⋮----
import { SidebarItemProps } from '~/settings-payments/onboarding/types';
import { WC_ASSET_URL } from '~/utils/admin-settings';
⋮----
className=
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/components/banner-notice/index.tsx">
import React, { ComponentProps } from 'react';
import { __ } from '@wordpress/i18n';
import { useEffect, renderToString } from '@wordpress/element';
import { speak } from '@wordpress/a11y';
import clsx from 'clsx';
import { Button } from '@wordpress/components';
import { check, info } from '@wordpress/icons';
import NoticeOutlineIcon from 'gridicons/dist/notice-outline';
import NoticeIcon from 'gridicons/dist/notice';
import CloseIcon from 'gridicons/dist/cross-small';
⋮----
type Status = keyof typeof statusIconMap;
⋮----
const useSpokenMessage = ( status?: string, message?: React.ReactNode ) =>
⋮----
interface Props {
	className?: string;
	children: React.ReactNode;
	status?: Status;
	isDismissible?: boolean;
	actions?: ReadonlyArray< {
		label: string;
		className?: string;
		variant?: ComponentProps< typeof Button >[ 'variant' ];
		url?: string;
		urlTarget?: string;
		onClick?: React.MouseEventHandler< HTMLAnchorElement >;
	} >;
	onRemove?: () => void;
}
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/components/custom-select-control/index.tsx">
import React from 'react';
import { Button } from '@wordpress/components';
import { check, chevronDown, Icon } from '@wordpress/icons';
import { useCallback } from '@wordpress/element';
import clsx from 'clsx';
import { __, sprintf } from '@wordpress/i18n';
import { useSelect, UseSelectState } from 'downshift';
⋮----
export interface Item {
	key: string;
	name?: string;
	className?: string;
	style?: React.CSSProperties;
}
⋮----
export interface ControlProps< ItemType > {
	name?: string;
	className?: string;
	label: string;
	describedBy?: string;
	options: ItemType[];
	value?: ItemType | null;
	placeholder?: string;
	onChange?: ( changes: Partial< UseSelectState< ItemType > > ) => void;
	children?: ( item: ItemType ) => JSX.Element;
}
⋮----
const itemToString = ( item:
⋮----
function getDescribedBy()
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/components/grouped-select-control/index.tsx">
import React, { useRef, useState } from 'react';
import { check, chevronDown, chevronUp, Icon } from '@wordpress/icons';
import clsx from 'clsx';
import { __ } from '@wordpress/i18n';
import { useSelect, UseSelectState } from 'downshift';
⋮----
export interface ListItem {
	key: string;
	name: string;
	group?: string;
	context?: string;
	className?: string;
	items?: string[];
}
⋮----
export interface GroupedSelectControlProps< ItemType > {
	label: string;
	options: ItemType[];
	value?: ItemType | null;
	placeholder?: string;
	searchable?: boolean;
	name?: string;
	className?: string;
	onChange?: ( changes: Partial< UseSelectState< ItemType > > ) => void;
}
⋮----
const handleSearch = ( {
		target,
}: React.ChangeEvent< HTMLInputElement > ) =>
⋮----
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/components/header/index.tsx">
import { Button, Icon } from '@wordpress/components';
import { close } from '@wordpress/icons';
⋮----
import { WC_ASSET_URL } from '~/utils/admin-settings';
⋮----
interface WooPaymentsStepHeaderProps {
	onClose: () => void;
}
⋮----
export default function WooPaymentsStepHeader( {
	onClose,
}: WooPaymentsStepHeaderProps ): React.ReactNode
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/components/onboarding/index.tsx">
import { __ } from '@wordpress/i18n';
import { Route, Routes, useLocation } from 'react-router-dom';
import { useEffect } from 'react';
⋮----
import StripeSpinner from '../stripe-spinner';
import Stepper from '~/settings-payments/onboarding/components/stepper';
import { useOnboardingContext } from '../../data/onboarding-context';
⋮----
// Displays a loading indicator if the content is still loading.
⋮----
// Renders the Stepper if there are steps available.
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/components/snackbar/index.tsx">
import { useState, useEffect } from '@wordpress/element';
⋮----
import Snackbar from '~/layout/transient-notices/snackbar';
⋮----
const WooPaymentsOnboardingModalSnackbar = ( {
	children,
	duration = 4000,
	className,
}: {
	children: React.ReactNode;
	duration?: number;
	className?: string;
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/components/stripe-spinner/index.tsx">
import React from 'react';
⋮----
const StripeSpinner = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/data/onboarding-context.tsx">
import {
	createContext,
	useContext,
	useCallback,
	useState,
	useEffect,
} from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import {
	woopaymentsOnboardingStore,
	WooPaymentsOnboardingStepContent,
	paymentSettingsStore,
} from '@woocommerce/data';
import { getHistory, getNewPath, getQuery } from '@woocommerce/navigation';
⋮----
import {
	WooPaymentsProviderOnboardingStep,
	OnboardingContextType,
} from '~/settings-payments/onboarding/types';
import { wooPaymentsOnboardingSessionEntrySettings } from '~/settings-payments/constants';
⋮----
const getStepByKeyRecursively = (
	key: string,
	steps: WooPaymentsProviderOnboardingStep[]
): WooPaymentsProviderOnboardingStep | undefined =>
⋮----
interface URLStrategy {
	buildStepURL: (
		stepPath: string,
		currentParams?: Record< string, string >
... (54 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/components/embedded/appearance.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/components/embedded/index.tsx">
import React, { useState, useEffect } from 'react';
import {
	loadConnectAndInitialize,
	LoadError,
	LoaderStart,
	StripeConnectInstance,
} from '@stripe/connect-js';
import {
	ConnectAccountOnboarding,
	ConnectComponentsProvider,
} from '@stripe/react-connect-js';
import { __ } from '@wordpress/i18n';
⋮----
import { createEmbeddedKycSession } from '../../utils/actions';
import appearance from './appearance';
import {
	type EmbeddedAccountInitializationFailure,
	EmbeddedKycSession,
	EmbeddedKycSessionCreateResult,
	OnboardingFields,
} from '../../types';
import BannerNotice from '../../../../components/banner-notice';
import { useOnboardingContext } from '../../../../data/onboarding-context';
⋮----
interface EmbeddedComponentProps {
	onLoaderStart?: ( { elementTagName }: LoaderStart ) => void;
	onLoadError?: ( { error, elementTagName }: LoadError ) => void;
}
⋮----
interface EmbeddedAccountOnboardingProps extends EmbeddedComponentProps {
... (28 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/components/form/fields.tsx">
import React, { ComponentProps, forwardRef } from 'react';
import { TextControl } from '@wordpress/components';
import clsx from 'clsx';
⋮----
import CustomSelectControl, {
	ControlProps as SelectControlProps,
	Item as SelectItem,
} from '../../../../components/custom-select-control';
import GroupedSelectControl, {
	GroupedSelectControlProps,
	ListItem as GroupedSelectItem,
} from '../../../../components/grouped-select-control';
⋮----
interface CommonProps {
	error?: string;
}
⋮----
export type TextFieldProps = ComponentProps< typeof TextControl > & CommonProps;
export type SelectFieldProps< ItemType > = SelectControlProps< ItemType > &
	CommonProps;
export type GroupedSelectFieldProps< ItemType > =
	GroupedSelectControlProps< ItemType > & CommonProps;
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/components/form/index.tsx">
import React, { useState } from 'react';
import { Button } from '@wordpress/components';
import { isEmpty, mapValues } from 'lodash';
⋮----
import { useOnboardingContext } from '../../../../data/onboarding-context';
import { useStepperContext } from '../stepper';
import { Item as SelectItem } from '../../../../components/custom-select-control';
import { ListItem as GroupedSelectItem } from '../../../../components/grouped-select-control';
import {
	GroupedSelectField,
	GroupedSelectFieldProps,
	SelectField,
	SelectFieldProps,
	TextField,
	TextFieldProps,
} from './fields';
import { useBusinessVerificationContext } from '../../data/business-verification-context';
import { OnboardingFields } from '../../types';
import { isPreKycComplete } from '../../utils';
import { completeSubStep } from '../../utils/actions';
import { useValidation } from '../../utils/validation';
import strings from '../../strings';
⋮----
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
⋮----
type OnboardingFormProps = {
	children: React.ReactNode;
};
⋮----
export const OnboardingForm: React.FC< OnboardingFormProps > = ( {
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/components/step/index.tsx">
import React from 'react';
⋮----
import { OnboardingSteps } from '../../types';
import strings from '../../strings';
⋮----
interface Props {
	name: OnboardingSteps;
	showHeading?: boolean;
	children: React.ReactNode;
}
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/components/stepper/index.tsx">
import React, { createContext, useContext, useState } from 'react';
import { useEffect } from '@wordpress/element';
⋮----
import { useOnboardingContext } from '../../../../data/onboarding-context';
⋮----
interface UseContextValueParams {
	steps: Record< string, React.ReactElement >;
	initialStep?: string;
	onStepView?: ( step: string ) => void;
	onStepChange?: ( step: string ) => void;
	onComplete?: () => void;
	onExit?: () => void;
}
⋮----
const useContextValue = ( {
	steps,
	initialStep,
	onStepChange,
	onComplete,
	onExit,
}: UseContextValueParams ) =>
⋮----
const nextStep = () =>
⋮----
const prevStep = () =>
⋮----
const exit = ()
⋮----
type ContextValue = ReturnType< typeof useContextValue >;
⋮----
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/data/business-verification-context.tsx">
import React, { createContext, useCallback, useContext, useState } from 'react';
import { isNil, omitBy } from 'lodash';
⋮----
import { OnboardingFields } from '../types';
⋮----
const useBusinessVerificationContextValue = (
	initialState = {} as OnboardingFields
) =>
⋮----
type BusinessVerificationContextValue = ReturnType<
	typeof useBusinessVerificationContextValue
>;
⋮----
export const BusinessVerificationContextProvider: React.FC< {
	initialData?: OnboardingFields;
	children: React.ReactNode;
} > = (
⋮----
value=
⋮----
export const useBusinessVerificationContext =
(): BusinessVerificationContextValue =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/sections/activate-payments.tsx">
import React, { useState } from 'react';
import { Button } from '@wordpress/components';
import apiFetch from '@wordpress/api-fetch';
⋮----
import { useStepperContext } from '../components/stepper';
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
import strings from '../strings';
import { useOnboardingContext } from '~/settings-payments/onboarding/providers/woopayments/data/onboarding-context';
⋮----
const handleContinue = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/sections/business-details.tsx">
import React from 'react';
import apiFetch from '@wordpress/api-fetch';
⋮----
import { useBusinessVerificationContext } from '../data/business-verification-context';
import { useOnboardingContext } from '../../../data/onboarding-context';
import { Item } from '../../../components/custom-select-control';
import { OnboardingFields, BusinessType, MccsDisplayTreeItem } from '../types';
import {
	OnboardingGroupedSelectField,
	OnboardingSelectField,
} from '../components/form';
import {
	getAvailableCountries,
	getBusinessTypes,
	getMccsFlatList,
} from '../utils';
import strings from '../strings';
⋮----
const handleTiedChange = (
		name: keyof OnboardingFields,
		selectedItem?: Item | null
): Promise< void > =>
⋮----
const updateDataOnChange = (
		name: keyof OnboardingFields,
		selectedItem?: Item | null
): Promise< void > =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/sections/embedded-kyc.tsx">
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { __ } from '@wordpress/i18n';
import { LoadError } from '@stripe/connect-js';
⋮----
import { useOnboardingContext } from '../../../data/onboarding-context';
import StripeSpinner from '../../../components/stripe-spinner';
import BannerNotice from '../../../components/banner-notice';
import { useBusinessVerificationContext } from '../data/business-verification-context';
import { finalizeEmbeddedKycSession } from '../utils/actions';
import { EmbeddedAccountOnboarding } from '../components/embedded';
import { type EmbeddedAccountInitializationFailure } from '../types';
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
⋮----
interface Props {
	continueKyc?: boolean;
	collectPayoutRequirements?: boolean;
}
⋮----
type EmbeddedKycLoadFailureReason =
	| 'timeout'
	| 'load_error'
	| 'bad_session'
	| 'init_error';
⋮----
type EmbeddedKycLoadFailure = {
	reason: EmbeddedKycLoadFailureReason;
	message?: string;
	errorType?: string;
	receivedKeys?: string[];
};
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/translations/descriptions.tsx">
import { __ } from '@wordpress/i18n';
⋮----
interface DescriptionKeyMap {
	[ key: string ]: {
		[ key: string ]: string;
	};
}
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/utils/actions.ts">
import apiFetch from '@wordpress/api-fetch';
⋮----
import {
	OnboardingFields,
	FinalizeEmbeddedKycSessionResponse,
	EmbeddedKycSessionCreateResult,
} from '../types';
import { fromDotNotation } from './';
⋮----
export const finalizeEmbeddedKycSession = async (
	apiUrl: string,
	source?: string
) =>
⋮----
export const completeSubStep = (
	stepName: string,
	apiUrl: string | undefined,
	data: Record<
		string,
		{
			status: string;
		}
	>
): Promise< void > =>
⋮----
export const createEmbeddedKycSession = async (
	data: OnboardingFields,
	apiUrl: string,
	source?: string
): Promise< EmbeddedKycSessionCreateResult > =>
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/utils/index.ts">
import { set, toPairs } from 'lodash';
⋮----
import { ListItem } from '../../../components/grouped-select-control';
import businessTypeDescriptionStrings from '../translations/descriptions';
import { Country, MccsDisplayTreeItem, OnboardingFields } from '../types';
⋮----
export const fromDotNotation = (
	record: Record< string, unknown >
): Record< string, unknown >
⋮----
export const getAvailableCountries = (
	countries: Record< string, string >
): Country[]
⋮----
export const getBusinessTypes = ( data: Country[] ): Country[] =>
⋮----
export const hasUndefinedValues = ( obj: Record< string, unknown > ): boolean
⋮----
export const getMccFromIndustry = (
	industryToMcc: string[]
): string | undefined =>
⋮----
export const getMccsFlatList = (
	industryToMcc: MccsDisplayTreeItem[]
): ListItem[] =>
⋮----
export const isPreKycComplete = ( data: OnboardingFields ): boolean =>
⋮----
export const getComingSoonShareKey = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/utils/validation.ts">
import { useEffect } from 'react';
⋮----
import strings from '../strings';
import { useBusinessVerificationContext } from '../data/business-verification-context';
import { OnboardingFields } from '../types';
⋮----
const isValid = ( name: keyof OnboardingFields, value?: string ): boolean =>
⋮----
export const useValidation = ( name: keyof OnboardingFields ) =>
⋮----
const validate = ( value: string | undefined = data[ name ] ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/index.tsx">
import React from 'react';
import { __, _n, sprintf } from '@wordpress/i18n';
import { Notice } from '@wordpress/components';
⋮----
import { useOnboardingContext } from '../../data/onboarding-context';
import WooPaymentsStepHeader from '../../components/header';
import { BusinessVerificationContextProvider } from './data/business-verification-context';
import { OnboardingForm } from './components/form';
import BusinessDetails from './sections/business-details';
import EmbeddedKyc from './sections/embedded-kyc';
import ActivatePayments from './sections/activate-payments';
import { Stepper } from './components/stepper';
import Step from './components/step';
import { getMccFromIndustry, getComingSoonShareKey } from './utils';
⋮----
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
import type { OnboardingError } from '~/settings-payments/onboarding/types';
⋮----
const normalizeErrorMessage = ( message: unknown ): string =>
⋮----
const handleStepChange = () =>
⋮----
⋮----
onComplete=
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/strings.tsx">
import { __, sprintf } from '@wordpress/i18n';
import interpolateComponents from '@automattic/interpolate-components';
import React from 'react';
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/business-verification/types.ts">
export type OnboardingSteps =
	| 'activate'
	| 'business'
	| 'store'
	| 'embedded'
	| 'loading';
⋮----
export type OnboardingFields = {
	country?: string;
	business_type?: string;
	'company.structure'?: string;
	mcc?: string;
};
⋮----
export interface Country {
	key: string;
	name: string;
	types: BusinessType[];
}
⋮----
export interface BusinessType {
	key: string;
	name: string;
	description: string;
	requires_structure?: boolean;
	structures: BusinessStructure[];
}
⋮----
export interface BusinessStructure {
	key: string;
... (41 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/finish/index.tsx">
import React from 'react';
import { __ } from '@wordpress/i18n';
import { Button, Notice } from '@wordpress/components';
⋮----
import { useOnboardingContext } from '../../data/onboarding-context';
import WooPaymentsStepHeader from '../../components/header';
⋮----
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/payment-methods-selection/index.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { Button, Icon, Notice } from '@wordpress/components';
import { RecommendedPaymentMethod } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { useState, useEffect, useMemo, useRef } from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';
import { close } from '@wordpress/icons';
import clsx from 'clsx';
⋮----
import { useOnboardingContext } from '../../data/onboarding-context';
import { PaymentMethodListItem } from './list-item';
import {
	combinePaymentMethodsState,
	combineRequestMethods,
	recordPaymentsOnboardingEvent,
	shouldRenderPaymentMethodInMainList,
} from '~/settings-payments/utils';
⋮----
const savePaymentMethodsState = (
		state: Record< string, boolean >,
		changedMethodId?: string
): Promise< void > =>
⋮----
const checkHasOverflow = () =>
⋮----
const handleResize = () =>
⋮----
paymentMethodsState={ combinePaymentMethodsState(
											paymentMethodsState
										) }
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/payment-methods-selection/list-item.tsx">
import { decodeEntities } from '@wordpress/html-entities';
import { type RecommendedPaymentMethod } from '@woocommerce/data';
import { ToggleControl } from '@wordpress/components';
import { useRef } from '@wordpress/element';
import { Notice } from '@wordpress/ui';
⋮----
import sanitizeHTML from '~/lib/sanitize-html';
import { shouldRenderPaymentMethodInMainList } from '~/settings-payments/utils';
⋮----
type PaymentMethodListItemProps = {
	method: RecommendedPaymentMethod;
	paymentMethodsState: Record< string, boolean >;
	setPaymentMethodsState: ( state: Record< string, boolean > ) => void;
	isExpanded: boolean;
	initialVisibilityStatus?: boolean | null;
	isLoading?: boolean;
};
⋮----
spokenMessage=
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/test-account/index.tsx">
import React, { useState, useRef, useEffect, useCallback } from 'react';
import apiFetch from '@wordpress/api-fetch';
import { Loader } from '@woocommerce/onboarding';
import { __ } from '@wordpress/i18n';
import { Notice } from '@wordpress/components';
import { navigateTo, getNewPath } from '@woocommerce/navigation';
⋮----
import WooPaymentsStepHeader from '../../components/header';
import { useOnboardingContext } from '../../data/onboarding-context';
import { WC_ASSET_URL } from '~/utils/admin-settings';
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
import { WooPaymentsResetAccountModal } from '~/settings-payments/components/modals';
⋮----
interface StepCheckResponse {
	status: string;
	success: boolean;
}
⋮----
alt=
⋮----
const clearTimers = () =>
⋮----
const cleanStepIfNeeded = async () =>
⋮----
const poll = () =>
⋮----
return; // Stop polling loop.
⋮----
// Still pending, update progress and determine next poll.
⋮----
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/test-or-live-account/index.tsx">
import React, { useState } from 'react';
import { __ } from '@wordpress/i18n';
import interpolateComponents from '@automattic/interpolate-components';
import { Button, Notice } from '@wordpress/components';
import { Link } from '@woocommerce/components';
import apiFetch from '@wordpress/api-fetch';
⋮----
import WooPaymentsStepHeader from '../../components/header';
import { useOnboardingContext } from '../../data/onboarding-context';
import { WC_ASSET_URL } from '~/utils/admin-settings';
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
import {
	TESTING_ACCOUNT_STEP_ID,
	LIVE_ACCOUNT_STEP_ID,
} from '~/settings-payments/onboarding/providers/woopayments/steps';
⋮----
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/wpcom-connection/index.tsx">
import React from 'react';
import { __ } from '@wordpress/i18n';
import { Button, Notice } from '@wordpress/components';
import { useState } from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';
⋮----
import { useOnboardingContext } from '../../data/onboarding-context';
import WooPaymentsStepHeader from '../../components/header';
⋮----
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/steps/index.tsx">
import React from 'react';
import { __, sprintf } from '@wordpress/i18n';
⋮----
import { WooPaymentsProviderOnboardingStep } from '~/settings-payments/onboarding/types';
import WordPressComStep from './wpcom-connection';
import BusinessVerificationStep from './business-verification';
import PaymentMethodsSelection from './payment-methods-selection';
import TestAccountStep from './test-account';
import TestOrLiveAccountStep from './test-or-live-account';
import FinishStep from './finish';
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/providers/woopayments/index.tsx">
import React from 'react';
import { __ } from '@wordpress/i18n';
import { useLocation } from 'react-router-dom';
import { getHistory, getNewPath, getQuery } from '@woocommerce/navigation';
import { getQueryArg } from '@wordpress/url';
import { dispatch } from '@wordpress/data';
⋮----
import Modal from '~/settings-payments/onboarding/components/modal';
import WooPaymentsOnboarding from './components/onboarding';
import { WooPaymentsModalProps } from '~/settings-payments/onboarding/types';
import {
	OnboardingProvider,
	useOnboardingContext,
} from './data/onboarding-context';
import { recordPaymentsOnboardingEvent } from '~/settings-payments/utils';
import { steps } from './steps';
import WooPaymentsOnboardingModalSnackbar from './components/snackbar';
⋮----
const SnackbarWrapper = () =>
⋮----
/**
 * Modal component for WooPayments onboarding
 */
export default function WooPaymentsModal( {
	isOpen,
	setIsOpen,
	providerData,
}: WooPaymentsModalProps ): React.ReactNode
⋮----
const handleClose = () =>
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/onboarding/types.ts">
import { type ReactNode } from 'react';
import {
	type RecommendedPaymentMethod,
	type PaymentsProvider,
} from '@woocommerce/data';
⋮----
import {
	Country,
	MccsDisplayTreeItem,
} from './providers/woopayments/steps/business-verification/types';
⋮----
export interface OnboardingError {
	message: string;
	code: string;
}
⋮----
export interface OnboardingModalProps {
	setIsOpen: ( isOpen: boolean ) => void;
	children?: ReactNode;
}
⋮----
export interface SidebarItemProps {
	label: string;
	isCompleted?: boolean;
	isActive?: boolean;
}
⋮----
export interface WooPaymentsModalProps {
	isOpen: boolean;
	setIsOpen: ( isOpen: boolean ) => void;
... (121 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/CLAUDE.md">
# Claude Code Documentation for WooCommerce Settings Payments

**Scope**: Payment gateway UI architecture and patterns
**Location**: `plugins/woocommerce/client/admin/client/settings-payments`

**See also:**

- `../CLAUDE.md` - Testing, linting, and build commands
- `packages/js/data/src/payment-settings/` - Data layer and types

## Quick Workflow

**Modifying payment gateway features (data + UI must be updated together):**

1. Update types: `packages/js/data/src/payment-settings/types.ts`
2. Update test stubs: `packages/js/data/src/payment-settings/test/helpers/stub.ts`
3. Update UI: `client/settings-payments/components/`
4. Test: `cd ../.. && pnpm run test:js -- settings-payments && pnpm run ts:check`

## Architecture

### Data/UI Separation (Critical Pattern)

**Data layer** (must be updated first):

- Types: `packages/js/data/src/payment-settings/types.ts`
- Test stubs: `packages/js/data/src/payment-settings/test/helpers/stub.ts`
- Key types: `PaymentGatewayProvider`, `PaymentsProviderOnboardingState`, `OfflinePaymentMethodProvider`

**UI layer** (depends on data layer):
... (335 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/constants.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/index.tsx">
import { Gridicon } from '@automattic/components';
import { Button, Placeholder, SelectControl } from '@wordpress/components';
import React, { lazy, Suspense, useEffect } from '@wordpress/element';
import {
	unstable_HistoryRouter as HistoryRouter,
	Route,
	Routes,
	useLocation,
} from 'react-router-dom';
import { getHistory, getNewPath } from '@woocommerce/navigation';
import { __, sprintf } from '@wordpress/i18n';
⋮----
import { Header } from './components/header/header';
import { BackButton } from './components/buttons/back-button';
import { ListPlaceholder } from '~/settings-payments/components/list-placeholder';
⋮----
interface OfflinePaymentGatewayWrapperProps {
	title: string;
	chunkComponent: React.ComponentType;
}
⋮----
href=
⋮----
const externalElement = document.querySelector< HTMLElement >(
		'.woo-nav-tab-wrapper'
	);
⋮----
if ( externalElement )
⋮----
const location = useLocation();
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/settings-payments-main.tsx">
import { useCallback, useRef } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import {
	pluginsStore,
	paymentSettingsStore,
	PaymentsProvider,
	PaymentsEntity,
} from '@woocommerce/data';
import {
	dispatch,
	resolveSelect,
	useDispatch,
	useSelect,
} from '@wordpress/data';
import React, { useState, useEffect } from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';
import { getHistory, getNewPath } from '@woocommerce/navigation';
import { Button } from '@wordpress/components';
⋮----
import { createNoticesFromResponse } from '~/lib/notices';
import { OtherPaymentGateways } from '~/settings-payments/components/other-payment-gateways';
import { PaymentGateways } from '~/settings-payments/components/payment-gateways';
import { IncentiveBanner } from '~/settings-payments/components/incentive-banner';
import { IncentiveModal } from '~/settings-payments/components/incentive-modal';
import {
	providersContainWooPaymentsInTestMode,
	providersContainWooPaymentsInDevMode,
	isIncentiveDismissedInContext,
	isSwitchIncentive,
	isWooPayments,
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/settings-payments-offline.tsx">
import { useDispatch, useSelect } from '@wordpress/data';
import { useEffect, useState } from '@wordpress/element';
import {
	type OfflinePaymentMethodProvider,
	paymentSettingsStore,
} from '@woocommerce/data';
⋮----
import { ListPlaceholder } from '~/settings-payments/components/list-placeholder';
import { OfflinePaymentGatewayList } from '~/settings-payments/components/offline-payment-gateway-list';
⋮----
function handleOrderingUpdate( sorted: OfflinePaymentMethodProvider[] )
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/settings-payments-woopayments.tsx">
export const SettingsPaymentsWoopayments = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/settings-payments/utils.ts">
import {
	PaymentsProvider,
	PaymentsProviderIncentive,
	RecommendedPaymentMethod,
} from '@woocommerce/data';
import { getAdminLink } from '@woocommerce/settings';
import { __, sprintf } from '@wordpress/i18n';
import { recordEvent } from '@woocommerce/tracks';
import { parseAdminUrl } from '@woocommerce/navigation';
⋮----
import { getAdminSetting } from '~/utils/admin-settings';
import {
	wooPaymentsProviderId,
	wooPaymentsProviderSuggestionId,
	wooPaymentsSuggestionId,
} from '~/settings-payments/constants';
⋮----
export const hasIncentive = ( extension: PaymentsProvider ) =>
⋮----
export const isActionIncentive = (
	incentive: PaymentsProviderIncentive | undefined
) =>
⋮----
export const isSwitchIncentive = (
	incentive: PaymentsProviderIncentive | undefined
) =>
⋮----
export const isIncentiveDismissedInContext = (
	incentive: PaymentsProviderIncentive | undefined,
	context: string
... (95 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/settings-recommendations/dismissable-list.tsx">
import { Button, Card, CardHeader } from '@wordpress/components';
import { useEffect, useRef } from '@wordpress/element';
import { speak } from '@wordpress/a11y';
import { EllipsisMenu } from '@woocommerce/components';
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
</file>

<file path="plugins/woocommerce/client/admin/client/settings-recommendations/recommendations-eligibility-wrapper.tsx">
import { useSelect } from '@wordpress/data';
import { useUser, optionsStore } from '@woocommerce/data';
⋮----
const RecommendationsEligibilityWrapper = ( {
	children,
}: {
	children: React.ReactNode;
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/shipping/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/shipping/packlink-item.tsx">
import { __ } from '@wordpress/i18n';
import { useDispatch } from '@wordpress/data';
import { Button, ExternalLink } from '@wordpress/components';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import type { ShippingPartnerTrackingProps } from './woocommerce-shipping-item';
⋮----
const handleClick = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/shipping/shipping-recommendations-utils.tsx">
import { __ } from '@wordpress/i18n';
import { useDispatch } from '@wordpress/data';
import { useState, Children } from '@wordpress/element';
import { Text } from '@woocommerce/experimental';
import { PluginNames, pluginsStore } from '@woocommerce/data';
import { getAdminLink } from '@woocommerce/settings';
import { CardFooter } from '@wordpress/components';
⋮----
import { createNoticesFromResponse } from '../lib/notices';
import {
	DismissableList,
	DismissableListHeading,
} from '../settings-recommendations/dismissable-list';
import { TrackedLink } from '~/components/tracked-link/tracked-link';
import { type DismissState } from '~/hooks/use-option-dismiss';
⋮----
type ShippingRecommendationsMarketplaceLinkProps = {
	textProps?: {
		as?: string;
		className?: string;
	};
};
⋮----
export const useInstallPlugin = () =>
⋮----
const handleInstall = ( slugs: string[] ): PromiseLike< void > =>
⋮----
const handleActivate = ( slugs: string[] ): PromiseLike< void > =>
</file>

<file path="plugins/woocommerce/client/admin/client/shipping/shipping-recommendations-wrapper.tsx">
import { lazy, Suspense } from '@wordpress/element';
⋮----
import { EmbeddedBodyProps } from '../embedded-body-layout/embedded-body-props';
import RecommendationsEligibilityWrapper from '../settings-recommendations/recommendations-eligibility-wrapper';
⋮----
export const ShippingRecommendations = ( {
	page,
	tab,
	section,
	zone_id,
}: EmbeddedBodyProps ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/shipping/shipping-recommendations.tsx">
import { useSelect } from '@wordpress/data';
import { useEffect, useRef } from '@wordpress/element';
import {
	pluginsStore,
	settingsStore,
	onboardingStore,
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { getCountryCode } from '~/dashboard/utils';
import { useOptionDismiss } from '~/hooks/use-option-dismiss';
import WooCommerceShippingItem from './woocommerce-shipping-item';
import ShipStationItem from './shipstation-item';
import PacklinkItem from './packlink-item';
import {
	SHIPPING_RECOMMENDATIONS_DISMISS_OPTION,
	ShippingRecommendationsList,
	ShippingRecommendationsMarketplaceLink,
	useInstallPlugin,
} from './shipping-recommendations-utils';
⋮----
import { ShippingTour } from '~/guided-tours/shipping-tour';
⋮----
type ExtensionId = 'woocommerce-shipping' | 'shipstation' | 'packlink';
⋮----
// Render every country-mapped recommendation regardless of which partner
// is already installed: the settings page is meant to surface alternatives
// the merchant can evaluate and switch to. The onboarding wizard keeps a
// narrower selection because installing every option there at once is not
// desired during initial setup.
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/shipping/shipstation-item.tsx">
import { __ } from '@wordpress/i18n';
import { useDispatch } from '@wordpress/data';
import { Button, ExternalLink } from '@wordpress/components';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import type { ShippingPartnerTrackingProps } from './woocommerce-shipping-item';
⋮----
const handleClick = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/shipping/woocommerce-shipping-item.tsx">
import { __ } from '@wordpress/i18n';
import { useDispatch } from '@wordpress/data';
import { Button, ExternalLink } from '@wordpress/components';
import { Pill } from '@woocommerce/components';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import WooIcon from './woo-icon.svg';
⋮----
export type ShippingPartnerTrackingProps = {
	context: 'settings';
	country: string;
	plugins: string;
};
⋮----
const handleClick = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/store-management-links/quick-link/index.js">
export const QuickLink = (
</file>

<file path="plugins/woocommerce/client/admin/client/store-management-links/quick-link-category/index.js">
export const QuickLinkCategory = (
</file>

<file path="plugins/woocommerce/client/admin/client/store-management-links/index.js">
export function getLinkTypeAndHref(
⋮----
export function getItemsByCategory( shopUrl )
⋮----
export const generateExtensionLinks = ( links ) =>
⋮----
export const StoreManagementLinks = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/components/progress-header/default-progress-header.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { getVisibleTasks, onboardingStore } from '@woocommerce/data';
⋮----
import { TaskListMenu } from '~/task-lists/components/task-list-menu';
⋮----
export type DefaultProgressHeaderProps = {
	taskListId: string;
};
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/components/progress-header/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/components/progress-header/progress-header.tsx">
import { useSlot } from '@woocommerce/experimental';
⋮----
import {
	WC_TASKLIST_EXPERIMENTAL_PROGRESS_HEADER_SLOT_NAME,
	WooTaskListProgressHeaderItem,
} from './utils';
import {
	DefaultProgressHeader,
	DefaultProgressHeaderProps,
} from './default-progress-header';
⋮----
export const ProgressHeader = ( {
	taskListId,
}: DefaultProgressHeaderProps ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/components/progress-header/utils.tsx">
import { Slot, Fill } from '@wordpress/components';
import {
	createOrderedChildren,
	sortFillsByOrder,
} from '@woocommerce/components';
⋮----
export const WooTaskListProgressHeaderItem = ( {
	children,
	order = 1,
}: {
	children?: React.ReactNode;
	order?: number;
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/components/back-button.tsx">
import { __ } from '@wordpress/i18n';
import { Tooltip } from '@wordpress/components';
import { Icon, chevronLeft } from '@wordpress/icons';
import { updateQueryString } from '@woocommerce/navigation';
import { ENTER, SPACE } from '@wordpress/keycodes';
import { recordEvent } from '@woocommerce/tracks';
⋮----
export type BackButtonProps = {
	title: string;
};
⋮----
const navigateHome = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/components/placeholder.tsx">
export type TasksPlaceholderProps = {
	numTasks?: number;
	query: {
		task?: string;
	};
};
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/components/task-list-item.tsx">
import { __ } from '@wordpress/i18n';
import { getNewPath, navigateTo } from '@woocommerce/navigation';
import {
	onboardingStore,
	TaskType,
	useUserPreferences,
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { TaskItem, useSlot } from '@woocommerce/experimental';
import { useCallback, useEffect } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import { Button } from '@wordpress/components';
import { WooOnboardingTaskListItem } from '@woocommerce/onboarding';
import { useLayoutContext } from '@woocommerce/admin-layout';
⋮----
export type TaskListItemProps = {
	isExpandable: boolean;
	isExpanded: boolean;
	setExpandedTask: ( id: string ) => void;
	task: TaskType & {
		onClick?: () => void;
	};
	isSkipDisabled?: boolean;
	onTaskSkip?: ( task: TaskType ) => Promise< void >;
	showSkipAction?: boolean;
	trackClick?: () => void;
};
⋮----
const getTaskStartedCount = () =>
⋮----
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/components/task-list-menu.tsx">
import { __ } from '@wordpress/i18n';
import { DropdownMenu } from '@wordpress/components';
import { moreVertical } from '@wordpress/icons';
import { onboardingStore } from '@woocommerce/data';
import { useDispatch } from '@wordpress/data';
⋮----
export type TaskListMenuProps = {
	id: string;
	hideTaskListText?: string;
};
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/components/task-list.tsx">
import { __, _n, sprintf } from '@wordpress/i18n';
import { useEffect, useRef, useState } from '@wordpress/element';
import { Button, Card, CardHeader } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { Badge, H } from '@woocommerce/components';
import {
	getVisibleTasks,
	onboardingStore,
	TaskType,
	TaskListType,
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import {
	Text,
	List,
	ListItem,
	CollapsibleList,
} from '@woocommerce/experimental';
import { useLayoutContext } from '@woocommerce/admin-layout';
import clsx from 'clsx';
⋮----
import { TaskListItem } from './task-list-item';
import { TaskListMenu } from './task-list-menu';
⋮----
import ChecklistImage from './checklist.svg';
import { ProgressHeader } from '~/task-lists/components/progress-header';
⋮----
export type TaskListProps = TaskListType & {
	query: {
		task?: string;
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/components/task.tsx">
import {
	WooHeaderNavigationItem,
	WooHeaderPageTitle,
} from '@woocommerce/admin-layout';
import { WooOnboardingTask } from '@woocommerce/onboarding';
import { getHistory, getNewPath } from '@woocommerce/navigation';
import { onboardingStore, TaskType } from '@woocommerce/data';
import { useCallback } from '@wordpress/element';
import { useDispatch, resolveSelect } from '@wordpress/data';
⋮----
import { BackButton } from './back-button';
⋮----
export type TaskProps = {
	query: { task?: string };
	task: TaskType;
};
⋮----
export const Task = (
⋮----
// eslint-disable-next-line no-console
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/components/terms-of-service.js">
export const TermsOfService = ( { buttonText } ) => (
	<Text
		variant="caption"
		className="woocommerce-task__caption is-tos"
		size="12"
		lineHeight="16px"
		style={ { display: 'block' } }
	>
		{ interpolateComponents( {
			mixedString: sprintf(
				__(
					'By clicking "%s," you agree to our {{tosLink}}Terms of Service{{/tosLink}} and have read our {{privacyPolicyLink}}Privacy Policy{{/privacyPolicyLink}}.',
					'woocommerce'
				),
				buttonText
			),
			components: {
				tosLink: (
					<Link
						href={ 'https://wordpress.com/tos/' }
						target="_blank"
						type="external"
					>
						<></>
					</Link>
				),
				privacyPolicyLink: (
					<Link
						href={ 'https://automattic.com/privacy/' }
						target="_blank"
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/components/load-sample-product-confirm-modal.tsx">
import { __ } from '@wordpress/i18n';
import { Button, Modal } from '@wordpress/components';
import { Text } from '@woocommerce/experimental';
⋮----
type Props = {
	onCancel: () => void;
	onImport: () => void;
};
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/components/load-sample-product-modal.tsx">
import { __ } from '@wordpress/i18n';
import { Modal, Spinner } from '@wordpress/components';
import { Text } from '@woocommerce/experimental';
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/components/use-load-sample-products.ts">
import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
import { WC_ADMIN_NAMESPACE } from '@woocommerce/data';
import { useDispatch } from '@wordpress/data';
import { useState } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import useRecordCompletionTime from '../use-record-completion-time';
⋮----
type UseLoadSampleProductsProps = {
	redirectUrlAfterSuccess: string;
};
⋮----
const useLoadSampleProducts = ( {
	redirectUrlAfterSuccess,
}: UseLoadSampleProductsProps ) =>
⋮----
const loadSampleProduct = async () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/import-products/CardList.tsx">
import { List } from '@woocommerce/components';
⋮----
type Card = {
	key: string;
	title: string;
	content: string | JSX.Element;
	before: JSX.Element;
};
⋮----
type CardListProps = {
	items: Card[];
};
⋮----
const CardList = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/import-products/importTypes.tsx">
import { __ } from '@wordpress/i18n';
import PageIcon from 'gridicons/dist/pages';
import { getAdminLink } from '@woocommerce/settings';
import { recordEvent } from '@woocommerce/tracks';
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/import-products/index.tsx">
import { WooOnboardingTask } from '@woocommerce/onboarding';
import { registerPlugin } from '@wordpress/plugins';
import { __ } from '@wordpress/i18n';
import { Icon, chevronUp, chevronDown } from '@wordpress/icons';
import { Button } from '@wordpress/components';
import { useMemo, useState } from '@wordpress/element';
import { getAdminLink } from '@woocommerce/settings';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import Stacks from '../products/stack';
import CardList from './CardList';
import { importTypes } from './importTypes';
⋮----
import useProductTypeListItems from '../products/use-product-types-list-items';
import { getProductTypes } from '../products/utils';
import LoadSampleProductModal from '../components/load-sample-product-modal';
import useLoadSampleProducts from '../components/use-load-sample-products';
import LoadSampleProductConfirmModal from '../components/load-sample-product-confirm-modal';
import useRecordCompletionTime from '../use-record-completion-time';
⋮----
onClickLoadSampleProduct=
⋮----
recordEvent(
							'tasklist_add_product_from_scratch_click'
						);
setStackVisibility( ! showStacks );
⋮----
setIsConfirmingLoadSampleProducts( false );
recordEvent(
								'tasklist_cancel_load_sample_products_click'
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/Marketing/index.tsx">
import { __ } from '@wordpress/i18n';
import { Card, CardHeader, Spinner } from '@wordpress/components';
import {
	onboardingStore,
	pluginsStore,
	Extension,
	ExtensionList,
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { Text } from '@woocommerce/experimental';
import { useMemo, useState } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import { registerPlugin } from '@wordpress/plugins';
import { WooOnboardingTask } from '@woocommerce/onboarding';
import { getNewPath } from '@woocommerce/navigation';
import { getAdminLink } from '@woocommerce/settings';
⋮----
import { createNoticesFromResponse } from '~/lib/notices';
import { PluginList, PluginListProps } from './PluginList';
import { PluginProps } from './Plugin';
import { getPluginSlug } from '../../../utils';
import { TaskPromo } from './TaskPromo';
⋮----
export const transformExtensionToPlugin = (
	extension: Extension,
	activePlugins: string[],
	installedPlugins: string[]
): PluginProps =>
⋮----
export const getMarketingExtensionLists = (
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/Marketing/Plugin.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { getAdminLink } from '@woocommerce/settings';
import { recordEvent } from '@woocommerce/tracks';
import { Text } from '@woocommerce/experimental';
import { Pill } from '@woocommerce/components';
import { type TagsSlug } from '@woocommerce/data';
⋮----
export type PluginProps = {
	isActive: boolean;
	isBusy?: boolean;
	isBuiltByWC: boolean;
	isDisabled?: boolean;
	isInstalled: boolean;
	description?: string;
	installAndActivate?: ( slug: string ) => void;
	onManage?: ( slug: string ) => void;
	imageUrl?: string;
	manageUrl?: string;
	name: string;
	slug: string;
	tags?: TagsSlug[];
	learnMoreLink?: string;
	installExternal?: boolean;
};
⋮----
/* translators: %s = name of the plugin */
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/Marketing/PluginList.tsx">
import { Text } from '@woocommerce/experimental';
⋮----
import { Plugin, PluginProps } from './Plugin';
⋮----
export type PluginListProps = {
	currentPlugin?: string | null;
	key?: string;
	installAndActivate?: ( slug: string ) => void;
	onManage?: ( slug: string ) => void;
	plugins?: PluginProps[];
	title?: string;
};
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/Marketing/TaskPromo.tsx">
import { __ } from '@wordpress/i18n';
import { Button, Card, CardBody, CardHeader } from '@wordpress/components';
import { Text } from '@woocommerce/experimental';
import { useEffect } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { WC_ASSET_URL } from '~/utils/admin-settings';
⋮----
export type TaskPromoProps = {
	title?: string;
	iconSrc?: string;
	iconAlt?: string;
	name?: string;
	text?: string;
	buttonHref?: string;
	buttonText?: string;
	onButtonClick?: () => void;
};
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/List/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/List/Item.js">
export const Item = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/List/List.js">
export const List = ( {
	heading,
	headingDescription,
	markConfigured,
	recommendation,
	paymentGateways,
	footerLink,
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/List/Placeholder.js">
const PlaceholderItem = () =>
⋮----
export const Placeholder = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/Setup/Configure.js">
export const validateFields = ( values, fields ) =>
⋮----
const getField = ( fieldId )
⋮----
export const Configure = (
⋮----
const handleSubmit = ( values ) =>
⋮----
markConfigured: ()
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/Setup/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/Setup/Placeholder.js">
export const Placeholder = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/Setup/Setup.js">
export const Setup = (
⋮----
markConfigured: ()
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/Toggle/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/Toggle/Toggle.js">
export const Toggle = (
⋮----
const onClick = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/WCPay/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/WCPay/Suggestion.tsx">
import { __ } from '@wordpress/i18n';
import {
	WCPayBanner,
	WCPayBannerFooter,
	WCPayBannerBody,
	WCPayBenefits,
	WCPayBannerImageCut,
} from '@woocommerce/onboarding';
import { useDispatch, useSelect } from '@wordpress/data';
import { paymentSettingsStore } from '@woocommerce/data';
⋮----
import { Action } from '../Action';
import { connectWcpay } from './utils';
⋮----
interface PaymentGateway {
	id: string;
	needsSetup: boolean;
	installed: boolean;
	enabled: boolean;
}
⋮----
interface SuggestionProps {
	paymentGateway: PaymentGateway;
	onSetupCallback?: ( () => void ) | null;
}
⋮----
export const Suggestion = ( {
	paymentGateway,
	onSetupCallback = null,
}: SuggestionProps ) =>
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/WCPay/UsageModal.js">
export const UsageModal = () =>
⋮----
const closeModal = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/WCPay/utils.js">
export function connectWcpay( createNotice, onCatch )
⋮----
export function installActivateAndConnectWcpay(
	reject,
	createNotice,
	installAndActivatePlugins
)
⋮----
export function isWCPaySupported( countryCode )
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/WCPayBNPL/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/WCPayBNPL/Suggestion.js">
const recordTrack = () =>
⋮----
export const Suggestion = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/components/Action.js">
export const Action = ( {
	hasSetup = false,
	needsSetup = true,
	id,
	isEnabled = false,
	isLoading = false,
	isInstalled = false,
	isRecommended = false,
	hasPlugins,
	manageUrl = null,
	markConfigured = () => {},
	onSetUp = () => {},
	onSetupCallback,
	setupButtonText = __( 'Get started', 'woocommerce' ),
	externalLink = null,
} ) =>
⋮----
const handleClick = async () =>
⋮----
const ManageButton = () => (
		<Button
			className={ classes }
			isSecondary
			role="button"
			href={ manageUrl }
			onClick={ () => recordEvent( 'tasklist_payment_manage', { id } ) }
		>
			{ __( 'Manage', 'woocommerce' ) }
		</Button>
	);
... (24 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/plugins/Bacs.js">
const BacsPaymentGatewaySetup = () =>
⋮----
const validate = ( values ) =>
⋮----
const updateSettings = async ( values, markConfigured ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/index.js">
export const PaymentGatewaySuggestions = (
⋮----
const trackSeeMore = () =>
⋮----
render: ()
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/PaymentGatewaySuggestions/utils.js">
export const comparePaymentGatewaysByPriority = ( a, b )
⋮----
export const getIsGatewayWCPay = ( gateway )
⋮----
export const getIsGatewayOtherCategory = ( gateway, countryCode )
⋮----
export const getIsGatewayAdditionalCategory = ( gateway, countryCode )
⋮----
export const getEnrichedPaymentGateways = (
	installedPaymentGateways,
	paymentGatewaySuggestions
) =>
⋮----
export const getIsWCPayOrOtherCategoryDoneSetup = (
	paymentGateways,
	countryCode
) =>
⋮----
export const getSplitGateways = (
	paymentGateways,
	countryCode,
	isWCPaySupported,
	isWCPayOrOtherCategoryDoneSetup
)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/products/icon/lightbulb_24px.js">
const Lightbulb = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/products/icon/link_24px.js">
const Link = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/products/icon/upload_40px.js">
const Upload = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/products/icon/widgets_24px.js">
const Widget = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/products/constants.tsx">
import { __, isRTL } from '@wordpress/i18n';
import ProductIcon from 'gridicons/dist/product';
import CloudOutlineIcon from 'gridicons/dist/cloud-outline';
import TypesIcon from 'gridicons/dist/types';
import { Icon, chevronRight, chevronLeft } from '@wordpress/icons';
import { recordEvent } from '@woocommerce/tracks';
import { getAdminLink } from '@woocommerce/settings';
⋮----
import Link from './icon/link_24px.js';
import Widget from './icon/widgets_24px.js';
import LightBulb from './icon/lightbulb_24px.js';
import PrintfulIcon from './icon/printful.png';
import Upload from './icon/upload_40px.js';
⋮----
const listItemChevron = <Icon icon=
⋮----
recordEvent( 'tasklist_add_product', {
			method: 'import',
		} );
window.location.href = getAdminLink(
			'edit.php?post_type=product&page=product_importer&wc_onboarding_active_task=products'
		);
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/products/index.tsx">
import { __ } from '@wordpress/i18n';
import { WooOnboardingTask } from '@woocommerce/onboarding';
import { Text } from '@woocommerce/experimental';
import { registerPlugin } from '@wordpress/plugins';
import { useMemo, useState } from '@wordpress/element';
import { Button } from '@wordpress/components';
import { getAdminLink } from '@woocommerce/settings';
import { Icon, chevronDown, chevronUp } from '@wordpress/icons';
import { recordEvent } from '@woocommerce/tracks';
import { applyFilters } from '@wordpress/hooks';
import { pluginsStore } from '@woocommerce/data';
import { useSelect } from '@wordpress/data';
⋮----
import { getAdminSetting } from '~/utils/admin-settings';
import { getSurfacedProductTypeKeys, getProductTypes } from './utils';
import useProductTypeListItems from './use-product-types-list-items';
import Stack from './stack';
import LoadSampleProductModal from '../components/load-sample-product-modal';
import useLoadSampleProducts from '../components/use-load-sample-products';
import LoadSampleProductConfirmModal from '../components/load-sample-product-confirm-modal';
import useRecordCompletionTime from '../use-record-completion-time';
import {
	SETUP_TASKLIST_PRODUCTS_AFTER_FILTER,
	ImportCSVItem,
	PrintfulAdvertProductPlacement,
	SponsoredProductPlacementType,
} from './constants';
import { TrackedLink } from '~/components/tracked-link/tracked-link';
⋮----
const getOnboardingProductType = (): string[] =>
... (24 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/products/stack.tsx">
import { __ } from '@wordpress/i18n';
import { List, Link, Spinner } from '@woocommerce/components';
import { Text } from '@woocommerce/experimental';
import interpolateComponents from '@automattic/interpolate-components';
import { getAdminLink } from '@woocommerce/settings';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { ProductType } from './constants';
⋮----
import useRecordCompletionTime from '../use-record-completion-time';
⋮----
type StackProps = StackWithLoadSampleBlurb | StackWithoutText;
⋮----
type StackWithLoadSampleBlurb = {
	items: ( ProductType & {
		onClick: () => void;
	} )[];
	onClickLoadSampleProduct: () => void;
	showOtherOptions?: boolean;
	isTaskListItemClicked?: boolean;
};
⋮----
type StackWithoutText = {
	items: ( ProductType & {
		onClick: () => void;
	} )[];
	showOtherOptions: false;
	onClickLoadSampleProduct?: () => void;
	isTaskListItemClicked?: boolean;
};
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/products/use-create-product-by-type.ts">
import { useDispatch } from '@wordpress/data';
import { itemsStore } from '@woocommerce/data';
import { navigateTo } from '@woocommerce/navigation';
import { getAdminLink } from '@woocommerce/settings';
import { useState } from '@wordpress/element';
⋮----
import { ProductTypeKey } from './constants';
import { createNoticesFromResponse } from '../../../lib/notices';
⋮----
export const useCreateProductByType = () =>
⋮----
const getProductEditPageLink = async ( type: ProductTypeKey ) =>
⋮----
const createProductByType = async ( type: ProductTypeKey ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/products/use-product-types-list-items.tsx">
import { useMemo } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { useCreateProductByType } from './use-create-product-by-type';
import { ProductType, ProductTypeKey } from './constants';
⋮----
type ProductTypeWithOnclick = ProductType & {
	onClick?: () => void;
};
⋮----
const useProductTypeListItems = (
	_productTypes: ProductType[],
	suggestedProductTypes: ProductTypeKey[] = [],
	{
		onClick,
	}: {
onClick?: ()
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/products/utils.tsx">
import { intersection } from 'lodash';
import { applyFilters } from '@wordpress/hooks';
⋮----
import {
	productTypes as baseProductTypes,
	ProductType,
	ProductTypeKey,
	onboardingProductTypesToSurfaced,
	supportedOnboardingProductTypes,
	defaultSurfacedProductTypes,
	SETUP_TASKLIST_PRODUCT_TYPES_FILTER,
} from './constants';
⋮----
export const getProductTypes = ( {
	exclude,
}: {
	exclude?: ProductTypeKey[];
} =
⋮----
export const getSurfacedProductTypeKeys = (
	onboardingProductTypes: string[]
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/shipping/shipping-providers/partners.tsx">
import { ShippingMethod } from '@woocommerce/data';
⋮----
import { PluginBanner } from '../../shipping-recommendation/components/plugin-banner';
⋮----
export const ShippingLayoutColumn = ( {
	shippingMethod,
}: {
	shippingMethod: ShippingMethod;
} ) =>
⋮----
/**
 * Renders a row layout for the shipping method. Used for rendering two shipping partners side by side.
 *
 * @param {Object} props                Component props
 * @param {Object} props.shippingMethod Shipping method object
 * @param {Array}  props.children       Children to render inside the layout
 * @return {JSX.Element} React node
 */
export const ShippingLayoutRow = ( {
	shippingMethod,
	children,
}: {
	shippingMethod: ShippingMethod;
	children: React.ReactNode;
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/shipping/index.js">
export const hasInstallableSlug = ( shippingMethod )
⋮----
export class Shipping extends Component
⋮----
componentDidMount()
⋮----
reset()
⋮----
async fetchShippingZones()
⋮----
getShippingPartnerTrackingProps()
⋮----
recordInstallAndActivateEvents( selectedPlugin, success )
⋮----
componentDidUpdate( prevProps, prevState )
⋮----
completeStep()
⋮----
getSteps()
⋮----
const onShippingPluginInstallationSkip = () =>
⋮----
const getSinglePluginDescription = ( name, url ) =>
⋮----
render()
⋮----
render: () => (
		<WooOnboardingTask id="shipping">
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/shipping/rates.js">
const ShippingRateIcon = ( { zone } ) => (
	<div className="woocommerce-shipping-rate__icon">
		{ zone.locations ? (
			zone.locations.map( ( location ) => (
				<Flag
					size={ 24 }
					code={ location.code }
					key={ location.code }
				/>
			) )
		) : (
			<Icon icon={ globe } />
		) }
	</div>
);
⋮----
const ShippingRateToggle = ( { zone, getInputProps } ) => (
	<label
		htmlFor={ `woocommerce-shipping-rate__toggle-${ zone.id }` }
		className="woocommerce-shipping-rate__name"
	>
		{ zone.name }
		<FormToggle
			id={ `woocommerce-shipping-rate__toggle-${ zone.id }` }
			{ ...getInputProps( `${ zone.id }_enabled` ) }
		/>
	</label>
);
⋮----
const ShippingRateInput = ( {
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/shipping/single-partner-features.ts">
import { __ } from '@wordpress/i18n';
⋮----
import TimerImage from './shipping-providers/assets/timer.svg';
import DiscountImage from './shipping-providers/assets/discount.svg';
import StarImage from './shipping-providers/assets/star.svg';
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/shipping-recommendation/components/connect.tsx">
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { default as ConnectForm } from '~/dashboard/components/connect';
⋮----
type ConnectProps = {
	onConnect?: () => void;
};
⋮----
export const Connect = (
⋮----
recordEvent( 'tasklist_shipping_recommendation_connect_store', {
					connect: true,
				} );
onConnect?.();
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/shipping-recommendation/components/plugin-banner.tsx">
import clsx from 'clsx';
⋮----
type Feature = {
	icon: string;
	title?: string;
	description: string;
};
⋮----
type PluginBannerProps = {
	logo?: {
		image: string;
		alt?: string;
		label?: string;
	};
	description?: string;
	layout?: 'single' | 'dual';
	features: Array< Feature >;
	children?: React.ReactNode;
};
⋮----
className=
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/shipping-recommendation/components/plugins.tsx">
import { __ } from '@wordpress/i18n';
import { Plugins as PluginInstaller } from '@woocommerce/components';
import { optionsStore, InstallPluginsResponse } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { useDispatch, useSelect } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
⋮----
import { createNoticesFromResponse } from '~/lib/notices';
import { TermsOfService } from '~/task-lists/components/terms-of-service';
⋮----
const isWcShippingOptions = (
	wcShippingOptions: unknown
): wcShippingOptions is
⋮----
type Props = {
	nextStep: () => void;
	pluginsToActivate: string[];
};
⋮----
createNoticesFromResponse( response );
recordEvent(
						'tasklist_shipping_recommendation_install_extensions',
						{
							install_extensions: true,
						}
					);
void updateOptions( {
						woocommerce_setup_jetpack_opted_in: true,
					} );
nextStep();
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/shipping-recommendation/components/store-location.tsx">
import { settingsStore } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { useEffect } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
⋮----
import { getCountryCode } from '~/dashboard/utils';
import { hasCompleteAddress } from '../../tax/utils';
import { default as StoreLocationForm } from '~/task-lists/fills/steps/location';
⋮----
export const StoreLocation = ( {
	nextStep,
	onLocationComplete,
}: {
nextStep: ()
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/shipping-recommendation/components/wcs-banner.tsx">
import { __ } from '@wordpress/i18n';
⋮----
import WCSImage from '../images/wcs.svg';
import PrinterImage from '../images/printer.svg';
import PaperImage from '../images/paper.svg';
import DiscountImage from '../images/discount.svg';
import { PluginBanner } from './plugin-banner';
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/shipping-recommendation/index.tsx">
import { optionsStore, pluginsStore, settingsStore } from '@woocommerce/data';
import { withSelect } from '@wordpress/data';
import { registerPlugin } from '@wordpress/plugins';
import { WooOnboardingTask } from '@woocommerce/onboarding';
import { compose } from '@wordpress/compose';
import type { SelectFunction } from '@wordpress/data/build-types/types';
⋮----
import { ShippingRecommendation } from './shipping-recommendation';
import { TaskProps } from './types';
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/shipping-recommendation/shipping-recommendation.tsx">
import { __ } from '@wordpress/i18n';
import { difference } from 'lodash';
import { useEffect, useState } from '@wordpress/element';
import { Stepper } from '@woocommerce/components';
import { Card, CardBody, Button } from '@wordpress/components';
import { getAdminLink } from '@woocommerce/settings';
⋮----
import { Connect } from './components/connect';
import { Plugins } from './components/plugins';
import { StoreLocation } from './components/store-location';
import { WCSBanner } from './components/wcs-banner';
import { TaskProps, ShippingRecommendationProps } from './types';
import { redirectToWCSSettings } from './utils';
import { TrackedLink } from '~/components/tracked-link/tracked-link';
⋮----
const nextStep = () =>
⋮----
const redirect = () =>
⋮----
const viewLocationStep = () =>
⋮----
const onLocationComplete = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/shipping-recommendation/types.ts">
import { TaskType } from '@woocommerce/data';
⋮----
export type TaskProps = {
	onComplete: () => void;
	query: Record< string, string >;
	task: TaskType;
};
⋮----
export type ShippingRecommendationProps = {
	activePlugins: string[];
	isJetpackConnected: boolean;
	isResolving: boolean;
};
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/shipping-recommendation/utils.ts">
import { getAdminLink } from '@woocommerce/settings';
⋮----
export const redirectToWCSSettings = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/steps/location.tsx">
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { countriesStore } from '@woocommerce/data';
import { Fragment, useState } from '@wordpress/element';
import { Form, FormContextType, Spinner } from '@woocommerce/components';
import { useSelect } from '@wordpress/data';
⋮----
import {
	StoreAddress,
	getStoreAddressValidator,
	FormValues,
} from '~/dashboard/components/settings/general/store-address';
import type { NoticeOptions, NoticeStatus } from '~/lib/notices/types';
⋮----
type StoreLocationProps = {
	onComplete: ( values: FormValues ) => void;
	createNotice: (
		status: NoticeStatus | undefined,
		content: string,
		options?: Partial< NoticeOptions >
	) => void;
	isSettingsRequesting: boolean;
	buttonText?: string;
	updateAndPersistSettingsForGroup: (
		group: string,
		data: {
			[ key: string ]: unknown;
		} & {
			general?: {
				[ key: string ]: string;
... (20 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/components/bullet.tsx">
export const Bullet = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/components/partner-card.tsx">
import { Button } from '@wordpress/components';
⋮----
import { Bullet } from './bullet';
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/components/partners.tsx">
import { __ } from '@wordpress/i18n';
import { Button, Card, CardBody, CardHeader } from '@wordpress/components';
import { Children } from '@wordpress/element';
import clsx from 'clsx';
import { getAdminLink } from '@woocommerce/settings';
⋮----
import { TaxChildProps } from '../utils';
import { TrackedLink } from '~/components/tracked-link/tracked-link';
⋮----
onManual();
⋮----
onDisable();
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/components/store-location.tsx">
import { settingsStore } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { useEffect } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
⋮----
import { getCountryCode } from '~/dashboard/utils';
import { hasCompleteAddress } from '../utils';
import {
	default as StoreLocationForm,
	defaultValidate,
} from '~/task-lists/fills/steps/location';
import { FormValues } from '~/dashboard/components/settings/general/store-address';
⋮----
const validateLocationForm = ( values: FormValues ) =>
⋮----
export const StoreLocation = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/manual-configuration/configure.tsx">
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import interpolateComponents from '@automattic/interpolate-components';
import { Link } from '@woocommerce/components';
import { recordEvent } from '@woocommerce/tracks';
import { settingsStore } from '@woocommerce/data';
import { useSelect } from '@wordpress/data';
⋮----
import { TaxChildProps } from '../utils';
⋮----
export const Configure = ( {
	isPending,
	onManual,
}: Pick< TaxChildProps, 'isPending' | 'onManual' > ) =>
⋮----
recordEvent( 'tasklist_tax_config_rates',
onManual();
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/manual-configuration/index.tsx">
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import { Stepper } from '@woocommerce/components';
⋮----
import { Configure } from './configure';
import { StoreLocation } from '../components/store-location';
⋮----
export type ManualConfigurationProps = {
	isPending: boolean;
	onDisable: () => void;
	onAutomate: () => void;
	onManual: () => void;
};
⋮----
export const ManualConfiguration = ( {
	isPending,
	onDisable,
	onAutomate,
	onManual,
}: ManualConfigurationProps ) =>
⋮----
const nextStep = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/stripe-tax/card.tsx">
import { __ } from '@wordpress/i18n';
import { getAdminLink } from '@woocommerce/settings';
import { recordEvent } from '@woocommerce/tracks';
import { Plugins } from '@woocommerce/components';
import { dispatch, useDispatch } from '@wordpress/data';
import { settingsStore } from '@woocommerce/data';
import { Button } from '@wordpress/components';
⋮----
import { PartnerCard } from '../components/partner-card';
import { TaxChildProps } from '../utils';
import StripeTaxLogo from './stripe-tax-logo.svg';
import { createNoticesFromResponse } from '~/lib/notices';
⋮----
const redirectToStripeTaxSettings = () =>
⋮----
name=
⋮----
__( 'Multi-economic nexus compliance', 'woocommerce' ),
__( 'Detailed tax transaction reports', 'woocommerce' ),
__( 'Coverage in over 55 countries', 'woocommerce' ),
⋮----
onComplete=
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/woocommerce-tax/automated-taxes.tsx">
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import interpolateComponents from '@automattic/interpolate-components';
import { H } from '@woocommerce/components';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { SetupStepProps } from './setup';
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/woocommerce-tax/card.tsx">
import { __ } from '@wordpress/i18n';
import interpolateComponents from '@automattic/interpolate-components';
import { recordEvent } from '@woocommerce/tracks';
import { updateQueryString } from '@woocommerce/navigation';
⋮----
import { PartnerCard } from '../components/partner-card';
import logo from './logo.png';
import { TermsOfService } from '~/task-lists/components/terms-of-service';
⋮----
export const Card = () =>
⋮----
name=
⋮----
interpolateComponents(
⋮----
__( '100% free', 'woocommerce' ),
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/woocommerce-tax/connect.tsx">
import { __ } from '@wordpress/i18n';
import { recordEvent, queueRecordEvent } from '@woocommerce/tracks';
⋮----
import { default as ConnectForm } from '~/dashboard/components/connect';
import { SetupStepProps } from './setup';
⋮----
export const Connect = (
⋮----
recordEvent( 'tasklist_tax_connect_store', {
					connect: true,
					no_tax: false,
				} );
⋮----
queueRecordEvent( 'tasklist_tax_connect_store', {
					connect: false,
					no_tax: false,
				} );
onManual();
⋮----
skipText=
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/woocommerce-tax/index.tsx">
import { difference } from 'lodash';
import { useSelect } from '@wordpress/data';
import { Spinner } from '@woocommerce/components';
import { pluginsStore, settingsStore } from '@woocommerce/data';
⋮----
import {
	AUTOMATION_PLUGINS,
	hasCompleteAddress,
	TaxChildProps,
} from '../utils';
import { AutomatedTaxes } from './automated-taxes';
import { Setup } from './setup';
⋮----
export const WooCommerceTax = ( {
	isPending,
	onAutomate,
	onManual,
	onDisable,
}: TaxChildProps ) =>
⋮----
const canAutomateTaxes = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/woocommerce-tax/plugins.tsx">
import { __ } from '@wordpress/i18n';
import { Plugins as PluginInstaller } from '@woocommerce/components';
import { optionsStore, InstallPluginsResponse } from '@woocommerce/data';
import { recordEvent, queueRecordEvent } from '@woocommerce/tracks';
import { useDispatch, useSelect } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
⋮----
import { createNoticesFromResponse } from '~/lib/notices';
import { SetupStepProps } from './setup';
import { TermsOfService } from '~/task-lists/components/terms-of-service';
⋮----
const isWcConnectOptions = (
	wcConnectOptions: unknown
): wcConnectOptions is
⋮----
createNoticesFromResponse( response );
recordEvent( 'tasklist_tax_install_extensions', {
						install_extensions: true,
					} );
void updateOptions( {
						woocommerce_setup_jetpack_opted_in: true,
					} );
nextStep();
⋮----
createNoticesFromResponse( response )
⋮----
queueRecordEvent( 'tasklist_tax_install_extensions', {
						install_extensions: false,
					} );
onManual();
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/woocommerce-tax/setup.tsx">
import { __ } from '@wordpress/i18n';
import { difference } from 'lodash';
import { useEffect, useState } from '@wordpress/element';
import { Stepper } from '@woocommerce/components';
import { optionsStore, pluginsStore, settingsStore } from '@woocommerce/data';
import { useSelect } from '@wordpress/data';
⋮----
import { AUTOMATION_PLUGINS } from '../utils';
import { Connect } from './connect';
import { Plugins } from './plugins';
import { StoreLocation } from '../components/store-location';
⋮----
export type SetupProps = {
	isPending: boolean;
	onDisable: () => void;
	onAutomate: () => void;
	onManual: () => void;
};
⋮----
export type SetupStepProps = {
	isPending: boolean;
	isResolving: boolean;
	nextStep: () => void;
	onDisable: () => void;
	onAutomate: () => void;
	onManual: () => void;
	pluginsToActivate: string[];
};
⋮----
export const Setup = ( {
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/index.tsx">
import { __ } from '@wordpress/i18n';
import { Card, CardBody, Spinner } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { getAdminLink } from '@woocommerce/settings';
import { optionsStore, settingsStore, TaskType } from '@woocommerce/data';
import { queueRecordEvent, recordEvent } from '@woocommerce/tracks';
import { registerPlugin } from '@wordpress/plugins';
import {
	useCallback,
	useEffect,
	useState,
	createElement,
	useMemo,
} from '@wordpress/element';
import { WooOnboardingTask } from '@woocommerce/onboarding';
⋮----
import { redirectToTaxSettings } from './utils';
import { Card as WooCommerceTaxCard } from './woocommerce-tax/card';
import { Card as StripeTaxCard } from './stripe-tax/card';
import { createNoticesFromResponse } from '../../../lib/notices';
import { getCountryCode } from '~/dashboard/utils';
import { ManualConfiguration } from './manual-configuration';
import { Partners } from './components/partners';
import { WooCommerceTax } from './woocommerce-tax';
⋮----
const TaskCard = (
⋮----
export type TaxProps = {
	onComplete: () => void;
	query: Record< string, string >;
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/tax/utils.ts">
import { getAdminLink } from '@woocommerce/settings';
import { TaskType } from '@woocommerce/data';
⋮----
export const hasCompleteAddress = (
	generalSettings: Record< string, string >,
	requiresPostcode = true
): boolean =>
⋮----
export const redirectToTaxSettings = (): void =>
⋮----
export type TaxChildProps = {
	isPending: boolean;
	onAutomate: () => void;
	onManual: () => void;
	onDisable: () => void;
	task: TaskType;
	children?: React.ReactNode;
};
⋮----
export const supportsWooCommerceTax = (
	countryCode: string | null
): boolean =>
⋮----
export const supportsAvalara = ( countryCode: string ): boolean =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/appearance.js">
export const useAppearanceClick = () =>
⋮----
const onClick = () =>
⋮----
const AppearanceFill = () =>
⋮----
render: ()
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/deprecated-tasks.tsx">
import { registerPlugin } from '@wordpress/plugins';
import { WooOnboardingTask } from '@woocommerce/onboarding';
import { useSelect } from '@wordpress/data';
import {
	onboardingStore,
	TaskType,
	DeprecatedTaskType,
} from '@woocommerce/data';
⋮----
import { isTaskListActive } from '~/hooks/use-tasklists-state';
⋮----
type MergedTask = TaskType | DeprecatedTaskType;
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/index.ts">
import { isImportProduct } from './utils';
⋮----
const possiblyImportProductTask = async () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/launch-your-store.tsx">
import { registerPlugin } from '@wordpress/plugins';
import { WooOnboardingTaskListItem } from '@woocommerce/onboarding';
⋮----
const LaunchYourStoreTaskItem = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/purchase.tsx">
import { registerPlugin } from '@wordpress/plugins';
import { WooOnboardingTaskListItem } from '@woocommerce/onboarding';
import { useState, useCallback } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
import { useSelect } from '@wordpress/data';
import { onboardingStore, pluginsStore } from '@woocommerce/data';
⋮----
import CartModal from '../../dashboard/components/cart-modal';
import { getCategorizedOnboardingProducts } from '../../dashboard/utils';
⋮----
type PurchaseTaskItemProps = {
	defaultTaskItem: React.ComponentType< {
		onClick: () => void;
	} >;
};
⋮----
toggleCartModal();
⋮----
onClose=
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/use-record-completion-time.ts">
import { useRef } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { getTimeFrame } from '~/utils';
⋮----
const useRecordCompletionTime = ( taskName: string, startTime?: number ) =>
⋮----
const recordCompletionTime = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/utils.js">
export const isImportProduct = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/fills/woocommerce-payments.tsx">
import { registerPlugin } from '@wordpress/plugins';
import { WooOnboardingTask } from '@woocommerce/onboarding';
⋮----
import { PaymentGatewaySuggestions } from './PaymentGatewaySuggestions';
⋮----
const WoocommercePaymentsTaskPage = () => (
	<WooOnboardingTask id="woocommerce-payments">
		{ ( { onComplete, query } ) => (
			<PaymentGatewaySuggestions
				onComplete={ onComplete }
				query={ query }
			/>
		) }
	</WooOnboardingTask>
);
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/progress-title/default-progress-title.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { useMemo } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { getVisibleTasks, onboardingStore } from '@woocommerce/data';
import { getSetting } from '@woocommerce/settings';
⋮----
import sanitizeHTML from '../../lib/sanitize-html';
⋮----
export type DefaultProgressTitleProps = {
	taskListId: string;
};
⋮----
export const DefaultProgressTitle = ( {
	taskListId,
}: DefaultProgressTitleProps ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/progress-title/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/progress-title/progress-title.tsx">
import { useSlot } from '@woocommerce/experimental';
⋮----
import {
	WC_TASKLIST_EXPERIMENTAL_PROGRESS_TITLE_SLOT_NAME,
	WooTaskListProgressTitleItem,
} from './utils';
⋮----
import {
	DefaultProgressTitle,
	DefaultProgressTitleProps,
} from './default-progress-title';
⋮----
export const ProgressTitle = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/progress-title/utils.tsx">
import { Slot, Fill } from '@wordpress/components';
import {
	createOrderedChildren,
	sortFillsByOrder,
} from '@woocommerce/components';
⋮----
export const WooTaskListProgressTitleItem = ( {
	children,
	order = 1,
}: {
	children?: React.ComponentProps< typeof Fill >[ 'children' ];
	order?: number;
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-headers/appearance.js">
const AppearanceHeader = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-headers/customize-store.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { TaskType } from '@woocommerce/data';
⋮----
import { WC_ASSET_URL } from '../../../../utils/admin-settings';
import { isWooExpress } from '~/utils/is-woo-express';
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-headers/default.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { TaskType } from '@woocommerce/data';
⋮----
interface DefaultTaskHeaderProps {
	task: TaskType;
	goToTask: () => void;
}
⋮----
const DefaultTaskHeader = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-headers/index.ts">
import StoreDetailsHeader from './store-details';
import CustomizeStoreHeader from './customize-store';
import TaxHeader from './tax';
import MarketingHeader from './marketing';
import AppearanceHeader from './appearance';
import ShippingHeader from './shipping';
import ProductsHeader from './products';
import PurchaseHeader from './purchase';
import PaymentsHeader from './payments';
import WoocommercePaymentsHeader from './woocommerce-payments';
import LaunchYourStoreHeader from './launch-your-store';
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-headers/launch-your-store.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { TaskType } from '@woocommerce/data';
⋮----
import { WC_ASSET_URL } from '../../../../utils/admin-settings';
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-headers/marketing.js">
const MarketingHeader = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-headers/payments.js">
const PaymentsHeader = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-headers/products.js">
const ProductsHeader = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-headers/purchase.js">
const PurchaseHeader = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-headers/shipping.js">
const ShippingHeader = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-headers/store-details.js">
const StoreDetailsHeader = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-headers/tax.js">
const TaxHeader = (
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-headers/woocommerce-payments.js">
const connect = ( createNotice, setIsBusy ) =>
⋮----
const WoocommercePaymentsHeader = (
⋮----
const onClick = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/dismiss-modal.tsx">
import { Button, Modal } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
const closeModal = ()
⋮----
onClick=
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-list-completed-header.tsx">
import clsx from 'clsx';
import { useEffect, useState } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
import { useDispatch, useSelect } from '@wordpress/data';
import { optionsStore, WEEK } from '@woocommerce/data';
import { Card, CardHeader, DropdownMenu } from '@wordpress/components';
import { moreVertical } from '@wordpress/icons';
import { Text } from '@woocommerce/experimental';
import {
	ADMIN_INSTALL_TIMESTAMP_OPTION_NAME,
	ALLOW_TRACKING_OPTION_NAME,
	CustomerFeedbackModal,
	CustomerFeedbackSimple,
	SHOWN_FOR_ACTIONS_OPTION_NAME,
} from '@woocommerce/customer-effort-score';
import { __ } from '@wordpress/i18n';
⋮----
import HeaderImage from '../assets/completed-celebration-header.svg';
⋮----
type TaskListCompletedHeaderProps = {
	hideTasks: () => void;
	customerEffortScore: boolean;
};
⋮----
function getStoreAgeInWeeks( adminInstallTimestamp: number )
⋮----
const submitScore = ( {
		firstScore,
		secondScore,
		comments,
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-list-completed.tsx">
import clsx from 'clsx';
import { Button, Card, CardHeader } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
import HeaderImage from '../assets/task-list-completed.svg';
⋮----
className=
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-list-item.tsx">
import { __ } from '@wordpress/i18n';
import { onboardingStore, TaskType } from '@woocommerce/data';
import { TaskItem, useSlot } from '@woocommerce/experimental';
import { useCallback } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
⋮----
import { WooOnboardingTaskListItem } from '@woocommerce/onboarding';
import clsx from 'clsx';
⋮----
export type TaskListItemProps = {
	task: TaskType;
	activeTaskId: string;
	taskIndex: number;
	goToTask: () => void;
	trackClick: () => void;
};
⋮----
export const TaskListItem = ( {
	task,
	activeTaskId,
	taskIndex,
	goToTask,
	trackClick,
}: TaskListItemProps ) =>
⋮----
const onDismissTask = ( onDismiss?: () => void ) =>
⋮----
const onClick = ( e: React.MouseEvent< HTMLButtonElement > ) =>
⋮----
isDismissable ? ()
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/components/task-list-placeholder.tsx">
import clsx from 'clsx';
⋮----
type TasksPlaceholderProps = {
	numTasks?: number;
	twoColumns?: boolean;
	query: {
		task?: string;
	};
};
⋮----
className=
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/footer-slot/footer-slot.tsx">
import { useSlot } from '@woocommerce/experimental';
⋮----
import {
	EXPERIMENTAL_WC_TASKLIST_FOOTER_SLOT_NAME,
	ExperimentalWooTaskListFooterItem,
} from './utils';
⋮----
export const ExperimentalWooTaskListFooter = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/footer-slot/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/footer-slot/utils.tsx">
import { Slot, Fill } from '@wordpress/components';
import {
	createOrderedChildren,
	sortFillsByOrder,
} from '@woocommerce/components';
⋮----
export const ExperimentalWooTaskListFooterItem = ( {
	children,
	order = 1,
}: {
	children: React.ReactNode;
	order?: number;
} ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/task-list-completion-slot/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/task-list-completion-slot/task-list-completion-slot.tsx">
import { useSlot } from '@woocommerce/experimental';
import clsx from 'clsx';
⋮----
import {
	EXPERIMENTAL_WC_TASK_LIST_COMPLETION_SLOT_NAME,
	WooTaskListCompletion,
	WooTaskListCompletionFillProps,
} from './utils';
⋮----
export const TaskListCompletionSlot = ( {
	className,
	fillProps,
}: {
	className?: string;
	fillProps: WooTaskListCompletionFillProps;
} ) =>
⋮----
className=
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/task-list-completion-slot/utils.tsx">
import { Slot, Fill } from '@wordpress/components';
import {
	createOrderedChildren,
	sortFillsByOrder,
} from '@woocommerce/components';
⋮----
type WooTaskListCompletionProps = {
	children: React.ReactNode;
	order?: number;
};
⋮----
export const WooTaskListCompletion = ( {
	children,
	order = 1,
}: WooTaskListCompletionProps ) =>
⋮----
export type WooTaskListCompletionFillProps = {
	hideTasks: () => void;
	keepTasks: () => void;
	customerEffortScore: boolean;
};
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/setup-task-list/setup-task-list.tsx">
import { __ } from '@wordpress/i18n';
import { useEffect, useRef, useState, createElement } from '@wordpress/element';
import { Button, Card } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { EllipsisMenu } from '@woocommerce/components';
import { navigateTo, getNewPath } from '@woocommerce/navigation';
import { WooOnboardingTaskListHeader } from '@woocommerce/onboarding';
import {
	TaskType,
	useUserPreferences,
	getVisibleTasks,
	TaskListType,
	onboardingStore,
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { List, useSlot } from '@woocommerce/experimental';
import clsx from 'clsx';
import { useLayoutContext } from '@woocommerce/admin-layout';
⋮----
import { taskHeaders, DefaultTaskHeader } from './components/task-headers';
import DismissModal from './components/dismiss-modal';
import TaskListCompleted from './components/task-list-completed';
import { ProgressHeader } from '~/task-lists/components/progress-header';
import { TaskListItem } from './components/task-list-item';
import { TaskListCompletedHeader } from './components/task-list-completed-header';
⋮----
import { ExperimentalWooTaskListFooter } from './footer-slot';
import {
	TaskListCompletionSlot,
	EXPERIMENTAL_WC_TASK_LIST_COMPLETION_SLOT_NAME,
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/task-lists/task-lists.tsx">
import { __ } from '@wordpress/i18n';
import { MenuGroup, MenuItem } from '@wordpress/components';
import { check } from '@wordpress/icons';
import { Fragment } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import { onboardingStore, TaskListType, TaskType } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { DisplayOption } from '~/activity-panel/display-options';
⋮----
import {
	SetupTaskList,
	TaskListPlaceholder as SetupTaskListPlaceholder,
} from './setup-task-list';
⋮----
import { Task } from './components/task';
import { TasksPlaceholder } from './components/placeholder';
import { TaskList } from './components/task-list';
import { getAdminSetting } from '~/utils/admin-settings';
⋮----
export type TaskListsProps = {
	query: { task?: string };
	context?: string;
};
⋮----
const getCurrentTask = () =>
⋮----
const toggleTaskList = ( taskList: TaskListType ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/tax/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/tax/tax-recommendations-wrapper.tsx">
import { lazy, Suspense } from '@wordpress/element';
⋮----
import { EmbeddedBodyProps } from '../embedded-body-layout/embedded-body-props';
import RecommendationsEligibilityWrapper from '../settings-recommendations/recommendations-eligibility-wrapper';
⋮----
export const TaxRecommendations = ( {
	page,
	tab,
	section,
}: EmbeddedBodyProps ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/tax/tax-recommendations.tsx">
import { Button, CardFooter, ExternalLink } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { Children, useEffect, useRef, useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { Text } from '@woocommerce/experimental';
import { PluginNames, pluginsStore, settingsStore } from '@woocommerce/data';
import { getAdminLink } from '@woocommerce/settings';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import taxLogo from '../task-lists/fills/tax/woocommerce-tax/logo.png';
import { createNoticesFromResponse } from '../lib/notices';
import {
	DismissableList,
	DismissableListHeading,
} from '../settings-recommendations/dismissable-list';
import { supportsWooCommerceTax } from '../task-lists/fills/tax/utils';
import { TrackedLink } from '~/components/tracked-link/tracked-link';
import { getCountryCode } from '~/dashboard/utils';
import { getAdminSetting } from '~/utils/admin-settings';
import { useEndpointDismiss } from '~/hooks/use-endpoint-dismiss';
⋮----
type TaxRecommendation = {
	id: 'anrok-tax' | 'woocommerce-tax';
	title: string;
	description: string;
	productUrl: string;
	logo: React.ReactNode;
	pluginSlugs: string[];
};
⋮----
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/typings/global.d.ts">
type DeprecatedWcAdminFeatureFlags = {
	'activity-panels': boolean;
	analytics: boolean;
	'analytics-scheduled-import': boolean;
	'experimental-iapi-mini-cart': boolean;
	coupons: boolean;
	'core-profiler': boolean;
	'customize-store': boolean;
	'customer-effort-score-tracks': boolean;
	'import-products-task': boolean;
	'experimental-fashion-sample-products': boolean;
	'shipping-smart-defaults': boolean;
	'shipping-setting-tour': boolean;
	homescreen: boolean;
	marketing: boolean;
	'mobile-app-banner': boolean;
	onboarding: boolean;
	'onboarding-tasks': boolean;
	'pattern-toolkit-full-composability': boolean;
	'payment-gateway-suggestions': boolean;
	'product-custom-fields': boolean;
	printful: boolean;
	'remote-inbox-notifications': boolean;
	'remote-free-extensions': boolean;
	'shipping-label-banner': boolean;
	subscriptions: boolean;
	'transient-notices': boolean;
	'wc-pay-promotion': boolean;
	'wc-pay-welcome-page': boolean;
	'woo-mobile-welcome': boolean;
... (136 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/typings/index.d.ts">
export declare function getAdminLink( path: string ): string;
export declare function getSetting< T >(
		name: string,
		fallback?: unknown,
filter = ( val: unknown, fb: unknown )
⋮----
export type ShortcutKeyCombination = {
		modifier?: string;
		character: string;
	};
</file>

<file path="plugins/woocommerce/client/admin/client/typings/monorepo-enhancements.d.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/utils/features/features.ts">
import { getAdminSetting } from '../admin-settings';
import { Feature } from './types';
import {
	isRetiredFeatureFlag,
	warnRetiredFeatureFlag,
} from './retired-feature-flags';
⋮----
get( target, property, receiver )
⋮----
export function getFeature( featureId: string ): Feature | undefined
⋮----
export function isFeatureEnabled( featureId: string ): boolean
⋮----
export function isFeatureExperimental( featureId: string ): boolean
</file>

<file path="plugins/woocommerce/client/admin/client/utils/features/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/utils/features/retired-feature-flags.ts">
import deprecated from '@wordpress/deprecated';
⋮----
type RetiredFeatureFlagMetadata = {
	deprecatedSince: string;
	removedIn: string | null;
};
⋮----
type RetiredFeatureFlag = keyof typeof RETIRED_FEATURE_FLAGS;
⋮----
export const getRetiredFeatureFlagDeprecationVersion = (
	featureId: string
): string | undefined
⋮----
export const getRetiredFeatureFlagRemovalVersion = (
	featureId: string
): string | null | undefined
⋮----
export const isRetiredFeatureFlag = ( featureId: string ): boolean
⋮----
export const warnRetiredFeatureFlag = ( featureId: string ): void =>
</file>

<file path="plugins/woocommerce/client/admin/client/utils/features/types.ts">
export interface Feature {
	is_enabled: boolean;
	is_experimental: boolean;
}
</file>

<file path="plugins/woocommerce/client/admin/client/utils/react-hooks/use-network-status.tsx">
import { useState, useEffect } from '@wordpress/element';
⋮----
export const useNetworkStatus = () =>
⋮----
const offlineEventHandler = () =>
⋮----
const onlineEventHandler = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/utils/xstate/find-component.tsx">
export function findComponentMeta< T >(
	obj: Record< string, unknown >,
	visited = new Set< Record< string, unknown > >()
): T | undefined
</file>

<file path="plugins/woocommerce/client/admin/client/utils/xstate/url-handling.ts">
import {
	getHistory,
	getQuery,
	updateQueryString,
} from '@woocommerce/navigation';
import { AnyEventObject } from 'xstate5';
⋮----
export const createQueryParamsListener = (
	paramName: string,
	sendBack: ( event: AnyEventObject ) => void
) =>
⋮----
export const updateQueryParams = < T extends Record< string, string > >(
	params: Partial< T >
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/utils/xstate/useComponentFromService.tsx">
import { useSelector as xstateUseSelector } from '@xstate5/react';
import { useEffect, useState } from 'react';
⋮----
import { findComponentMeta } from '~/utils/xstate/find-component';
⋮----
type ComponentMetaType< ComponentPropsType > = {
	component: ( arg0: ComponentPropsType ) => React.ReactElement;
};
export function useComponentFromXStateService< ComponentProps >(
	service: Parameters< typeof xstateUseSelector >[ 0 ]
): [ ComponentMetaType< ComponentProps >[ 'component' ] | null ]
</file>

<file path="plugins/woocommerce/client/admin/client/utils/xstate/useMobileHeaderFromService.tsx">
import { useSelector as xstateUseSelector } from '@xstate5/react';
import { useEffect, useState } from 'react';
⋮----
type MobileHeaderMetaType< ComponentPropsType > = {
	mobileHeader: ( arg0: ComponentPropsType ) => React.ReactElement;
};
⋮----
export function useMobileHeaderFromXStateService< ComponentProps >(
	service: Parameters< typeof xstateUseSelector >[ 0 ]
): [ MobileHeaderMetaType< ComponentProps >[ 'mobileHeader' ] | null ]
</file>

<file path="plugins/woocommerce/client/admin/client/utils/admin-settings.js">
export function getAdminSetting(
	name,
	fallback = false,
	filter = ( val ) => val,
	deprecatedProperties = deprecatedAdminProperties
)
⋮----
export function setAdminSetting( name, value, filter = ( val ) => val )
</file>

<file path="plugins/woocommerce/client/admin/client/utils/derive-wp-admin-background-colours.ts">
function blendWithWhite( hex: string, alpha: number )
⋮----
export const deriveWpAdminBackgroundColours = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/utils/enqueue-script.js">
export function enqueueScript( script )
</file>

<file path="plugins/woocommerce/client/admin/client/utils/index.js">
export function getUrlParams( locationSearch )
⋮----
export function getScreenName()
⋮----
export const sift = ( arr, partitioner )
⋮----
export const getTimeFrame = ( timeInMs ) =>
⋮----
export const useFullScreen = ( classes ) =>
⋮----
export function createDeprecatedPropertiesProxy(
	obj,
	messages,
	basePath = ''
)
⋮----
// If not a plain object or array, return as is
⋮----
get( target, prop, receiver )
</file>

<file path="plugins/woocommerce/client/admin/client/utils/is-woo-express.ts">
interface Window {
		wcCalypsoBridge?: {
			isWooExpress: boolean;
		};
	}
⋮----
export const isWooExpress = (): boolean
</file>

<file path="plugins/woocommerce/client/admin/client/utils/localStorage.ts">
type StoredItem< T > = {
	data: T;
	expiry: string;
};
⋮----
export function createStorageUtils< T >(
	key: string,
	durationInSeconds: number
)
</file>

<file path="plugins/woocommerce/client/admin/client/utils/plugins.ts">
export function getPluginSlug( id: string | null ): string
⋮----
export function getPluginTrackKey( id: string ): string
</file>

<file path="plugins/woocommerce/client/admin/client/utils/README.md">
Utils
=========

This folder contains general utils.
</file>

<file path="plugins/woocommerce/client/admin/client/utils/static-form-helper.ts">
export function staticFormDataToObject( elForm: HTMLFormElement )
</file>

<file path="plugins/woocommerce/client/admin/client/utils/url-helpers.ts">
export function getSegmentsFromPath( path?: string ): string[]
</file>

<file path="plugins/woocommerce/client/admin/client/utils/use-filter-hook.ts">
import { useEffect, useState } from '@wordpress/element';
import { addAction, removeAction, didFilter } from '@wordpress/hooks';
⋮----
export function useFilterHook< T >(
	filterName: string,
	getterFn: () => T,
	dependencies: React.DependencyList = []
): T
⋮----
const handleHookAdded = ( hookName: string ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/add-term-tracking/index.js">
function actionButtonEventHandler( event )
⋮----
function addActionButtonListeners()
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/attributes-tracking/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/category-tracking/index.js">
function actionButtonEventHandler( event )
⋮----
function addActionButtonListeners()
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/command-palette/index.js">
function useProductCommandLoader(
⋮----
callback: (
⋮----
callback: () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/command-palette/register-command-with-tracking.js">
export const registerCommandWithTracking = ( {
	name,
	label,
	icon,
	callback,
	origin,
} ) =>
⋮----
callback: ( ...args ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/command-palette-analytics/index.js">
const registerWooCommerceAnalyticsCommand = (
⋮----
callback: () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/hooks/use-apply-update.ts">
import { useCallback, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
import { select, useDispatch } from '@wordpress/data';
import { store as noticesStore } from '@wordpress/notices';
import { store as coreStore } from '@wordpress/core-data';
⋮----
export interface ApplyChoice {
	path: Array< number | string >;
	decision: 'keep_yours' | 'use_core';
}
⋮----
interface ApplyResponse {
	merged_content: string;
	revision_id: string;
	version_to: string;
	status: 'applied';
	structural_skipped: boolean;
	aliases_migrated: string[];
}
⋮----
interface UndoResponse {
	restored_content: string;
	status: 'restored';
}
⋮----
interface UseApplyUpdateOptions {
	suppressSnackbarOnError?: boolean;
}
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/hooks/use-change-summary.ts">
import { useCallback, useEffect, useState } from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';
⋮----
export interface ChangeSummaryBlockEntry {
	name: string;
	label: string;
	path: Array< number | string >;
}
⋮----
export interface ChangeSummaryCopyChange {
	block: string;
	before: string;
	after: string;
	occurrence: number;
	total: number;
	path: Array< number | string >;
	auto_resolvable?: boolean;
}
⋮----
export interface ChangeSummaryStructuralChange {
	kind: string;
	description: string;
	path?: Array< number | string >;
}
⋮----
export interface ChangeSummary {
	version_from: string;
	version_to: string;
	source_hash_to: string;
	added_blocks: ChangeSummaryBlockEntry[];
... (20 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/hooks/use-update-banner.ts">
import {
	useCallback,
	useEffect,
	useMemo,
	useRef,
	useState,
} from '@wordpress/element';
import { select, useDispatch, useSelect } from '@wordpress/data';
import { useEntityRecord } from '@wordpress/core-data';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { useChangeSummary, type ChangeSummary } from './use-change-summary';
import { useApplyUpdate } from './use-apply-update';
import { STORE_NAME } from '../store';
import {
	buildSharedTracksPayload,
	APPLIED_FROM_EDITOR_BANNER,
	VIEWED_FROM_EDITOR_BANNER,
	type SharedTracksPayload,
} from '../tracks/build-shared-payload';
⋮----
function compareTemplateVersions( a: string, b: string ): number
⋮----
async function sha1Hex( input: string ): Promise< string >
⋮----
/**
 * Apply state machine values surfaced by `useUpdateBanner`.
 *
 * `idle`     — no apply has been initiated, or the previous apply settled
 *              and the banner is back to its default surface.
... (29 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/templates/index.tsx">
import { addFilter } from '@wordpress/hooks';
⋮----
import { TemplateSenderPanel } from './template_sender_panel';
⋮----
function modifyTemplateSidebar()
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/templates/template_sender_panel.tsx">
import { __ } from '@wordpress/i18n';
import { PanelRow, TextControl } from '@wordpress/components';
import { useEntityProp } from '@wordpress/core-data';
import { useCallback, useRef } from '@wordpress/element';
⋮----
type TemplateSenderPanelProps = {
	debouncedRecordEvent: (
		name: string,
		data?: Record< string, unknown >
	) => void;
};
⋮----
/* translators: Label for the sender's `“from” email` in email settings. */
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/tracks/build-shared-payload.ts">
import type { ChangeSummary } from '../hooks/use-change-summary';
⋮----
export type AppliedFrom =
	| typeof APPLIED_FROM_EDITOR_BANNER
	| typeof APPLIED_FROM_AUTO
	| typeof APPLIED_FROM_SELECTIVE_REST;
⋮----
export type ViewedFrom =
	| typeof VIEWED_FROM_EDITOR_BANNER
	| typeof VIEWED_FROM_EMAIL_LIST;
⋮----
export interface SharedTracksPayload {
	email_id: string;
	template_version_from: string;
	template_version_to: string | null;
	source_hash_to: string | null;
	classification: string;
	was_backfilled: boolean;
	[ key: string ]: unknown;
}
⋮----
export interface SharedPayloadInputs {
	record: {
		slug?: unknown;
		meta?: Record< string, unknown >;
	} | null;
	summary: ChangeSummary | null;
}
⋮----
export function buildSharedTracksPayload( {
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/constants.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/email-status.tsx">
import { __, sprintf } from '@wordpress/i18n';
import { select, dispatch } from '@wordpress/data';
import {
	PanelRow,
	Button,
	Flex,
	FlexItem,
	Dropdown,
	RadioControl,
} from '@wordpress/components';
import { closeSmall } from '@wordpress/icons';
import { store as coreDataStore, useEntityProp } from '@wordpress/core-data';
⋮----
import { EMAIL_STATUSES } from '../../settings-email/settings-email-listing-status';
⋮----
interface EmailStatusProps {
	className?: string;
	recordEvent: ( name: string, data?: Record< string, unknown > ) => void;
}
⋮----
const updateStatus = ( newValue: boolean ): void =>
⋮----
aria-label=
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/email-validation.ts">
import { addFilter } from '@wordpress/hooks';
import { __, sprintf } from '@wordpress/i18n';
import { select } from '@wordpress/data';
⋮----
import { NAME_SPACE } from './constants';
⋮----
type EmailContentValidationRule = {
	id: string;
	testContent: ( emailContent: string ) => boolean;
	message: string;
	actions: [];
};
⋮----
type WooCommerceEmailEditorData = Partial< EmailWooCommerceData > &
	Partial< TemplateWooCommerceData >;
⋮----
function getWooCommerceData(): WooCommerceEmailEditorData | undefined
⋮----
function isValidEmail( email: string ): boolean
⋮----
function getInvalidCommaSeparatedEmails( commaSeparatedEmails: string )
⋮----
function createValidationRuleForCommaSeparatedEmailsField(
	fieldName: 'recipient' | 'cc' | 'bcc',
	message: string
): EmailContentValidationRule
⋮----
get message()
⋮----
// @ts-expect-error - The type isn't correct. We need to update @wordpress/i18n to a newer version to fix it.
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/global.d.ts">
interface Window {
	WooCommerceEmailEditor: {
		current_post_type: string;
		current_post_id: string;
		email_types: {
			value: string;
			label: string;
			id: string;
		}[];
		sender_settings: {
			from_name: string;
			from_address: string;
		};
	};
}
⋮----
interface EmailWooCommerceData {
	recipient: string | null;
	cc: string | null;
	bcc: string | null;
	preheader: string | null;
	email_type: string | null;
	subject: string | null;
	subject_full: string | null;
	subject_partial: string | null;
	default_subject: string | null;
	is_manual: boolean;
	enabled: boolean;
}
⋮----
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/index.ts">
import { dispatch } from '@wordpress/data';
import { addFilter, addAction } from '@wordpress/hooks';
import { registerPlugin } from '@wordpress/plugins';
import {
	initializeEditor,
	registerEntityAction,
} from '@woocommerce/email-editor';
⋮----
import { NAME_SPACE } from './constants';
import { registerWooEmailSaveButton } from './save-button';
import { modifyTemplateSidebar } from './templates';
import { modifySidebar } from './sidebar_settings';
import { registerEmailValidationRules } from './email-validation';
import getResetNotificationEmailContentAction from './reset-notification-email-content';
import { ReviewUpdatePlugin } from './review-update-plugin';
import { UpdateBannerPlugin } from './update-banner-plugin';
import {
	registerStore as registerIntegrationStore,
	STORE_NAME as INTEGRATION_STORE_NAME,
} from './store';
⋮----
/**
 * Register the reset notification email content entity action for the woo_email post type.
 * This action allows users to reset the email content to the original state as distributed by the plugin.
 */
const registerResetNotificationEmailContentAction = ( postType: string ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/reset-notification-email-content.tsx">
import { __, sprintf, TranslatableText } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';
import { store as coreStore } from '@wordpress/core-data';
import { backup } from '@wordpress/icons';
import { useState } from '@wordpress/element';
import { select, useDispatch } from '@wordpress/data';
import {
	Button,
	__experimentalText as Text,
	__experimentalHStack as HStack,
	__experimentalVStack as VStack,
} from '@wordpress/components';
import { decodeEntities } from '@wordpress/html-entities';
import apiFetch from '@wordpress/api-fetch';
⋮----
import type { PostWithPermissions } from '@woocommerce/email-editor';
⋮----
function getItemTitle( item: {
	title: string | { rendered: string } | { raw: string };
} )
⋮----
/**
	 * Reset notification email content action.
	 * Resets a woo_email post content to the original state as distributed by the plugin.
	 */
⋮----
isEligible( item: PostWithPermissions )
⋮----
onClick=
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/review-drawer.tsx">
import { createPortal, useEffect, useRef, useState } from '@wordpress/element';
import { __, sprintf, _n } from '@wordpress/i18n';
import { Button, Spinner } from '@wordpress/components';
import { closeSmall } from '@wordpress/icons';
⋮----
import {
	useChangeSummary,
	type ChangeSummary,
	type ChangeSummaryCopyChange,
	type ChangeSummaryStructuralChange,
} from './hooks/use-change-summary';
import { useApplyUpdate, type ApplyChoice } from './hooks/use-apply-update';
⋮----
interface Props {
	postId: number | null;
	emailTitle: string;
	isOpen: boolean;
	onOpenChange: ( open: boolean ) => void;
}
⋮----
type ChoiceMap = Record< string, 'keep_yours' | 'use_core' >;
type AutoTag = 'apply_core' | 'keep_yours';
⋮----
function pathKey( path: Array< number | string > ): string
⋮----
const SectionDot = ( { tone }: { tone: 'warning' | 'brand' } ) => (
	<span
		aria-hidden="true"
		className={ `woocommerce-review-drawer__dot woocommerce-review-drawer__dot--${ tone }` }
	/>
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/review-update-plugin.tsx">
import { useDispatch, useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
⋮----
import { ReviewDrawer } from './review-drawer';
import { STORE_NAME } from './store';
⋮----
function extractTitle( post:
⋮----
/**
 * Mounts the review drawer into the WooCommerce email editor's plugin
 * scope. The drawer's open / close state lives in the
 * `woocommerce/email-editor-integration` store, so any other surface
 * can open it via:
 *
 * ```
 * wp.data.dispatch( 'woocommerce/email-editor-integration' )
 *   .openReviewDrawer();
 * ```
 *
 * RSM-141 will wire the dispatch to the design's floating editor
 * banner. Until then, opening the drawer for testing happens from the
 * browser console using the same dispatch call.
 */
export const ReviewUpdatePlugin = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/save-button.tsx">
import { Button } from '@wordpress/components';
import { useSelect, useDispatch, select as dataSelect } from '@wordpress/data';
import { useEffect, useRef } from '@wordpress/element';
import { addFilter } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n';
import { store as editorStore } from '@wordpress/editor';
import { store as coreDataStore } from '@wordpress/core-data';
import {
	useShortcut,
	store as keyboardShortcutsStore,
	type ShortcutKeyCombination,
} from '@wordpress/keyboard-shortcuts';
⋮----
import { NAME_SPACE } from './constants';
⋮----
function useSaveShortcutTakeover( onSave: () => void, isDisabled: boolean )
⋮----
const onClick = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/sidebar_settings.tsx">
import { select, dispatch } from '@wordpress/data';
import { store as coreDataStore, useEntityProp } from '@wordpress/core-data';
import {
	BaseControl,
	PanelRow,
	TextControl,
	ToggleControl,
	__experimentalText as Text,
} from '@wordpress/components';
import { addFilter } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
import { useState } from '@wordpress/element';
import {
	EmailActionsFill,
	TemplateSelection,
	recordEvent as emailEditorRecordEvent,
} from '@woocommerce/email-editor';
import { registerPlugin } from '@wordpress/plugins';
⋮----
import { NAME_SPACE } from './constants';
import { EmailStatus } from './email-status';
⋮----
type SidebarSettings = {
	RichTextWithButton: React.ComponentType< {
		attributeName: string;
		attributeValue: string;
		updateProperty: ( name: string, value: string | boolean ) => void;
		label: string;
		placeholder: string;
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/store.ts">
import { createReduxStore, register, select } from '@wordpress/data';
import type {
	ReduxStoreConfig,
	StoreDescriptor as GenericStoreDescriptor,
} from '@wordpress/data/build-types/types';
⋮----
interface State {
	isReviewDrawerOpen: boolean;
	dismissedPostIds: Set< number >;
	viewedPostVersionPairs: Set< string >;
}
⋮----
type Action =
	| { type: 'SET_REVIEW_DRAWER_OPEN'; open: boolean }
	| { type: 'DISMISS_UPDATE_BANNER'; postId: number }
	| { type: 'CLEAR_DISMISSED_FOR_POST'; postId: number }
	| { type: 'MARK_UPDATE_BANNER_VIEWED'; postId: number; versionTo: string };
⋮----
const reducer = ( state: State = initialState, action: Action ): State =>
⋮----
export function registerStore(): void
⋮----
interface StoreRegistry {
		[ STORE_NAME ]: GenericStoreDescriptor<
			ReduxStoreConfig< State, typeof actions, typeof selectors >
		>;
	}
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/update-banner-plugin.tsx">
import { createPortal, useEffect, useState } from '@wordpress/element';
⋮----
import { UpdateBanner } from './update-banner';
import { useUpdateBanner } from './hooks/use-update-banner';
⋮----
function resolvePortalTarget(): HTMLElement | null
⋮----
export function UpdateBannerPlugin(): JSX.Element | null
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/email-editor-integration/update-banner.tsx">
import { useEffect } from '@wordpress/element';
import { Button, Tooltip } from '@wordpress/components';
import { __, _n, sprintf } from '@wordpress/i18n';
⋮----
import type { ChangeSummary } from './hooks/use-change-summary';
import type { ApplyState } from './hooks/use-update-banner';
⋮----
interface UpdateBannerProps {
	summary: ChangeSummary | null;
	applyState: ApplyState;
	canApply: boolean;
	canReview: boolean;
	disabledReason: 'dirty' | 'read_only' | 'has_conflicts' | null;
	expanded: boolean;
	onApply: () => void;
	onReview: () => void;
	onDismiss: () => void;
	onAutoDismiss: () => void;
	onToggleExpanded: () => void;
}
⋮----
function tooltipText(
	reason: UpdateBannerProps[ 'disabledReason' ]
): string | null
⋮----
function defaultSubtitle( summary: ChangeSummary | null ): string
⋮----
function MaybeTooltip( {
	tip,
	children,
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/action-buttons/cancel-link.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useInstanceId } from '@wordpress/compose';
⋮----
export default function CancelLink(
⋮----
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/action-buttons/edit-fulfillment-button.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useInstanceId } from '@wordpress/compose';
⋮----
export default function EditFulfillmentButton( {
	onClick,
}: {
onClick: ()
⋮----
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/action-buttons/fulfill-items-button.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useDispatch, select } from '@wordpress/data';
import { useState } from 'react';
import { useInstanceId } from '@wordpress/compose';
⋮----
import { useFulfillmentContext } from '../../context/fulfillment-context';
import { store as FulfillmentStore } from '../../data/store';
import {
	getFulfillmentItems,
	refreshOrderFulfillmentStatus,
} from '../../utils/fulfillment-utils';
import { useFulfillmentDrawerContext } from '../../context/drawer-context';
⋮----
export default function FulfillItemsButton( {
	setError,
}: {
setError: ( message: string | null )
⋮----
const handleFulfillItems = async () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/action-buttons/remove-button.tsx">
import { Button, Modal } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useDispatch, select } from '@wordpress/data';
import { useState } from 'react';
import { useInstanceId } from '@wordpress/compose';
⋮----
import { useFulfillmentContext } from '../../context/fulfillment-context';
import { store as FulfillmentStore } from '../../data/store';
import { useFulfillmentDrawerContext } from '../../context/drawer-context';
import CustomerNotificationBox from '../customer-notification-form';
import { refreshOrderFulfillmentStatus } from '../../utils/fulfillment-utils';
⋮----
const openModal = ()
const closeModal = ()
⋮----
const handleDeleteFulfillment = async () =>
⋮----
const handleRemoveButtonClick = ( event: React.MouseEvent ) =>
⋮----
title=
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/action-buttons/save-draft-button.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useDispatch, select } from '@wordpress/data';
import { useState } from 'react';
import { useInstanceId } from '@wordpress/compose';
⋮----
import { useFulfillmentContext } from '../../context/fulfillment-context';
import { store as FulfillmentStore } from '../../data/store';
import {
	getFulfillmentItems,
	refreshOrderFulfillmentStatus,
} from '../../utils/fulfillment-utils';
import { useFulfillmentDrawerContext } from '../../context/drawer-context';
⋮----
export default function SaveAsDraftButton( {
	setError,
}: {
setError: ( message: string | null )
⋮----
const handleFulfillItems = async () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/action-buttons/update-button.tsx">
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useDispatch, select } from '@wordpress/data';
import { useState } from 'react';
import { useInstanceId } from '@wordpress/compose';
⋮----
import { useFulfillmentContext } from '../../context/fulfillment-context';
import { store as FulfillmentStore } from '../../data/store';
import {
	getFulfillmentItems,
	refreshOrderFulfillmentStatus,
} from '../../utils/fulfillment-utils';
import { useFulfillmentDrawerContext } from '../../context/drawer-context';
⋮----
export default function UpdateButton( {
	setError,
}: {
setError: ( message: string | null )
⋮----
const handleUpdateFulfillment = async () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/customer-notification-form/index.tsx">
import { useEffect, useMemo, useRef } from 'react';
import { TextareaControl, ToggleControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
⋮----
import FulfillmentCard from '../user-interface/fulfillments-card/card';
import { EnvelopeIcon } from '../../utils/icons';
import { useFulfillmentContext } from '../../context/fulfillment-context';
⋮----
export default function CustomerNotificationBox( {
	type = 'fulfill',
}: {
	type: 'fulfill' | 'update' | 'remove';
} )
⋮----
setNotifyCustomer( checked );
⋮----
label=
⋮----
help=
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/fulfillments/fulfillment-editor.tsx">
import { Icon } from '@wordpress/components';
import { useEffect, useState, useRef } from 'react';
import { __, sprintf } from '@wordpress/i18n';
⋮----
import { Fulfillment } from '../../data/types';
import {
	combineItems,
	getItemsFromFulfillment,
	getItemsNotInAnyFulfillment,
} from '../../utils/order-utils';
import { FulfillmentProvider } from '../../context/fulfillment-context';
import ItemSelector from './item-selector';
import EditFulfillmentButton from '../action-buttons/edit-fulfillment-button';
import FulfillItemsButton from '../action-buttons/fulfill-items-button';
import CancelLink from '../action-buttons/cancel-link';
import RemoveButton from '../action-buttons/remove-button';
import UpdateButton from '../action-buttons/update-button';
import CustomerNotificationBox from '../customer-notification-form';
import FulfillmentStatusBadge from './fulfillment-status-badge';
import ErrorLabel from '../user-interface/error-label';
import { useFulfillmentDrawerContext } from '../../context/drawer-context';
import ShipmentViewer from '../shipment-form/shipment-viewer';
import ShipmentForm from '../shipment-form';
import { ShipmentFormProvider } from '../../context/shipment-form-context';
import MetadataViewer from '../metadata-viewer';
import { getFulfillmentLockState } from '../../utils/fulfillment-utils';
import LockLabel from '../user-interface/lock-label';
⋮----
interface FulfillmentEditorProps {
	index: number;
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/fulfillments/fulfillment-line-item.tsx">
import { useContext, useState } from 'react';
import { Button, CheckboxControl, Icon } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import CurrencyFactory, {
	CurrencyContext,
	SymbolPosition,
} from '@woocommerce/currency';
import { decodeEntities } from '@wordpress/html-entities';
import { range } from 'lodash';
⋮----
import { LineItem } from '../../data/types';
⋮----
type FulfillmentItemProps = {
	item: LineItem;
	quantity: number;
	currency: string;
	editMode: boolean;
	toggleItem: ( id: number, index: number, checked: boolean ) => void;
	isChecked: ( id: number, index: number ) => boolean;
	isIndeterminate: ( id: number ) => boolean;
};
⋮----
const getFormattedItemTotal = (
		total: number | string,
		orderCurrencyCode: string
) =>
⋮----
setItemExpanded( ! itemExpanded );
⋮----
checked=
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/fulfillments/fulfillment-status-badge.tsx">
import { __ } from '@wordpress/i18n';
⋮----
import { Fulfillment } from '../../data/types';
⋮----
export default function FulfillmentStatusBadge( {
	fulfillment,
}: {
	fulfillment: Fulfillment;
} )
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/fulfillments/fulfillments-list.tsx">
import FulfillmentEditor from './fulfillment-editor';
import { useFulfillmentDrawerContext } from '../../context/drawer-context';
⋮----
export default function FulfillmentsList()
⋮----
onCollapse=
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/fulfillments/item-selector.tsx">
import { CheckboxControl } from '@wordpress/components';
import { __, _n, sprintf } from '@wordpress/i18n';
import { speak } from '@wordpress/a11y';
⋮----
import FulfillmentLineItem from './fulfillment-line-item';
import { ItemSelection } from '../../utils/order-utils';
import { useFulfillmentContext } from '../../context/fulfillment-context';
⋮----
type ItemSelectorProps = {
	editMode: boolean;
};
⋮----
const clearSelectedItems = () =>
⋮----
const selectAllItems = () =>
⋮----
const handleToggleItem = (
		id: number,
		index: number,
		checked: boolean
) =>
⋮----
const isChecked = ( id: number, index: number ) =>
⋮----
const isIndeterminate = ( id: number ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/fulfillments/new-fulfillment-form.tsx">
import { useEffect, useMemo, useState } from 'react';
import { __ } from '@wordpress/i18n';
import { Icon } from '@wordpress/components';
⋮----
import { LineItem, Order } from '../../data/types';
import { FulfillmentProvider } from '../../context/fulfillment-context';
import SaveAsDraftButton from '../action-buttons/save-draft-button';
import FulfillItemsButton from '../action-buttons/fulfill-items-button';
import { getItemsNotInAnyFulfillment } from '../../utils/order-utils';
import ItemSelector from './item-selector';
import { useFulfillmentDrawerContext } from '../../context/drawer-context';
import ErrorLabel from '../user-interface/error-label';
import { ShipmentFormProvider } from '../../context/shipment-form-context';
import ShipmentForm from '../shipment-form';
import CustomerNotificationBox from '../customer-notification-form';
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/metadata-viewer/index.tsx">
import { __ } from '@wordpress/i18n';
⋮----
import { Fulfillment } from '../../data/types';
import { PostListIcon } from '../../utils/icons';
import FulfillmentCard from '../user-interface/fulfillments-card/card';
import MetaList from '../user-interface/meta-list/meta-list';
⋮----
interface MetadataViewerProps {
	fulfillment: Fulfillment;
}
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/shipment-form/index.tsx">
import { __ } from '@wordpress/i18n';
import { CheckboxControl } from '@wordpress/components';
⋮----
import ShipmentTrackingNumberForm from './shipment-tracking-number-form';
import ShipmentManualEntryForm from './shipment-manual-entry-form';
import { TruckIcon } from '../../utils/icons';
import FulfillmentCard from '../user-interface/fulfillments-card/card';
⋮----
import {
	SHIPMENT_OPTION_MANUAL_ENTRY,
	SHIPMENT_OPTION_NO_INFO,
	SHIPMENT_OPTION_TRACKING_NUMBER,
} from '../../data/constants';
import { useShipmentFormContext } from '../../context/shipment-form-context';
⋮----
label=
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/shipment-form/shipment-manual-entry-form.tsx">
import { ComboboxControl, TextControl } from '@wordpress/components';
import { ComboboxControlOption } from '@wordpress/components/build-types/combobox-control/types';
import { __ } from '@wordpress/i18n';
⋮----
import { useShipmentFormContext } from '../../context/shipment-form-context';
import ShipmentProviders from '../../data/shipment-providers';
import { SearchIcon, TruckIcon } from '../../utils/icons';
⋮----
⋮----
label=
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/shipment-form/shipment-tracking-number-form.tsx">
import { Button, ExternalLink, Flex, TextControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useEffect, useRef, useState } from 'react';
import { useInstanceId } from '@wordpress/compose';
import { isEmpty } from 'lodash';
import apiFetch from '@wordpress/api-fetch';
import { speak } from '@wordpress/a11y';
import { addQueryArgs } from '@wordpress/url';
⋮----
import { useShipmentFormContext } from '../../context/shipment-form-context';
import ErrorLabel from '../user-interface/error-label';
import { EditIcon, TruckIcon } from '../../utils/icons';
import { findShipmentProviderName } from '../../utils/fulfillment-utils';
import ShipmentProviders from '../../data/shipment-providers';
import { useFulfillmentContext } from '../../context/fulfillment-context';
import { SHIPMENT_OPTION_MANUAL_ENTRY } from '../../data/constants';
⋮----
interface TrackingNumberParsingPossibility {
	url: string;
	ambiguity_score: number;
}
⋮----
interface TrackingNumberParsingResponse {
	tracking_number: string;
	tracking_url: string;
	shipping_provider: string;
	possibilities?: Record< string, TrackingNumberParsingPossibility >;
}
⋮----
const handleTrackingNumberLookup = async () =>
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/shipment-form/shipment-viewer.tsx">
import { __ } from '@wordpress/i18n';
⋮----
import { useShipmentFormContext } from '../../context/shipment-form-context';
import ShipmentProviders from '../../data/shipment-providers';
import { CopyIcon, TruckIcon } from '../../utils/icons';
import FulfillmentCard from '../user-interface/fulfillments-card/card';
import MetaList from '../user-interface/meta-list/meta-list';
import { findShipmentProviderName } from '../../utils/fulfillment-utils';
import { SHIPMENT_OPTION_NO_INFO } from '../../data/constants';
⋮----
const getShipmentProviderLabel = (
		savedProvider: string,
		savedProviderName: string
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/user-interface/fulfillment-drawer/fulfillment-drawer-body.tsx">
export default function FulfillmentDrawerBody( {
	children,
}: {
	children: React.ReactNode;
} )
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/user-interface/fulfillment-drawer/fulfillment-drawer-header.tsx">
import moment from 'moment';
import { __ } from '@wordpress/i18n';
⋮----
import { useFulfillmentDrawerContext } from '../../../context/drawer-context';
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/user-interface/fulfillment-drawer/fulfillment-drawer.tsx">
import React, { useEffect, useRef } from 'react';
⋮----
import NewFulfillmentForm from '../../fulfillments/new-fulfillment-form';
import { ErrorBoundary } from '~/error-boundary';
import FulfillmentsList from '../../fulfillments/fulfillments-list';
import FulfillmentsDrawerHeader from './fulfillment-drawer-header';
import { FulfillmentDrawerProvider } from '../../../context/drawer-context';
⋮----
import FulfillmentDrawerBody from './fulfillment-drawer-body';
⋮----
interface Props {
	isOpen: boolean;
	hasBackdrop?: boolean;
	onClose: () => void;
	orderId: number | null;
}
⋮----
const handleKeyDown = ( event: KeyboardEvent ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/user-interface/fulfillments-card/card.tsx">
import { Button, Icon } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import React, { ReactNode, useState } from 'react';
⋮----
const handleToggle = ()
const handleKeyUp = ( e: React.KeyboardEvent ) =>
⋮----
isOpen
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/user-interface/meta-list/meta-list.tsx">
import { __ } from '@wordpress/i18n';
import { isEmpty } from 'lodash';
⋮----
return <>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/user-interface/error-label.tsx">
import { useLayoutEffect, useRef } from 'react';
⋮----
export default function ErrorLabel(
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/components/user-interface/lock-label.tsx">
import { __ } from '@wordpress/i18n';
⋮----
export default function LockLabel(
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/context/drawer-context.tsx">
import React, { createContext, useLayoutEffect, useState } from 'react';
import { useSelect } from '@wordpress/data';
import { isEqual } from 'lodash';
⋮----
import { Fulfillment, Order, Refund } from '../data/types';
import { store as FulfillmentsStore } from '../data/store';
import { getItemsNotInAnyFulfillment } from '../utils/order-utils';
⋮----
interface FulfillmentDrawerContextProps {
	fulfillments: Fulfillment[];
	setFulfillments: ( fulfillments: Fulfillment[] ) => void;
	order: Order | null;
	setOrder: ( order: Order | null ) => void;
	refunds: Refund[];
	setRefunds: ( refunds: Refund[] ) => void;
	openSection: string;
	setOpenSection: ( section: string ) => void;
	isEditing: boolean;
	setIsEditing: ( isEditing: boolean ) => void;
}
⋮----
export const useFulfillmentDrawerContext = () =>
⋮----
export const FulfillmentDrawerProvider = ( {
	orderId,
	children,
}: {
	orderId: number | null;
	children: React.ReactNode;
} ) =>
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/context/fulfillment-context.tsx">
import React, { createContext, useEffect, useMemo, useState } from 'react';
⋮----
import { Fulfillment, Order } from '../data/types';
import { ItemSelection } from '../utils/order-utils';
import { useShipmentFormContext } from './shipment-form-context';
import {
	ITEMS_META_KEY,
	PROVIDER_NAME_META_KEY,
	SHIPMENT_OPTION_NO_INFO,
	SHIPMENT_PROVIDER_META_KEY,
	SHIPPING_OPTION_META_KEY,
	TRACKING_NUMBER_META_KEY,
	TRACKING_URL_META_KEY,
	WC_ORDER_CLASS,
} from '../data/constants';
⋮----
interface FulfillmentContextProps {
	order: Order | null;
	fulfillment: Fulfillment | null;
	setFulfillment: ( fulfillment: Fulfillment | null ) => void;
	selectedItems: ItemSelection[];
	setSelectedItems: ( items: ItemSelection[] ) => void;
	notifyCustomer: boolean;
	setNotifyCustomer: ( notifyCustomer: boolean ) => void;
	customerNote: string;
	setCustomerNote: ( customerNote: string ) => void;
}
⋮----
export const useFulfillmentContext = () =>
⋮----
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/context/shipment-form-context.tsx">
import React, { createContext, useMemo } from 'react';
⋮----
import { Fulfillment } from '../data/types';
import { getFulfillmentMeta } from '../utils/fulfillment-utils';
import {
	PROVIDER_NAME_META_KEY,
	SHIPMENT_OPTION_DEFAULT,
	SHIPMENT_PROVIDER_META_KEY,
	SHIPPING_OPTION_META_KEY,
	TRACKING_NUMBER_META_KEY,
	TRACKING_URL_META_KEY,
} from '../data/constants';
⋮----
interface ShipmentFormContextProps {
	selectedOption: string;
	setSelectedOption: ( selectedOption: string ) => void;
	trackingNumber: string;
	setTrackingNumber: ( trackingNumber: string ) => void;
	shipmentProvider: string;
	setShipmentProvider: ( shipmentProvider: string ) => void;
	trackingUrl: string;
	setTrackingUrl: ( trackingUrl: string ) => void;
	providerName: string;
	setProviderName: ( providerName: string ) => void;
}
⋮----
export const useShipmentFormContext = () =>
⋮----
export const ShipmentFormProvider = ( {
	fulfillment = null,
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/data/constants.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/data/shipment-providers.tsx">
import { __ } from '@wordpress/i18n';
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/data/store.ts">
import apiFetch from '@wordpress/api-fetch';
import { createReduxStore, register } from '@wordpress/data';
import { addQueryArgs } from '@wordpress/url';
⋮----
import { Order, Fulfillment, Refund } from './types';
⋮----
const getFulfillmentErrorMessage = (
	error: unknown,
	defaultMessage: string
): string =>
⋮----
interface OrderState {
	order: Order | null;
	refunds: Refund[];
	fulfillments: Fulfillment[];
	loading: boolean;
	error: string | null;
}
⋮----
const getInitialOrderState = (): OrderState => (
⋮----
setOrder( orderId: number, order: Order )
setRefunds( orderId: number, refunds: Refund[] )
setLoading( orderId: number, isLoading: boolean )
setError( orderId: number, error: string | null )
setFulfillments( orderId: number, fulfillments: Fulfillment[] )
setFulfillment(
		orderId: number,
		fulfillmentId: number,
		fulfillment: Fulfillment
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/data/types.ts">
export interface Order {
	id: number;
	parent_id: number;
	status: string;
	currency: string;
	version: string;
	prices_include_tax: boolean;
	date_created: Date;
	date_modified: Date;
	discount_total: string;
	discount_tax: string;
	shipping_total: string;
	shipping_tax: string;
	cart_tax: string;
	total: string;
	total_tax: string;
	customer_id: number;
	order_key: string;
	billing: Ing;
	shipping: Ing;
	payment_method: string;
	payment_method_title: string;
	transaction_id: string;
	customer_ip_address: string;
	customer_user_agent: string;
	created_via: string;
	customer_note: string;
	date_completed: null;
	date_paid: Date;
	cart_hash: string;
... (148 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/test-helper/global-mock.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/utils/fulfillment-utils.ts">
import { dispatch, resolveSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
⋮----
import ShipmentProviders from '../data/shipment-providers';
import { Fulfillment, FulfillmentItem, Order } from '../data/types';
import { store as FulfillmentStore } from '../data/store';
⋮----
export function getFulfillmentMeta< T >(
	fulfillment: Fulfillment | null,
	metaKey: string,
	defaultValue: T
)
⋮----
export function getFulfillmentItems(
	fulfillment: Fulfillment
): Array< FulfillmentItem >
⋮----
export async function refreshOrderFulfillmentStatus( orderId: number )
⋮----
export function getFulfillmentLockState( fulfillment: Fulfillment ):
⋮----
export function findShipmentProviderName( key: string )
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/utils/icons.tsx">
import { Button } from '@wordpress/components';
import { useEffect, useRef, useState } from 'react';
⋮----
export const SearchIcon = () => (
	<svg
		width="12"
		height="12"
		viewBox="0 0 12 12"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<path
			d="M6.75 0.75C4.275 0.75 2.25 2.775 2.25 5.25C2.25 6.3 2.625 7.275 3.225 8.025L0.375 10.875L1.2 11.7L4.05 8.85C4.8 9.45 5.775 9.825 6.825 9.825C9.3 9.825 11.325 7.8 11.325 5.325C11.325 2.85 9.225 0.75 6.75 0.75ZM6.75 8.625C4.875 8.625 3.375 7.125 3.375 5.25C3.375 3.375 4.875 1.875 6.75 1.875C8.625 1.875 10.125 3.375 10.125 5.25C10.125 7.125 8.625 8.625 6.75 8.625Z"
			fill="#1E1E1E"
		/>
	</svg>
);
⋮----
export const TruckIcon = () => (
	<svg
		width="18"
		height="14"
		viewBox="0 0 18 14"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
	>
		<path
			fillRule="evenodd"
			clipRule="evenodd"
			d="M0.5 1.75C0.5 0.783502 1.2835 0 2.25 0L12.5 0V3H14.5607L18 6.43934V8.75C18 9.7165 17.2165 10.5 16.25 10.5H16.2377C16.2458 10.5822 16.25 10.6656 16.25 10.75C16.25 12.1307 15.1307 13.25 13.75 13.25C12.3693 13.25 11.25 12.1307 11.25 10.75C11.25 10.6656 11.2542 10.5822 11.2623 10.5H7.23766C7.24582 10.5822 7.25 10.6656 7.25 10.75C7.25 12.1307 6.13071 13.25 4.75 13.25C3.36929 13.25 2.25 12.1307 2.25 10.75C2.25 10.6656 2.25418 10.5822 2.26234 10.5H0.5V1.75ZM11 9V1.5H2.25C2.11193 1.5 2 1.61193 2 1.75V9H2.96464C3.41837 8.53716 4.05065 8.25 4.75 8.25C5.44935 8.25 6.08163 8.53716 6.53536 9H11ZM15.5354 9H16.25C16.3881 9 16.5 8.88807 16.5 8.75V7.06066L13.9393 4.5H12.5V8.58446C12.8677 8.37174 13.2946 8.25 13.75 8.25C14.4493 8.25 15.0816 8.53716 15.5354 9ZM3.7815 10.5C3.76094 10.5799 3.75 10.6637 3.75 10.75C3.75 11.3023 4.19772 11.75 4.75 11.75C5.30228 11.75 5.75 11.3023 5.75 10.75C5.75 10.6637 5.73906 10.5799 5.7185 10.5C5.60749 10.0687 5.21596 9.75 4.75 9.75C4.28404 9.75 3.89251 10.0687 3.7815 10.5ZM12.7815 10.5C12.7609 10.5799 12.75 10.6637 12.75 10.75C12.75 11.3023 13.1977 11.75 13.75 11.75C14.3023 11.75 14.75 11.3023 14.75 10.75C14.75 10.6637 14.7391 10.5799 14.7185 10.5C14.7144 10.4841 14.7099 10.4683 14.705 10.4526C14.5784 10.0456 14.1987 9.75 13.75 9.75C13.284 9.75 12.8925 10.0687 12.7815 10.5Z"
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/utils/order-utils.ts">
import { range } from 'lodash';
⋮----
import { Fulfillment, LineItem, Order, Refund } from '../data/types';
import { getFulfillmentItems } from './fulfillment-utils';
⋮----
export interface ItemSelection {
	item_id: number;
	item: LineItem;
	selection: { index: number; checked: boolean }[];
}
⋮----
export const getItemsFromOrder = ( order: Order ): ItemSelection[] =>
⋮----
export const getItemsFromFulfillment = (
	order: Order,
	fulfillment: Fulfillment
): ItemSelection[] =>
⋮----
export const getOrderItemsCount = ( order: Order ): number =>
⋮----
export const combineItems = (
	items1: ItemSelection[],
	items2: ItemSelection[]
): ItemSelection[] =>
⋮----
const reduceItems = (
	items: ItemSelection[],
	itemsToReduce: ItemSelection[]
): ItemSelection[] =>
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/global.d.ts">
interface ShipmentProvider {
		label: string;
		icon: string | null;
		value: string;
		url: string;
	}
⋮----
interface FulfillmentStatusProps {
		label: string;
		is_fulfilled: boolean;
		background_color: string;
		text_color: string;
	}
⋮----
interface Window {
		wcFulfillmentSettings: {
			providers: Record< string, ShipmentProvider >;
			currency_symbols: Record< string, string >;
			fulfillment_statuses: Record< string, FulfillmentStatusProps >;
			order_fulfillment_statuses: Record<
				string,
				FulfillmentStatusProps
			>;
		};
	}
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/fulfillments/index.tsx">
import React, { useCallback, useLayoutEffect, useState } from 'react';
import { createRoot } from '@wordpress/element';
import { getQuery } from '@woocommerce/navigation';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import FulfillmentDrawer from './components/user-interface/fulfillment-drawer/fulfillment-drawer';
⋮----
function FulfillmentsController()
⋮----
const handleClick = ( e: Event ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/marketing-coupons/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/marketplace-orders-promo/index.tsx">
import { createRoot } from '@wordpress/element';
⋮----
import PromoCard from '~/marketplace/components/promo-card/promo-card';
import { Promotion } from '~/marketplace/components/promotions/types';
⋮----
interface Window {
		wcOrdersPromo?: {
			id?: string;
			promotion: Promotion;
			order_count?: number;
			dismiss_url?: string;
			dismiss_nonce?: string;
		};
	}
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/onboarding-homepage-notice/index.js">
const saveStarted = () =>
⋮----
const saveCompleted = () =>
⋮----
const onboardingHomepageNotice = () =>
⋮----
onClick: () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/onboarding-load-sample-products-notice/index.ts">
import { __ } from '@wordpress/i18n';
import { dispatch } from '@wordpress/data';
import domReady from '@wordpress/dom-ready';
import { getAdminLink } from '@woocommerce/settings';
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/onboarding-product-import-notice/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/onboarding-tax-notice/index.js">
const saveCompleted = ( saveButton ) =>
⋮----
const showTaxCompletionNotice = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/order-milestone-easter-egg/index.js">
function pinataPxWidth()
⋮----
function applyLayout()
⋮----
function pinataCentre()
⋮----
async function loadPinata( variantKey )
⋮----
function startBlink()
⋮----
function animTo( from, to, dur, done )
function doBlink()
⋮----
function updatePupil()
⋮----
function update()
⋮----
function applyRotation()
⋮----
function sizeCanvasHiDPI( canvas )
⋮----
function sizeConfetti()
⋮----
async function loadConfettiShapes()
⋮----
function filterShapes()
⋮----
function rebuildColumns()
⋮----
function colOf( x )
... (45 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/order-tracking/exit-order-page.ts">
import { addCustomerEffortScoreExitPageListener } from '@woocommerce/customer-effort-score';
⋮----
import { staticFormDataToObject } from '~/utils/static-form-helper';
⋮----
type FormElements = {
	post?: HTMLFormElement;
	order?: HTMLFormElement;
} & HTMLCollectionOf< HTMLFormElement >;
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/order-tracking/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/payment-method-promotions/index.tsx">
import { createRoot } from '@wordpress/element';
⋮----
import { PaymentPromotionRow } from './payment-promotion-row';
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/payment-method-promotions/payment-promotion-row.tsx">
import { Button } from '@wordpress/components';
import { EllipsisMenu, Link } from '@woocommerce/components';
import { useState, useEffect } from '@wordpress/element';
import {
	pluginsStore,
	paymentGatewaysStore,
	paymentSettingsStore,
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { useDispatch, useSelect } from '@wordpress/data';
import { sanitizeHTML } from '@woocommerce/sanitize';
import { __ } from '@wordpress/i18n';
import { WooPaymentsMethodsLogos } from '@woocommerce/onboarding';
⋮----
function sanitizeHTMLForReact( html: string )
⋮----
type PaymentPromotionRowProps = {
	paymentMethod: {
		gatewayId: string;
		pluginSlug: string;
		url: string;
	};
	title?: string;
	columns: {
		className: string;
		html: string;
		width: string | number | undefined;
	}[];
	subTitleContent?: string;
};
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/print-shipping-label-banner/dismiss-modal/index.js">
export class DismissModal extends Component
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/print-shipping-label-banner/setup-notice/index.js">
export default function SetupNotice( {
	isSetupError,
	errorReason,
	infoMessage,
} )
⋮----
const getErrorMessage = ( errorType ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/print-shipping-label-banner/shipping-banner/index.js">
export class ShippingBanner extends Component
⋮----
componentDidMount()
⋮----
async installAndActivatePlugins( pluginSlug )
⋮----
generateMetaBoxHtml( nodeId, title, args )
⋮----
loadWcsAssets(
⋮----
openWcsModal()
⋮----
render()
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/print-shipping-label-banner/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/print-shipping-label-banner/wcs-api.js">
export function acceptWcsTos()
⋮----
export function getWcsAssets()
⋮----
export function getWcsLabelPurchaseConfigs( orderId )
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/product-import-tracking/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/product-import-tracking/product-import-tracking.ts">
import {
	addExitPage,
	removeExitPage,
} from '@woocommerce/customer-effort-score';
import { getQuery } from '@woocommerce/navigation';
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/product-tour/index.tsx">
import { createRoot } from '@wordpress/element';
⋮----
import { ProductTour } from '../../guided-tours/add-product-tour/index';
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/product-tracking/global.d.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/product-tracking/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/product-tracking/product-edit.ts">
import { recordEvent } from '@woocommerce/tracks';
⋮----
import {
	addExitPageListener,
	getProductData,
	initProductScreenTracks,
} from './shared';
⋮----
const initTracks = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/product-tracking/product-new.ts">
import { recordEvent } from '@woocommerce/tracks';
⋮----
import { addExitPageListener, initProductScreenTracks } from './shared';
⋮----
const initTracks = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/product-tracking/products-list.ts">
import { recordEvent } from '@woocommerce/tracks';
⋮----
const initTracks = () =>
⋮----
const hasValue = ( selector: string ) =>
⋮----
interface actionsInterface {
				[ key: string ]: string;
			}
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/product-tracking/shared.ts">
import { addCustomerEffortScoreExitPageListener } from '@woocommerce/customer-effort-score';
import { recordEvent } from '@woocommerce/tracks';
⋮----
import {
	attachEventListenerToParentForChildren,
	waitUntilElementIsPresent,
} from './utils';
⋮----
const isElementVisible = ( element: HTMLElement )
⋮----
const getProductType = () =>
⋮----
type ProductTypeOption = {
	id: string | null;
	isEnabled: boolean;
};
⋮----
function getProductTypeOptions()
⋮----
function getProductTypeOptionsString(
	productTypeOptions: ProductTypeOption[]
)
⋮----
export const getProductData = () =>
⋮----
const getPublishDate = ( prefix = '' ) =>
⋮----
/**
 * Get the data from the publishing widget.
 *
... (53 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/product-tracking/utils.ts">
export function attachEventListenerToParentForChildren(
	parentQuery: string,
	children: Array< {
		eventName: 'click' | 'change';
		childQuery: string;
callback: ( clickedElement: Element )
⋮----
const eventListener = ( event: Event ) =>
⋮----
export function waitUntilElementIsPresent(
	query: string,
	func: () => void,
	tries = 0
)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/settings-embed/index.tsx">
import { createRoot } from '@wordpress/element';
⋮----
import { isFeatureEnabled } from '~/utils/features';
import {
	SettingsPaymentsBacsWrapper,
	SettingsPaymentsChequeWrapper,
	SettingsPaymentsCodWrapper,
	SettingsPaymentsMainWrapper,
	SettingsPaymentsOfflineWrapper,
	SettingsPaymentsWooPaymentsWrapper,
} from '~/settings-payments';
⋮----
import { possiblyRenderSettingsSlots } from '~/settings/settings-slots';
import { registerTaxSettingsConflictErrorFill } from '~/settings/conflict-error-slotfill';
import { registerPaymentsSettingsBannerFill } from '~/payments/payments-settings-banner-slotfill';
import { registerSiteVisibilitySlotFill } from '~/launch-your-store';
import { registerBlueprintSlotfill } from '~/blueprint';
import { registerSettingsEmailColorPaletteFill } from '~/settings-email/settings-email-color-palette-slotfill';
import { registerSettingsEmailImageUrlFill } from '~/settings-email/settings-email-image-url-slotfill';
import { registerSettingsEmailPreviewFill } from '~/settings-email/settings-email-preview-slotfill';
import { registerSettingsEmailFeedbackFill } from '~/settings-email/settings-email-feedback-slotfill';
import { registerSettingsEmailListingFill } from '~/settings-email/settings-email-listing-slotfill';
import { registerSettingsUIScreens } from '~/settings/settings-ui-registry';
⋮----
const renderPaymentsSettings = () =>
⋮----
const registerSlotFills = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/settings-tracking/exit-setting-page.ts">
import { addCustomerEffortScoreExitPageListener } from '@woocommerce/customer-effort-score';
⋮----
import { staticFormDataToObject } from '~/utils/static-form-helper';
⋮----
type FormElements = {
	mainform?: HTMLFormElement;
} & HTMLCollectionOf< HTMLFormElement >;
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/settings-tracking/index.ts">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/settings-tracking/marketplace-link-tracking.ts">
import { recordEvent } from '@woocommerce/tracks';
⋮----
const initMarketplaceLinkTracking = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/shipping-settings-region-picker/currency-context.js">
export const ShippingCurrencyContext = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/shipping-settings-region-picker/index.js">
const ShippingApp = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/shipping-settings-region-picker/region-picker.js">
export const RegionPicker = (
⋮----
const onChange = ( value ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/shipping-settings-region-picker/utils.js">
export const recursivelyTransformLabels = ( node, transform ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/tags-tracking/index.js">
function actionButtonEventHandler( event )
⋮----
function addActionButtonListeners()
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/variable-product-tour/index.tsx">
import { createRoot } from '@wordpress/element';
⋮----
import { VariableProductTour } from '../../guided-tours/variable-product-tour';
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/visual-attribute-picker/image-field.tsx">
import { createRoot, useEffect, useRef, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
⋮----
import {
	COLOR_INPUT_SELECTOR,
	clearSiblingVisualInput,
	clearVisualInput,
	IMAGE_INPUT_SELECTOR,
	observeInputValueChanges,
} from './utils';
⋮----
const getInitialImageId = ( input: HTMLInputElement ) =>
⋮----
type MediaAttachment = {
	id: number;
	url: string;
	sizes?: {
		thumbnail?: {
			url: string;
		};
	};
};
⋮----
// Listen to changes in the input field. Because WP core uses jQuery, we
// can't listen to native `change` and `input` events. Instead, we override
⋮----
const setImageValue = ( attachment: MediaAttachment ) =>
⋮----
const openMediaLibrary = () =>
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/visual-attribute-picker/index.tsx">
import { ColorPicker, Popover } from '@wordpress/components';
import { createRoot, useEffect, useRef, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
⋮----
import { mountAllImagePickers } from './image-field';
import { mountAllVisualTypeSwitchers } from './type-switcher';
import {
	COLOR_INPUT_SELECTOR,
	IMAGE_INPUT_SELECTOR,
	clearSiblingVisualInput,
	observeInputValueChanges,
} from './utils';
⋮----
const normalizeColor = ( value: string ) =>
⋮----
const getInitialColor = ( input: HTMLInputElement ) =>
⋮----
// Listen to changes in the input field. Because WP core uses jQuery, we
// can't listen to native `change` and `input` events. Instead, we override
⋮----
const handleColorSelection = ( value: string ) =>
⋮----
const clearColor = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/visual-attribute-picker/type-switcher.tsx">
import { IMAGE_INPUT_SELECTOR } from './utils';
⋮----
const hasStoredImage = ( input: HTMLInputElement ) =>
⋮----
const setVisualFieldVisibility = (
	container: ParentNode,
	visualType: typeof VISUAL_TYPE_COLOR | typeof VISUAL_TYPE_IMAGE
) =>
⋮----
const mountVisualTypeSwitcher = ( visualTypeSwitcher: HTMLElement ) =>
⋮----
export const mountAllVisualTypeSwitchers = (
	context: ParentNode = document
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/visual-attribute-picker/utils.ts">
type InputValueChangeHandler = ( nextValue: string ) => void;
⋮----
export const observeInputValueChanges = (
	input: HTMLInputElement,
	onValueChange: InputValueChangeHandler
) =>
⋮----
set( nextValue: string )
⋮----
export const getSiblingVisualInput = (
	input: HTMLInputElement,
	selector: string
): HTMLInputElement | null =>
⋮----
export const clearVisualInput = ( input: HTMLInputElement ) =>
⋮----
export const clearSiblingVisualInput = (
	input: HTMLInputElement,
	selector: string
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/wc-addons-tour/index.tsx">
import { createRoot } from '@wordpress/element';
⋮----
import WCAddonsTour from '../../guided-tours/wc-addons-tour/index';
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/wcsettings-deprecation/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/woo-connect-notice/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/woo-enable-autorenew/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/woo-plugin-update-connect-notice/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/woo-product-usage-notice/actions.js">
const request = (
⋮----
export const dismissRequest = (
	{ dismissAction, productId, dismissNonce },
	callback
) =>
⋮----
export const remindLaterRequest = (
	{ remindLaterAction, productId, remindLaterNonce },
	callback
) =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/woo-product-usage-notice/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/woo-product-usage-notice/modal.js">
export default function ProductUsageNoticeModal( {
	renewUrl,
	subscribeUrl,
	productId,
	productName,
	productRegularPrice,
	dismissAction,
	dismissNonce,
	remindLaterAction,
	remindLaterNonce,
	subscriptionState,
	screenId,
} )
⋮----
const dismiss = () =>
const remindLater = () =>
const renew = () =>
const subscribe = () =>
⋮----
const renderBenefits = () =>
⋮----
const renderPrimaryCard = () =>
⋮----
const renderSecondaryCard = () =>
</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/woo-purchase-subscription/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/woo-renew-subscription/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/woo-subscriptions-notice/index.js">

</file>

<file path="plugins/woocommerce/client/admin/client/wp-admin-scripts/README.md">
# WP Admin Scripts

Scripts located in this directory are meant to be loaded on wp-admin pages outside the context of WooCommerce Admin, such as the post editor. 

Each subdirectory of this directory is automatically added as an entrypoint in the [webpack build script](../../../../plugins/woocommerce-admin/webpack.config.js#L71) of WooCommerce Admin. When they are built, each one results in a pair of `<subdirectory-name>.asset.php` and `<subdirectory-name>.js` file in the `build\wp-admin-scripts\` path, but they will not be automatically loaded on every PHP page.

The `<subdirectory-name>.asset.php` file contains a list of automatically detected dependencies generated by the Dependency Extraction Webpack Plugin, so JS dependencies are not required to be manually enqueued as long as the `WCAdminAssets::register_script()` function is used to enqueue the script.

As an example, the `payment-method-promotions` wp-admin-scripts has generated `payment-method-promotions.asset.php` with the contents below:

`<?php return array('dependencies' => array('react', 'wc-components', 'wc-experimental', 'wc-settings', 'wc-store-data', 'wc-tracks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => 'e64b1e69145febe07734');`

And is registered as a script like so: [`plugins/woocommerce/src/Internal/Admin/WCPayPromotion/Init.php`](../../../../plugins/woocommerce/src/Internal/Admin/WCPayPromotion/Init.php#L179),

`WCAdminAssets::register_script( 'wp-admin-scripts', 'payment-method-promotions', true );`
</file>

<file path="plugins/woocommerce/client/admin/client/embed.tsx">
import { initRemoteLogging } from './lib/init-remote-logging';
⋮----
import { renderCustomerEffortScoreTracks } from './shared';
import { getAdminSetting } from '~/utils/admin-settings';
import { renderEmbeddedLayout } from './embedded-body-layout';
</file>

<file path="plugins/woocommerce/client/admin/client/index.tsx">
import { createRoot } from '@wordpress/element';
import {
	withCurrentUserHydration,
	withSettingsHydration,
} from '@woocommerce/data';
⋮----
import { initRemoteLogging } from './lib/init-remote-logging';
⋮----
import { renderCustomerEffortScoreTracks } from './shared';
import { Layout } from './layout';
import { getAdminSetting } from '~/utils/admin-settings';
import { deriveWpAdminBackgroundColours } from './utils/derive-wp-admin-background-colours';
import { ErrorBoundary } from './error-boundary';
</file>

<file path="plugins/woocommerce/client/admin/client/jest.config.js">

</file>

<file path="plugins/woocommerce/client/admin/client/shared.tsx">
import { CustomerEffortScoreTracksContainer } from '@woocommerce/customer-effort-score';
import { createRoot } from '@wordpress/element';
import debugFactory from 'debug';
⋮----
export const renderCustomerEffortScoreTracks = ( root: HTMLElement ) =>
</file>

<file path="plugins/woocommerce/client/admin/client/xstate.js">
async function enableXStateV4Inspect()
⋮----
async function enableXStateV5Inspect()
⋮----
export const useXStateInspect = ( machineVersion ) =>
</file>

<file path="plugins/woocommerce/client/admin/config/core.json">
{
	"features": {
		"experimental-blocks": false,
		"minified-js": false,
		"settings-ui": false,
		"store-alerts": true,
		"rest-api-v4": false,
		"order-detail-redesign": false
	}
}
</file>

<file path="plugins/woocommerce/client/admin/config/development.json">
{
	"features": {
		"experimental-blocks": true,
		"minified-js": true,
		"settings-ui": false,
		"store-alerts": true,
		"rest-api-v4": false,
		"order-detail-redesign": false
	}
}
</file>

<file path="plugins/woocommerce/client/admin/docs/examples/extensions/add-abbreviated-notification/js/index.js">
const MyAbbreviatedNotification = () =>
</file>

<file path="plugins/woocommerce/client/admin/docs/examples/extensions/add-abbreviated-notification/woocommerce-admin-add-abbreviated-notification-example.php">
function add_abbreviated_notification_register_script() {
⋮----
! \Automattic\WooCommerce\Admin\PageController::is_admin_or_embed_page()
</file>

<file path="plugins/woocommerce/client/admin/docs/examples/extensions/important-admin-notice/js/index.js">

</file>

<file path="plugins/woocommerce/client/admin/docs/examples/extensions/important-admin-notice/woocommerce-admin-important-admin-notice-example.php">
function wc_admin_important_notice_register_script() {
⋮----
! \Automattic\WooCommerce\Admin\PageController::is_admin_page() &&
! \Automattic\WooCommerce\Admin\PageController::is_embed_page()
⋮----
function wc_admin_add_important_notice() {
</file>

<file path="plugins/woocommerce/client/admin/docs/examples/extensions/simple-inbox-note/js/index.js">

</file>

<file path="plugins/woocommerce/client/admin/docs/examples/extensions/simple-inbox-note/class-simpleinboxnote.php">
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class SimpleInboxNote {
⋮----
public static function is_applicable() {
⋮----
if ( ! self::is_wc_admin_active_in_date_range( 'week-1-4', 5 * DAY_IN_SECONDS ) ) {
⋮----
public static function get_note() {
⋮----
$note->set_title( 'Hello From Inbox Note!' );
⋮----
$note->set_content(
⋮----
$note->set_content_data(
⋮----
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
⋮----
$note->set_source( 'simple-inbox-note-example' );
$note->set_name( self::NOTE_NAME );
⋮----
$note->add_action(
</file>

<file path="plugins/woocommerce/client/admin/docs/examples/extensions/simple-inbox-note/woocommerce-admin-simple-inbox-note-example.php">
function add_note() {
⋮----
SimpleInboxNote::possibly_add_note();
⋮----
function delete_note() {
⋮----
SimpleInboxNote::possibly_delete_note();
</file>

<file path="plugins/woocommerce/client/admin/docs/examples/extensions/examples.config.js">

</file>

<file path="plugins/woocommerce/client/admin/docs/examples/extensions/README.md">
# WooCommerce Admin Extension Examples

Examples for extending WooCommerce Admin

## Directions

Install dependencies, if you haven't already.

```bash
pnpm install
```

Build the example extension by running the pnpm script and passing the example name.


```bash
WC_EXT=<example> pnpm --filter=@woocommerce/admin-library example
```

You should see a new directory in `./woocommerce/plugins/{example} path.` Include the output plugin in your `.wp-env.json` or `.wp-env.override.json` and restart the WordPress instance. WooCommerce will now reflect the changes made by the example extension.

You can make changes to Javascript and PHP files in the example and see changes reflected upon refresh.

## Example Extensions

- `add-report` - Create a "Hello World" report page.
- `add-task` - Create a custom task for the onboarding task list.

> **Note:** Some of the previous examples have been moved to the [@woocommerce/create-woo-extension](https://www.npmjs.com/package/@woocommerce/create-woo-extension) package as extension variants for easier scaffolding of new extensions. See the [Create Woo Extension README](../../../../../../../packages/js/create-woo-extension/README.md) for more information.
</file>

<file path="plugins/woocommerce/client/admin/docs/examples/activity-panel-inbox.md">
# Activity Panel Inbox

Right now, installing and activating WooCommerce and a few extensions quickly results in a cascade of notices vying for the store administrator’s attention (and pushing whatever wp-admin content they were trying to get to on a page down, way down.)

As part of the Dashboard and Analytics improvements coming to WooCommerce, we’re going to do something a bit dramatic to try and clean up this notice-palooza.

First, we’re splitting up notices into two broad categories.

## Category 1: Store Alerts

The first category is what we’re calling “Store Alerts” - similar to the notices you have today, these notices are present at the top of administration pages and will look something like this:

![Store Alerts](images/activity-panel-store-alerts.png)

But unlike today’s notices, this part of the UI will be reserved for “priority” messages to the administrator - things like version and security updates and critical errors.  What sort of errors are “critical errors”? Well, things like a payment gateway that has stopped working because its connection is down, or when the store is set for physical product support but no shipping methods are defined.

## Category 2: Activity Panel Inbox

The second category is what we’re focusing on in this example - and what we expect the vast majority of extension developers will want to extend - we call it the “Activity Panel Inbox.” It will look something like this:

![Activity Panel Inbox](images/activity-panel-inbox.png)

This section is dedicated to informational content coming from multiple sources such as WooCommerce core, WooCommerce.com Subscription management, extensions activity and store achievements. This section was also envisioned to display more insightful content in the future, e.g. content that could help with the day to day tasks of managing and optimizing a store.

Each notice or “note” has a type represented by an icon (Gridicon), a title, content, a timestamp and one or two actions (action title + link).

### Inbox Design Constraints and Best Practices

Extensions can add their own notes via the data stores we’ll be covering below, but first: some constraints.

... (217 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/examples/README.md">
Examples
==========

This folder contains examples of extending various parts of WooCommerce Admin.
</file>

<file path="plugins/woocommerce/client/admin/docs/features/core-profiler.md">
# Core Profiler

The Core Profiler feature is a modernized and simplified new user setup experience for WooCommerce core. It is the first thing a new merchant will see upon installation of WooCommerce. 

It requests the minimum amount of information from a merchant to get their store up and running, and suggests some optional extensions that may fulfil common needs for new stores.

There are 4 pages in the Core Profiler:

1. Introduction & Data sharing opt-in
2. User Profile - Some questions determining the user's entry point to the WooCommerce setup
3. Business Information - Store Details and Location
4. Extensions - Optional extensions that may be useful to the merchant

If the merchant chooses to install any extensions that require Jetpack, they will then be redirected to WordPress.com to login to Jetpack after the extensions page. Upon completion of that, they will be returned back to the WooCommerce Admin homescreen which contains the Task List. The Task List will provide next steps for the merchant to continue with their store setup.

## Development

The Core Profiler is gated behind the `core-profiler` feature flag, but is enabled by default. 

This feature is the first feature in WooCommerce to use XState for state management, and so naming and organisational conventions will be developed as the team's experience with XState grows.

Refer to the [XState Dev Tooling](xstate.md) documentation for information on how to use the XState visualizer to debug the state machines.

The state machine for the Core Profiler is centrally located at `./client/core-profiler/index.tsx`, and is responsible for managing the state of the entire feature. It is responsible for rendering the correct page based on the current state, handling events that are triggered by the user, triggering side effects such as API calls and handling the responses. It also handles updating the browser URL state as well as responding to changes in it.

While working on this feature, bear in mind that the state machine should interact with WordPress and WooCommerce via actions and services, and the UI code should not be responsible for any API calls or interaction with WordPress Data Stores. This allows us to easily render the UI pages in isolation, for example use in Storybook. The UI pages should only send events back to the state machine in order to trigger side effects.

## Saving and retrieving data

As of writing, the following options are saved (and retrieved if the user has already completed the Core Profiler):
... (216 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/features/feature-flags.md">
# Feature Flags

Features inside the `woocommerce` repository can be in various states of completeness. To provide a way for improved control over how these features are released in these different environments, `woocommerce` has a system for feature flags.

We currently support the following environments:

| Environment | Description                                                                                                                                                            |
|-------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| development | Development - All features should be enabled in development. These flags are also used in both JS and PHP tests. Ran using `pnpm start`.                                |                              |
| core        | Core - assets/files ready and stable enough. Ran using `pnpm build` & `pnpm pack`.



## Adding a new flag

Flags can be added to the files located in the `config/` directory. Make sure to add a flag for each environment and explicitly set the flag to false.
Please add new feature flags alphabetically so they are easy to find.

## Basic Use - Client

The `window.wcAdminFeatures` constant is a global variable containing the feature flags.

Instances of `window.wcAdminFeatures` are replaced during the webpack build process by using webpack's [define plugin](https://webpack.js.org/plugins/define-plugin/). Using `webpack` for this allows us to eliminate dead code when making minified/production builds (`plugin`, or `core` environments).

To check if a feature is enabled, you can simplify check the boolean value of a feature:

```
{ window.wcAdminFeatures[ 'activity-panels' ] && <ActivityPanel /> }
```

... (20 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/features/fulfillments-hooks.md">
# WooCommerce Order Fulfillments - Complete Hooks Reference

This document provides a comprehensive reference for all action hooks and filter hooks available in the WooCommerce Order Fulfillments system.

## Action Hooks

Action hooks allow you to execute custom code at specific points in the fulfillment lifecycle without modifying the return value.

### Data Lifecycle Actions

#### `woocommerce_fulfillment_after_create`

Fired after a fulfillment is successfully created in the database.

**File:** `src/Admin/Features/Fulfillments/DataStore/FulfillmentsDataStore.php:122`

**Parameters:**

-   `$data` (Fulfillment) - The created fulfillment object

**Purpose:** Allows plugins to perform actions after a fulfillment is created, such as updating order fulfillment status, syncing to external systems, or logging.

```php
add_action( 'woocommerce_fulfillment_after_create', 'log_fulfillment_creation' );

function log_fulfillment_creation( $fulfillment ) {
    error_log( 'Fulfillment created: ' . $fulfillment->get_id() );
}
```

... (726 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/features/fulfillments-rest-api.md">
# WooCommerce Order Fulfillments REST API

This document describes the REST API endpoints for managing order fulfillments in WooCommerce.

## Base URL

All endpoints use the WooCommerce REST API v3 namespace:

```http
/wp-json/wc/v3/orders/{order_id}/fulfillments
```

## Authentication

All endpoints require authentication with `manage_woocommerce` capability for full access, or order ownership for read-only access.

## Endpoints

### 1. Get Order Fulfillments

Retrieve all fulfillments for a specific order.

**Endpoint:** `GET /wp-json/wc/v3/orders/{order_id}/fulfillments`

#### Parameters

| Parameter  | Type    | Required | Description                     |
| ---------- | ------- | -------- | ------------------------------- |
| `order_id` | integer | Yes      | Unique identifier for the order |

... (658 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/features/onboarding-tasks.md">
# WooCommerce Onboarding Tasks

The onboarding tasks provides a way to help store owners get their sites quickly set up.

The task list is easily extensible to allow inserting custom tasks around plugin setup that benefits store owners.

<!-- markdownlint-disable-next-line no-inline-html -->
<img src="./images/task-list.png" width="500px" alt="Onboarding Task List" />

## Adding a custom task

### Step 1: Add your task in PHP

To add a custom task, you first need to create a new class that extends the `Task` class.

```php
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;

class MyTask extends Task {
  public function get_id() {
    return 'my-task';
  }

  public function get_title() {
    return __( 'My task', 'woocommerce' );
  }

  public function get_content() {
    return __( 'Add your task description here for display in the task list.', 'woocommerce');
  }
... (340 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/features/onboarding.md">
# WooCommerce Onboarding (DEPRECATED)

**Refer to the new [Core Profiler](./core-profiler.md) documentation for the latest onboarding experience.**

**Some parts of this documentation are still relevant and will be gradually moved to the new Core Profiler documentation.**

The onboarding feature is a reimagined new user setup experience for WooCommerce core. It contains two sections aimed at getting merchants started with their stores. The merchant begins with the "profile wizard", which helps with initial steps like setting a store address, making extension recommendations, and connecting to Jetpack for additional features. Once the profile wizard is complete, the merchant can purchase & install optional extensions via WooCommerce.com, before continuing to the "task list". From the task list, merchants are walked through a variety of items to help them start selling, such as adding their first product and setting up payment methods.

## Enabling Onboarding

If you run the development version of WooCommerce Admin from GitHub directly, no further action should be needed to enable Onboarding.

Users of the published WooCommerce Admin plugin need to either opt-in to using the new onboarding experience manually, or become part of the a/b test in core. See [https://github.com/woocommerce/woocommerce/pull/24991](https://github.com/woocommerce/woocommerce/pull/24991) for more details on the testing implementation.

To enable the new onboarding experience manually, log-in to `wp-admin`, and go to `WooCommerce > Settings > Help > Setup Wizard`. Click `Enable` under the `New onboarding experience` heading.

## New REST API endpoints

To power the new onboarding flow client side, new REST API endpoints have been introduced. These are purpose built endpoints that exist under the `/wc-admin/onboarding/` namespace, and are not meant to be shipped in the core rest API package. The source is stored in `src/API/Plugins.php`, `src/API/OnboardingProfile.php`, and `src/API/OnboardingTasks.php` respectively.

-   POST `/wc-admin/plugins/install` - Install requested plugins.
-   GET `/wc-admin/plugins/active` - Returns a list of the currently active plugins.
-   POST `/wc-admin/plugins/activate` - Activates the requested plugins. Multiple plugins can be passed to activate at once.
-   GET `/wc-admin/plugins/connect-jetpack` - Generates a URL for connecting to Jetpack. A `redirect_url` is accepted, which is used upon a successful connection.
-   POST `/wc-admin/plugins/request-wccom-connect` - Generates a URL for the WooCommerce.com connection process.
-   POST `/wc-admin/plugins/finish-wccom-connect` - Finishes the WooCommerce.com connection process by storing the received access token.
-   POST `/wc-admin/plugins/connect-square` - Generates a URL for connecting to Square during the payments task.
-   GET `/wc-admin/onboarding/profile` - Returns the information gathered during the profile wizard. See the `woocommerce_onboarding_profile_properties` array for a list of fields.
-   POST `/wc-admin/onboarding/profile` - Sets data for the profile wizard. See the `woocommerce_onboarding_profile_properties` array for a list of fields.
-   POST `/wc-admin/onboarding/tasks/import_sample_products` - Used for importing sample products during the appearance task.
... (84 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/features/payment-gateway-suggestions.md">
# WooCommerce Payment Gateway Suggestions

This feature uses JSON to retrieve the currently recommended payment gateways. The feature is capable of polling remote JSON sources to retrieve a list of recommended and visible gateways based on rulesets to be shown to the user.

After merchants click on a recommendation, plugins from this source will then walk through an installer step, followed by a connection step with the minimum required fields for setup defined by the downloaded plugin.

## Quick start

Gateway suggestions are retrieved from a REST API and can be added via a remote JSON data source or filtered with the `woocommerce_admin_payment_gateway_suggestion_specs` filter.

To quickly get started with an example plugin, run the following:

`WC_EXT=payment-gateway-suggestions pnpm example --filter=@woocommerce/admin-library`

This will create a new plugin that when activated will add two new gateway suggestions. The first is a simple gateway demonstrating how configuration fields can be pulled from the gateway class to create a configuration form. The second gateway shows a more customized approach via SlotFill.

## Data Source Polling

If a store is opted into marketplace suggestions via `woocommerce_show_marketplace_suggestions` the suggestions by default will be retrieved from `https://woocommerce.com/wp-json/wccom/payment-gateway-suggestions/2.0/suggestions.json`.

If a user is not opted into marketplace suggestions or polling fails, the gateway suggestions will fall back to the defaults in the `DefaultPaymentGateways` class.

## Remote Data Source Schema

The data source schema defines the recommended payment gateways and required plugins to kick of the setup process. The goal of this config is to provide the minimum amount of information possible to show a list of gateways and allow the gateways themselves to define specifics around configuration.

```json
[
  {
    "key": "gateway-key",
... (49 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/features/README.md">
# Features

This section covers examples of enabling feature flags to preview
features that are still in development.
</file>

<file path="plugins/woocommerce/client/admin/docs/features/transient-notices.md">
# WooCommerce Transient Notices

Transient notices provide a way to display snackbar notices from the server.  This is useful for displaying temporary messages to users based on a recent PHP based event.

### Adding a notice

Adding a notice will be display the notice the next time the page is loaded and reaches the `admin_enqueue_scripts` hook.  This means that if a notice is added prior to this hook (for example, on `admin_init`) it will be displayed on the current page load.

If a redirect occurs or the `admin_enqueue_scripts` hook is not reached, the notice will remain in the queue until it is shown on the next page load.

This method accepts an array with the following properties:

* `id`      => (string) Unique ID for the notice. Required.
* `status`  => (string) info|error|success
* `content` => (string) Content to be shown for the notice. Required.
* `options` => (array) Array of options to be passed to the notice component. See https://developer.wordpress.org/block-editor/reference-guides/data/data-core-notices/#createNotice for available options.
* `user_id` => (int|null) User ID to show the notice to.

```php
\Automattic\WooCommerce\Admin\Features\TransientNotices::add(
    array(
        'id'      => 'my-notice',
        'status'  => 'success',
        'content' => 'Some information to display to the user.',
        'options' => array(
            'actions' => array(
                array(
                    'label' => 'Click me',
                    'url'   => 'http://wordpress.com',
                )
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/activity-panels.md">
# Activity Panels

The Activity Panel aims to be a "one stop shop" for managing your store - fulfill new orders, manage product inventory, moderate reviews, and get information about running your store.

Activity Panels can be accessed wherever the WooCommerce Admin navigation bar is shown.

![Activity Panels Tabs Overview](images/activity-panels-tabs.png)

There are five panels: Inbox, Orders, Stock, Reviews, and WordPress Notices. You can read more about each panel below.

Each panel has an orange indicator denoting "unread" items.

![Activity Panels Button on Mobile](images/activity-panels-mobile-view.png)

On mobile devices, all of the panels get collapsed under the Woo logo.

## Inbox Panel

![Inbox Activity Panel](images/activity-panels-inbox.png)

This Inbox Panel is dedicated to informational content coming from multiple sources such as WooCommerce core, WooCommerce.com Subscription management, extensions activity and store achievements. It also displays insightful content that could help with the day to day tasks of managing and optimizing a store.

## Orders Panel

![Orders Activity Panel](images/activity-panels-orders.png)

The Orders Panel displays Orders that are considered "actionable". Orders needing fulfillment are shown by default. You can click "begin fulfillment" to go to the Order Details screen.

![Orders Activity Panel](images/activity-panels-orders-empty.png)

... (50 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-basics.md">
# Using WooCommerce Analytics Reports

Most of the new reports in the WooCommerce Analytics section have a set of common tools. This document will introduce you to those features, and how they can be utilized to customize and dive-deeper into the various new analytics reports.

## Date Range Picker

![Analytics Date Range Picker](images/analytics-basics-date-range-picker.png)
The Date Range picker allows you to specify which dates you want to include in the report being viewed. When you first open the Date Range Picker, a variety of popular _presets_ allow you to quickly chose some common date ranges:

![Analytics Date Range Picker Presets](images/analytics-date-range-picker-presets.png)

- Today
- Yesterday
- Week to date
- Last week
- Month to date
- Last month
- Quarter to date
- Last year

You can also select which date range to compare against, either the same range from the _Prior Year_ or the _Prior Period_.

If the presets don't match your desired date range, click the _Custom_ tab at the top of the picker to have more granular control over the date range:

![Analytics Date Range Picker Custom](images/analytics-date-range-picker-custom.png)

On the custom picker, you can either manually enter the start and end date using the provided input fields, or use the calendar to make your selection.

After either choosing a preset, or a custom date range, click the _Update_ button to modify the data in the report. Note by doing this, the date range selected is added to the address of the report URL - which allows you to bookmark, or share a report url with a specific date range to other Store admins. This date selection is persisted on the report view until you navigate away from the report.

... (75 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-categories-report.md">
# Categories Report

The Categories Report provides insight about the product categories of your store.

By default, the Categories report is sorted by number of `Items sold` by category descending.

![Category Filter](images/analytics-categories-report.png)

### Report Totals

The total of the rows in the report may not equal the totals at the bottom of the report for two reasons:

- Products can be assigned more than one category. The sales amounts for a product is included in the totals of all assigned categories.
- The sales amounts for children/descendant categories are both shown in the report for that category and included in the totals of the parent category(ies).

### Categories Filters

When the Category report loads it includes all categories for the selected date range. The Category filter dropdown has two filter options:

![Category Filter](images/analytics-categories-report-filter.png)

For either filter, begin typing the name of the category. While you are typing the name of the category the filter will lookup category names that contain the string you have entered. 

#### Single Category

This filter loads the report Categories report listing the products sold within that category.

![Category Filter](images/analytics-categories-single-category.png)

#### Comparison
... (40 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-coupons-report.md">
# Coupons Report

WooCommerce 4.0 (and the WooCommerce Admin plugin) includes a new `Analytics` top level menu. The `Coupons` report is under the `Analytics` menu.

If you have a store with existing Orders, you should [Import your Historical Data](analytics-historical-data-import.md)

### Coupon Filters

When the Coupon report loads it includes all coupons for the selected date range. The Coupon filter dropdown has two filter options:

![Coupon Filter](images/analytics-coupons-report-coupon-filter.png)

For either filter, begin typing the name of the coupon. While you are typing the name of the coupon the filter will lookup coupon names that contain the string you have entered. 

#### Single Coupon

This filter loads the report for the coupon you have selected.

![Coupon Filter](images/analytics-coupons-report-coupon-single.png)

#### Comparison

This filter loads the report for two or more coupons that you have selected.

![Coupon Filter](images/analytics-coupons-report-coupon-compare.png)

### Search

At the top of the report table is the search box. This allows you to filter the report by one or more coupons.

... (17 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-customers-report.md">
# Customers Report

The Customers Report provides insight about the customers of your store - where they live, when they may have registered, and how they've spent money.

Both registered customers and guests are shown in the report. If a guest checks out using the same email address more than once, their orders will be associated with each other (and they will considered the same purchaser).

![Customers Report Overview](images/analytics-customers-report.png)

### Single Customer View

This option loads the report for the customer you have selected.

![Customers Report Single Customer View](images/analytics-customers-report-single-customer.png)

### Advanced Filters

There are several filters available to the Customers Report:

- Name
- Country / Region
- Username
- Email
- Orders (count)
- Total Spend
- AOV (Average order value)
- Registered
- Last Active

![Customers Report Advanced Filters](images/analytics-customers-report-advanced-filters.png)

... (32 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-dashboard.md">
# WooCommerce Dashboard
The new dashboard in WooCommerce has been designed to allow you to keep track of the statistics and data that matter most to your site. Each section of the dashboard can be fully customized to meet the needs of your store, and also act as launching points to dive deeper into other Analytics Reports.

The dashboard is comprised of three sections: Performance Indicators, Charts, and Leaderboards. The data presented in these sections are controlled by the Date Picker which appears at the top of the page. This lets you quickly look at data for a number of preset date ranges like week, month, quarter, and year to date, or to select a specific date range to view.

Furthermore these sections can be re-ordered, re-named, or even toggled off if you don't want to view a particular section(s).

## Customizing Dashboard Sections
To customize dashboard sections, click the kebab menu in the top right corner of the section. The first item that appears in this menu is the ability to toggle the display of the various stats that are shown in the section. Below that you will find options for renaming the section, moving it up or down, or removing it entirely from the dashboard.

### Adding a Dashboard Section
If you removed a dashboard section, or you have an extension installed that adds in an option for a new section, a plus icon will appear at the bottom of your dashboard. Clicking that plus will allow you to insert previously removed sections, or add in new ones.

## Performance Indicator Section
By default the Performance Indicators section is what appears at the top of your dashboard below the Date Picker. Each performance indicator will display a label informing you of the statistic that is being presented, the value of that statistic for the date range selected, a percentage change over the prior period along with a trend arrow of up/down/same, and the value for the previous period that is being compared.

Beyond giving you a quick glimpse into the statistic, Peroformance Indicators also act as a quick shortcut to dive deeper into the data behind the stat. For example, clicking on the Total sales indicator will open up the Revenue Report for the date range that has been selected on the Dashboard. From there you can view associated charts, and tabular data for deeper analysis.

Using the customization menu in the top right corner of the section, you can toggle the display of the following default performance indicators:

| Indicator Name  | Description  | Links To ( Report Name > Chart Name ) |
|---|---|---|
| Total sales | Gross sales - Returns - Coupons + Taxes + Shipping | Revenue Report > Total sales | 
| Net sales | Gross sales - Returns - Coupons | Revenue Report > Net sales |
| Orders | The number of new orders placed for a selected date range | Orders Report > Orders |
| Average order value | Net sales / Orders | Orders Report > Average order value | 
| Items sold | The discrete number of items sold. | Products Report > Items sold | 
| Refunds | Money returned to the customer via a refund | Revenue Report > Refunds | 
| Discounted orders | The count of orders with a coupon applied. | Coupons Report > Orders Count | 
| Net discount amount | Total sum of discounts from coupons. | Coupons Report > Amount | 
... (49 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-downloads-report.md">
# Downloads Report

The Downloads Report provides insight into the performance of your store's downloadable products. Downloads counts are a total including multiple from the same IP address. Please note that dates are representantive of UTC time as opposed to local timezone as other reports are.

### All Downloads View

By default, the Downloads Report displays the unfiltered `All downloads` View. Each download is represented in the table and chart.

![Downloads Report All Downloads View](images/analytics-downloads-report.png)

### Advanced Filters

There are several filters available to the Downloads Report:

- Product
- Username
- Order number
- IP Address

![Downloads Report Advanced Filters](images/analytics-downloads-report-advanced-filters.png)

### Report Sorting

The report table allows sorting by the following columns:

- Date
- Product title
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-historical-data-import.md">
# Importing Historical Data

When you install WooCommerce 4.0 (or the WooCommerce Admin plugin) the new Analytics functionality needs to process the historical data in order to populate new Report pages. This is not done automatically - extremely large or high volume stores might want to schedule a maintenance window in which to import their historical data.

Stores with existing Orders will be prompted to import their data:

![Prompt to import historical data](images/analytics-historical-data-import-notice.png)

### Starting the Import

To start a historical data import, use the prompt above or go to Analytics > Settings, and scroll down to Import historical data.

![Analytics > Settings > Import historical data](images/analytics-historical-data-import-ready-to-import.png)

Stores that only want to see report data from a certain date onward can choose a date period, otherwise "all" data will be imported.

Extremely large or high volume stores might choose to import data in smaller increments - perhaps each year or quarter separately. The "skip previously imported customers and orders" control allows for overlapping date ranges to be imported without unnecessary data processing.

The Customer and Order counts will be updated in real time to reflect changes made to the import settings. Press "start" when you're ready for the import to begin.

### Monitoring Progress

Once you've started an import, progress will be periodically updated on the Analytics > Settings screen.

![Historical data import in progress](images/analytics-historical-data-import-in-progress.png)

Navigating away from this page will not affect the import, and you can return to it at any time to monitor progress.

Once the import is complete, the status will reflect it:

... (22 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-orders-report.md">
# Orders Report

The Orders Report provides insight about your store's orders.

By default, orders with non-excluded statuses are listed by order date descending. Excluded statuses can be edited on the [Settings page](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-settings.md#excluded-statuses)

Refunded orders cannot be excluded from the orders report. Refunded orders have two rows in the report: one for the date of the original order and one for the date of refund.

![Orders Report Overview](images/analytics-orders-report.png)

## Advanced Filters

The advanced filters allow adding multiple filters to the report. These filters can be applied in two ways:

- All - Orders must match all filters to be included in the report
- Any - Orders must match one or more filters to be included in the report

![Orders Report Filter Matching](images/analytics-orders-filter-match.png)

The following fields can be used for filtering:

- Order Status
- Products
- Coupon Codes
- Customer type
- Refunds
- Tax Rates

![Customers Report Advanced Filters](images/analytics-orders-report-advanced-filters.png)

... (10 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-products-report.md">
# Products Report

The Products Report provides insight into the sales performance of each product on your store.

### All Products View

By default, the Products Report displays the `All products` view. All products that have had sales in the specified date range will be shown.

![Products Report All Products View](images/analytics-products-report.png)

### Single Product View

![Products Report Single Product Search](images/analytics-products-report-single-product-search.png)

By selecting "Single product", you can search for a single product to display report data for.

![Products Report Single Product View](images/analytics-products-report-single-product.png)

### Comparison Mode

![Products Report Comparison Mode Search](images/analytics-products-report-comparison-search.png)

By selecting "Comparison", you can search for a multiple products to display report data for.

![Products Report Comparison Mode](images/analytics-products-report-comparison.png)

You can also use the checkboxes in the report table to select products for comparison. Click "Compare" in the table header to compare the selected products.

### Report Search

... (41 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-revenue-report.md">
# Revenue Report

The Revenue Report provides insight into the daily revenue of your store. A row is included for each day whether or not there were any orders on that day.

![Revenue Report Overview](images/analytics-revenue-report.png)

### Report Sorting

The report table allows sorting by the all report columns:

- Date
- Orders (# of orders)
- Gross sales
- Returns (Return amount)
- Coupons (Coupon amount)
- Net sales
- Taxes
- Shipping
- Total sales

By default, the report shows the most recent days.

### Report Links

The Orders column contains clickable entries that take you to the order edit listing filtered to orders on that date.
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-settings.md">
# Analytics Settings

WooCommerce Admin is pre-configured with default settings for WooCommerce Analytics. These settings are broken down into sections:

- Excluded Statuses
- Actionable Statuses - See [Activity Panels](activity-panels.md) for details
- Default Date Range
- Import historical data - See [Importing Historical Data](analytics-historical-data-import.md) for details
- Reset defaults

### Excluded Statuses

![Excluded statuses settings](images/settings-excluded-statuses.png)

In this section, statuses that are **unchecked** are **included** in analytics reports. **Checked** statuses are **excluded**. If your store uses custom order statuses, those statuses are included in the reports by default. They will be listed in this section under `Custom Statuses` and can be excluded via the status checkbox.

### Default Date Range

![Default Date Range setting](images/settings-default-date-range.png)

WooCommerce Admin is pre-configured with a default date range of `Month to date`. This is the date range that will be used when loading the WooCommerce Dashboard or Analytics page from any non-WooCommerce Admin page. Any reports that support a date range will have a Date Range Picker to allow changing the date range for the report.

### Reset Defaults

The `Reset defaults` button resets the settings to default values for all of the settings above the button. It has no effect on the data imported via `Import historical data`.
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-stock-report.md">
# Stock Report

The Stock Report provides insight about the inventory of your store. This report is only available on stores with stock management enabled.


![Stock Report Overview](images/analytics-stock-report.png)

### Report Filter

The Stock Report allow you to filter the report by stock status. **Note:** Products that do not have stock management enabled are shown as `Out of stock`.

![Stock Report Filter](images/analytics-stock-status-filter.png)

### Single Status View

This option loads the report for the stock status you have selected.

![Stock Report Single Status](images/analytics-stock-single-status.png)

### Report Sorting

The report table allows sorting by all columns:

- Product
- SKU
- Status
- Stock

By default, the report shows stock ordered by stock quantity ascending.

... (7 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-taxes-report.md">
# Taxes Report

The Taxes Report provides insight into taxes collected on your store.

### All Taxes View

By default, the Taxes Report displays the `All taxes` view. All taxes that have been collected in the specified date range will be shown.

![Taxes Report All Taxes View](images/analytics-taxes-report.png)

### Comparison Mode

By selecting "Comparison", you can search for a multiple tax codes to display report data for.

![Taxes Report Comparison Mode Search](images/analytics-taxes-report-comparison.png)

You can also use the checkboxes in the report table to select tax codes for comparison. Click "Compare" in the table header to compare the selected tax codes.

### Report Search

The search control at the top of the report table provides a quick interface to filter the report to one or more specific tax codes.

![Taxes Report Search](images/analytics-taxes-report-search.png)

It also allows partial string matching on tax codes.

![Taxes Report Search Partial](images/analytics-taxes-report-search-results.png)

### Report Sorting

... (15 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/analytics-variations-report.md">
# Variations Report

The Variations Report provides insight into the sales performance of each Product Variation on your store.

### All Variations View

By default, the Variations Report displays the `All variations` view. All variations that have had sales in the specified date range will be shown.

![Variations Report All Variations View](images/analytics-variations-report.png)

### Single Variation View

![Variations Report Single Variation Search](images/analytics-variations-report-single-variation-search.png)

By selecting "Single variation", you can search for a single variation to display report data for.

![Variations Report Single variation View](images/analytics-variations-report-single-variation.png)

### Comparison Mode

![Variations Report Comparison Mode Search](images/analytics-variations-report-comparison-search.png)

By selecting "Comparison", you can search for multiple variations to display report data for.

![Variations Report Comparison Mode](images/analytics-variations-report-comparison.png)

You can also use the checkboxes in the report table to select variations for comparison. Click "Compare" in the table header to compare the selected variations.

### Advanced Filters

... (44 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/woocommerce.com/README.md">
# WooCommerce Admin

The WooCommerce Admin is where the next iteration of the administrative experience for WooCommerce is being developed. The project is being built on top of the modern JavaScript packages that are being released from the [core WordPress editor project](https://github.com/wordpress/gutenberg). By building with these `@wordpress/components` - WooCommerce Admin seeks to create a cohesive experience with the latest WordPress core design system, and to deliver a fast and modern set of tools to manage one's WooCommerce Store with.

Currently, development efforts have been focused on two primary areas:

- Analytics: A new suite of robust reports with powerful filtering and data export utilities.
- Dashboard: A fully customizable view into the metrics that matter most to your store.
- Navigation / Activity Panels: A way to keep in touch with key jobs to be done on your store. The new Activity panels in the header section of your store highlight areas that need attention.

## Analytics

With WooCommerce installed, a new Analytics menu item is created in the wp-admin menu system. This menu item, and the reports contained inside of it are available to all wp-admin users that have the `view_woocommerce_reports` capability, so per a standard WooCommerce install this would give `shop_manager`s and `administrator`s access to the reports.

Each report is quite unique with its own set of filtering options and chart types. To learn more about each individual report, please view the pages below:

- [Analytics Basics](analytics-basics.md)
- [Revenue Report](analytics-revenue-report.md)
- [Orders Report](analytics-orders-report.md)
- [Products Report](analytics-products-report.md)
- [Categories Report](analytics-categories-report.md)
- [Coupons Report](analytics-coupons-report.md)
- [Taxes Report](analytics-taxes-report.md)
- [Downloads Report](analytics-downloads-report.md)
- [Stock Report](analytics-stock-report.md)
- [Customers Report](analytics-customers-report.md)

### Settings and Historical Data Import

The Analytics section also has a menu item for _Settings_. On this page you can control items that affect how the WooCommerce Admin Analytics system works, and you can also import historical data into the reporting database tables.
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/data.md">
# Data

WooCommerce Admin data stores implement the [`SqlQuery` class](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Admin/API/Reports/SqlQuery.php). 

## SqlQuery Class

The `SqlQuery` class is a SQL Query statement object. Its properties consist of

- A `context` string identifying the context of the query.
- SQL clause (`type`) string arrays used to construct the SQL statement:
    - `select`
    - `from`
    - `right_join`
    - `join`
    - `left_join`
    - `where`
    - `where_time`
    - `group_by`
    - `having`
    - `order_by`
    - `limit`

## Reports Data Stores

The base DataStore `Automattic\WooCommerce\Admin\API\Reports\DataStore` extends the `SqlQuery` class. There is `StatsDataStoreTrait` that adds Interval & Total Queries. The implementation data store classes use the following `SqlQuery` instances:

| Data Store | Context | Class Query | Sub Query | Interval Query | Total Query |
| ---------- | ------- | ----------- | --------- | -------------- | ----------- |
| Categories | categories | Yes | Yes | - | - |
| Coupons | coupons | Yes | Yes | - | - |
... (55 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/layout.md">
Layout
======

This component handles the layout of the WooCommerce app. This also controls the routing, and which component should be shown on each page.

## Layout

The `Layout` component sets up the structure of the page, using the components described below.

## Notices

This component will house the list of high priority notices. This appears on every page. _Currently just a placeholder div._

## Controller

`layout/controller.js` has two exports, a `<Controller />` component and a `getPages` function.

### `getPages`

This function returns an array of objects, each describing a page in the app. The properties in each object are:

- `container`: A component, rendered in the main content area of the Layout
- `path`: The path this component should show up on (this should be unique to each entry)
- `wpMenu`: The ID of the menu item in the  wp-admin sidebar, used to toggle on/off the current menu item classes

### `<Controller />`

This component pulls out the current page from `getPages`, and renders the container component defined in the object.
</file>

<file path="plugins/woocommerce/client/admin/docs/page-controller.md">
# WooCommerce Admin Page Controller

Pages rendered with React and pages that include the WooCommerce Admin header (containing the Activity Panel) need to be registered with the WooCommerce Admin Page Controller.

This is the API you will use to add your own React-powered page, or to include the WooCommerce Admin header on your plugin pages.

## Connecting a PHP-powered Page

To show the WooCommerce Admin header on existing PHP-powered admin pages (most plugin pages), use the `wc_admin_connect_page()` function.

Connecting pages uses five parameters to `wc_admin_connect_page()`:

-   `id` - Identifies the page with the controller. Required.
-   `parent` - Denotes the page as a child of `parent`. Used for breadcrumbs. Optional.
-   `screen_id` - Corresponds to [`PageController::get_current_screen_id()`](../includes/page-controller/class-wc-admin-page-controller.php#L219) to determine the current page. Required.
-   `title` - Page title. Used to build breadcrumbs. String or array of breadcrumb pieces. Required.
-   `path` - Page path (relative). Used for linking breadcrumb pieces when this page is a `parent`. Optional.

### Examples

```php
// WooCommerce > Settings > General (default tab).
wc_admin_connect_page(
	array(
		'id'        => 'woocommerce-settings',
		'screen_id' => 'woocommerce_page_wc-settings-general',
		'title'     => array(
			__( 'Settings', 'woocommerce' ),
			__( 'General', 'woocommerce' ),
		),
... (150 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/docs/README.md">
# WooCommerce Admin

-   [CSS Structure](stylesheets.md)
-   [Data](data.md)
-   [Examples](examples/)
-   [Features](features/)
-   [Layout](layout.md)
-   [Page Controller](page-controller.md)
-   [WooCommerce.com](https://woocommerce.com/)
</file>

<file path="plugins/woocommerce/client/admin/docs/stylesheets.md">
# CSS

## Folder/File Structure

- `/shared/*` – these are the styles that will appear in compiled CSS - the reset, gutenberg components import, etc
- `/_embedded.scss` – this file is used for the embed pages CSS, and is imported in `embedded.js` only
- `/_index.scss` – this file is used for the app's CSS, and is imported in `index.js` only

## Naming: Component classes

Please refer to [CSS SASS coding guidelines and naming conventions](https://developer.woocommerce.com/docs/contribution/contributing/CSS-SASS-coding-guidelines-and-naming-conventions/)
</file>

<file path="plugins/woocommerce/client/admin/docs/xstate.md">
# XState Dev Tooling

XState is a state management framework for Javascript applications. It is based on the concept of [finite state machines](https://en.wikipedia.org/wiki/Finite-state_machine) and statecharts.

In order to help you visualize and debug the state machines within WooCommerce Core, XState provides a [visualizer](https://stately.ai/viz) that you can use in your browser.


## Enabling the visualizer

To enable this, run this command in your browser's developer console:

```js
localStorage.setItem('xstate_inspect', 'true');
```

Then, a new tab with the XState visualizer should appear for pages that have state machines.

## Using the visualizer


### Main View

The main panel in the visualizer will show you the current state of the state machine. Current states are shown with a blue border, and available transitions are solid blue bubbles. If the events are simple without payload requirements, you can click on the transition bubbles to trigger the transition. Otherwise, you can use the 'Send event' button on the bottom right of the visualizer to send events to the state machine.


### State Tab

The context is the working memory that the state machine has access to. It is a plain Javascript object that can be modified by the state machine.

Within the 'State' tab, you can see the printouts of three objects: "Value", "Context", and "State".
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/.browserslistrc">
extends @wordpress/browserslist-config
</file>

<file path="plugins/woocommerce/client/admin/.gitattributes">
# Line-ending normalization
* text=auto

/.* export-ignore
/*.md export-ignore
/node_modules* export-ignore
/tests export-ignore
/bin export-ignore
/phpcs.* export-ignore
/phpunit.* export-ignore
/composer.lock export-ignore
/composer.json export-ignore
/renovate.json export-ignore
/webpack.config.js export-ignore
/postcss.config.js export-ignore
/package.json export-ignore
/package-lock.json export-ignore
/babel.config.js export-ignore
/Gruntfile.js export-ignore
/packages* export-ignore
/docs* export-ignore
/config* export-ignore
/client* export-ignore
/docker* export-ignore
/storybook* export-ignore
</file>

<file path="plugins/woocommerce/client/admin/.prettierrc.js">

</file>

<file path="plugins/woocommerce/client/admin/babel.config.js">

</file>

<file path="plugins/woocommerce/client/admin/CLAUDE.md">
# Claude Code Documentation for WooCommerce Admin Client

**Scope**: React/TypeScript development, Jest testing, Webpack builds
**Location**: `plugins/woocommerce/client/admin`

**See also:**

- `../../CLAUDE.md` - PHP tests and plugin-level documentation
- `client/settings-payments/CLAUDE.md` - Settings Payments module patterns

## Quick Reference Commands

```bash
# Testing
pnpm run test:js                             # Run all tests
pnpm run test:js -- status-badge.test.tsx    # Specific file

# Linting (ONLY specific files)
npx eslint --fix path/to/file.tsx            # Fix specific file
npx eslint path/to/file.tsx                  # Check specific file
pnpm run ts:check                            # Type checking
markdownlint --fix path/to/file.md           # Lint markdown files

# Building
pnpm run build                               # Production build
```

## When to Use This Documentation

Use this doc when you need to:
... (521 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/composer.json">
{
	"name": "woocommerce/woocommerce-admin",
	"description": "WooCommerce admin.",
	"homepage": "https://woocommerce.com/",
	"type": "wordpress-plugin",
	"version": "11.8.0-dev",
	"license": "GPL-2.0-or-later",
	"prefer-stable": true,
	"minimum-stability": "dev",
	"require-dev": {
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"config": {
		"platform": {
			"php": "7.4"
		}
	},
	"extra": {
		"changelogger": {
			"changes-dir": "../../changelog",
			"formatter": {
				"filename": "../../../../tools/changelogger/class-package-formatter.php"
			},
			"types": {
				"fix": "Fixes an existing bug",
				"add": "Adds functionality",
				"update": "Update existing functionality",
				"dev": "Development related task",
				"tweak": "A minor adjustment to the codebase",
				"performance": "Address performance issues",
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/eslint.config.mjs">
/**
 * External dependencies
 */
⋮----
/**
 * Internal dependencies
 */
⋮----
// node_modules is ignored by default. `api` has its own config and command.
⋮----
/*
	 * The eslintrc registered the `import` plugin itself. It must not:
	 * eslint-plugin-import has no ESLint v10 support, and the shared config
	 * already provides the fixupPluginRules-wrapped instance WordPress registers.
	 * Registering a second copy is both fatal at rule-run time and a
	 * "Cannot redefine plugin" hazard.
	 */
</file>

<file path="plugins/woocommerce/client/admin/package.json">
{
	"name": "@woocommerce/admin-library",
	"private": true,
	"version": "3.3.0",
	"license": "GPL-2.0-or-later",
	"author": "Automattic",
	"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/client/admin/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com:woocommerce/woocommerce.git"
	},
	"files": [
		"build"
	],
	"scripts": {
		"build": "pnpm build:project",
		"build:project": "pnpm --stream '/^build:project:.*$/'",
		"build:project:bundle": "NODE_ENV=\"${NODE_ENV:-production}\" WC_ADMIN_PHASE=\"${WC_ADMIN_PHASE:-core}\" webpack",
		"build:project:feature-config": "php ../../bin/generate-feature-config.php",
		"changelog": "XDEBUG_MODE=off composer install --quiet && composer exec -- changelogger",
		"update:php": "XDEBUG_MODE=off composer update --quiet",
		"example": "webpack --config docs/examples/extensions/examples.config.js",
		"lint": "pnpm --if-present '/^lint:lang:.*$/'",
		"lint:fix": "pnpm --if-present '/^lint:fix:lang:.*$/'",
		"lint:fix:lang:css": "stylelint '**/*.scss' --fix --ip 'storybook/wordpress'",
		"lint:fix:lang:js": "pnpm lint:lang:js --fix",
		"lint:lang:css": "stylelint '**/*.scss' --cache --cache-location=node_modules/.cache/stylelint",
		"lint:lang:js": "eslint ./client --cache --cache-location=node_modules/.cache/eslint",
		"lint:lang:types": "tsc --build --emitDeclarationOnly",
		"postinstall": "node bin/xstate5-symlink.js",
... (222 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/README.md">
# WooCommerce Admin

This is a javascript-driven, React-based admin interface for WooCommerce.

## Development

Please refer to the [WooCommerce Admin Development](https://developer.woocommerce.com/docs/contribution/contributing/#setting-up-your-development-environment).

## End-to-end tests

Please refer to the [WooCommerce End to End Tests](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/tests/e2e/README.md).

## Common Issues

If you're encountering any issue setting things up, chances are we have been there too. Please have a look at our [wiki](https://github.com/woocommerce/woocommerce/wiki/Common-Issues) for a list of common problems.
</file>

<file path="plugins/woocommerce/client/admin/stylelint.config.js">

</file>

<file path="plugins/woocommerce/client/admin/tsconfig.json">
{
	"compilerOptions": {
		"noEmit": true,
		"target": "esnext",
		"moduleResolution": "node",
		"allowJs": true,
		"jsx": "preserve",
		"strict": true,
		"esModuleInterop": true,
		"skipLibCheck": true,
		"module": "esnext",
		"baseUrl": "client",
		"paths": {
			"~/*": [
				"*"
			]
		},
		"rootDir": "client",
		"typeRoots": [
			"./client/typings",
			"./node_modules/@types"
		],
		"composite": true
	},
	"include": [
		"./client/**/*"
	],
	"exclude": [
		"**/test/*"
	],
... (55 lines truncated)
</file>

<file path="plugins/woocommerce/client/admin/webpack.config.js">
const getSubdirectoriesAt = ( searchPath ) =>
⋮----
const resolvePackageDirectory = ( packageName, fromDirectory )
⋮----
const resolvePackageSourceEntry = ( name ) =>
⋮----
const resolvePackageStyleEntry = ( name ) =>
⋮----
const getEntryPoints = () =>
⋮----
filename: ( data ) =>
⋮----
modulename( outputPath, data )
⋮----
requestToExternal( request )
requestToHandle( request )
</file>

<file path="plugins/woocommerce/client/blocks/changelog/65429-fix-rtl-settings-modal-buttons">
Significance: patch
Type: fix

Fix right-to-left (RTL) button spacing in the shipping settings modal, where action buttons (for example in Local Pickup) were stuck together.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/66286-add-review-block-offset">
Significance: minor
Type: add

Add offset controls to the Reviews by Product and Reviews by Category blocks.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/add-cart-item-data-raw-key">
Significance: minor
Type: add

Store API: add `raw_key` to cart item `item_data` so extensions can identify their own entries without matching a translated label.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/clarify-blocks-package-api-boundaries">
Significance: patch
Type: dev

Organize Blocks packages into explicit public API and internal runtime directories without changing existing imports, script handles, or globals.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/dev-deprecate-wc-entities-global">
Significance: patch
Type: dev

Separate entity registration from tree-shaken helpers while deprecating the global utilities and manual registration functions.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/dev-remove-unused-markdown-it">
Significance: patch
Type: dev

Remove the unused markdown-it development dependency.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/remove-old-blocks-release-testing">
Significance: patch
Type: dev
Comment: Remove archived Blocks release testing documentation and its index links.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-add-to-cart-form">
Significance: patch
Type: dev
Comment: Reduce Add to Cart Form E2E tests from 13 to 8; Jest owns the quantity stepper's clamping, change-event dispatch, decimal rounding, and input defaults.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-add-to-cart-with-options">
Significance: patch
Type: dev
Comment: Add Jest coverage for the four Add to Cart with Options Interactivity API stores, plus PHPUnit coverage for the legacy form markup and the grouped-product quantity handler. No E2E tests are removed.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-cart-checkout-extensibility">
Significance: patch
Type: dev
Comment: Move 4 extension cart update E2E tests to Jest and PHPUnit, covering the extensionCartUpdate wrapper, the cart thunk, the notice context, and the CartExtensions route; keep one browser title per spec.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-cart-checkout-shopper-journeys">
Significance: patch
Type: dev
Comment: Consolidate the Cart block shopper E2E journeys and move the discount-label, single-use coupon, and shipping-topology checks to Jest and PHPUnit; replace the wall-clock nonce expiry with one deterministic invalid nonce.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-catalog-sorting">
Significance: patch
Type: dev
Comment: Add Jest coverage for the Catalog Sorting block's registration, dynamic save callback and editor placeholder. No E2E test is removed.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-checkout-block-shopper">
Significance: patch
Type: dev
Comment: Reduce Checkout block shopper E2E tests from 13 to 5; a Jest suite and a Checkout block PHPUnit test own the shipping-topology guard.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-customer-account-block">
Significance: patch
Type: dev
Comment: Add Jest coverage for the Customer Account block's sidebar settings and PHPUnit coverage for the accessible name its link exposes, which nothing covered before.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-fix-js-ci-changes-globs">
Significance: patch
Type: dev
Comment: Fix the JavaScript CI job changes globs so edits under tests/integration and tests/utils trigger the test run.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-name-slugs-in-unregister-block-types-test">
Significance: patch
Type: dev
Comment: Assert cart, catalog-sorting and product-results-count by name in the unregister-block-types unit test.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-product-collection-frontend">
Significance: patch
Type: dev
Comment: Reduce Product Collection frontend E2E tests from 37 to 20; PHPUnit owns the renderer's state and route parity, Jest owns the editor contracts and the product template's request, and one new browser title keeps the empty-collection and No Results render.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-product-collection-registration">
Significance: patch
Type: dev
Comment: Add Jest coverage for __experimentalRegisterProductCollection, covering falsy-value preservation, invalid-input rejection, prop-injection scoping and reference-context routing. No E2E test is removed.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-product-filters-block">
Significance: patch
Type: dev
Comment: Reduce Product Filters E2E tests from 9 to 3; PHPUnit owns the attribute filter's options and counts, and Jest owns the store's attribute toggle.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-product-gallery">
Significance: patch
Type: dev
Comment: Reduce Product Gallery E2E tests from 12 to 8; Jest owns the block's registered defaults and its Single Product ancestry.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-product-results-count">
Significance: patch
Type: dev
Comment: Add Jest coverage for the Product Results Count block's registration and PHPUnit coverage for its rendered result count. No E2E test is removed.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-refresh-block-manifest-copies">
Significance: patch
Type: dev

Refresh generated block.json copies exactly and prune stale ones so PHP test metadata matches the source manifests.
</file>

<file path="plugins/woocommerce/client/blocks/changelog/testops-234-unregister-block-types">
Significance: patch
Type: dev
Comment: Extend the unregister-block-types unrestricted-context test to cover Catalog Sorting and Product Results Count.
</file>

<file path="plugins/woocommerce/client/blocks/docs/contributors/block-assets.md">
# Block Script Assets <!-- omit in toc -->

## Table of contents <!-- omit in toc -->

-   [When are assets needed?](#when-are-assets-needed)
-   [Choosing Handles for Assets (and scripts in general)](#choosing-handles-for-assets-and-scripts-in-general)
-   [Using the `AbstractBlock` class](#using-the-abstractblock-class)
    -   [AbstractBlock::render](#abstractblockrender)
    -   [AbstractBlock::enqueue_editor_assets](#abstractblockenqueue_editor_assets)
    -   [AbstractBlock::enqueue_assets](#abstractblockenqueue_assets)
    -   [AbstractBlock::enqueue_data](#abstractblockenqueue_data)
-   [woocommerce_shared_settings deprecated filter](#woocommerce_shared_settings-deprecated-filter)

[Block Types](https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/trunk/src/BlockTypes) are often responsible for enqueuing script assets that make blocks functional on both the front-end and within the editor. Additionally, some block scripts require extra data from the server and thus have extra dependencies that need to be loaded.

For performance reasons the blocks plugin ensures assets and asset data is made available only as needed.

## When are assets needed?

Assets are needed when we know a block will be rendered.

In the context of [Block Types](https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/trunk/src/BlockTypes), assets and asset data is enqueued within the block `render()` method.

In an admin editor context we must also ensure asset _data_ is available when the `enqueue_block_editor_assets` hook is fired. That is because block scripts are enqueued ready for the Block Inserter, but the block may not be rendered.

Note: `enqueue_block_editor_assets` fires regardless of whether or not a block has been rendered in the editor context, so unless handled correctly, block data may be loaded twice. The `AbstractBlock` class below handles this for you, or you can track whether or not assets have been loaded already with a class variable.

## Choosing Handles for Assets (and scripts in general)

When creating a script or style assets, the following rules should be followed to keep asset names consistent, and to avoid
... (71 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/contributors/coding-guidelines.md">
# Coding Guidelines <!-- omit in toc -->

## Table of contents <!-- omit in toc -->

-   [CSS Class Names](#css-class-names)
    -   [Prefixing](#prefixing)
    -   [Naming](#naming)
-   [RTL Styles](#rtl-styles)
-   [SCSS File Naming Conventions for Blocks](#scss-file-naming-conventions-for-blocks)
-   [Accessible font sizes](#accessible-font-sizes)
-   [CSS specificity wars with 3rd party themes](#css-specificity-wars-with-3rd-party-themes)

This living document serves to prescribe coding guidelines specific to the WooCommerce Blocks project. Base coding guidelines follow the [WordPress Coding Standards](https://make.wordpress.org/core/handbook/best-practices/coding-standards/) and [Gutenberg coding standards](https://developer.wordpress.org/block-editor/contributors/develop/coding-guidelines/). The following sections outline additional patterns and conventions used in the Blocks project.

## CSS Class Names

To avoid class name collisions, class names must adhere to the following guidelines, based on the [BEM methodology](https://en.bem.info/methodology/) and [Gutenberg coding standards](https://developer.wordpress.org/block-editor/contributors/develop/coding-guidelines/).

### Prefixing

As a WordPress plugin, Blocks has to play nicely with other plugins and themes, and WordPress itself. To minimize potential conflicts, all classes should be prefixed with `.wc-block-`.

### Naming

All class names assigned to an element must be prefixed. We use different prefixes to differentiate frontend and editor elements as well as identifying if they are components or not:

-   `wc-block` for classes applied to a single block.
-   `wc-block-components` for classes applied to a component, which might be used by several blocks.
-   `wc-block-editor` for classes applied to a single block but only used in the editor UI.
-   `wc-block-editor-components` for classes applied to an editor component.
... (133 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/contributors/components.md">
# Storybook & Components

This repo includes [Storybook](https://storybook.js.org) tooling so we can test and develop components in isolation.

The storybook is automatically built and published to [GitHub pages](https://woocommerce.github.io/woocommerce-blocks/) on every push to the main branch.

## Where are our components?

We have components in a few folders, for different contexts.

-   [`assets/js/base/components`](../../assets/js/base/components)
-   [`assets/js/editor-components`](../../assets/js/editor-components)
-   [`assets/js/icons`](../../assets/js/icons)

**`assets/js/base/components`** are used in front-end code, as well as editor & admin.
These components help us build consistent interfaces across the front end (shopper) experience and elsewhere.
Because they can be used in the front end and editor, components in this folder should:

-   Perform efficiently - i.e. not adversely affect page performance/experience.
-   Have lean dependencies - i.e. not bloat the payload unnecessarily.
-   Look consistent in common themes; ideally should allow themes to adjust appearance as necessary.

**`assets/js/editor-components`** are used in the editor UI for our blocks.
They allow us to build a consistent and powerful UI for merchants for authoring content relating to Woo data - e.g. selecting products or product attributes. Because they are focused on the editor, they can rely on known editor dependencies and optimise styling for the editor only.

**`assets/js/icons`** is a suite of icons and SVG images that we use in our interfaces.

For more info about individual components, refer to [Storybook](https://woocommerce.github.io/woocommerce-blocks/) or individual readme files.

## How to run Storybook locally and test components
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/contributors/css-build-system.md">
# CSS Build System <!-- omit in toc -->

## Table of contents <!-- omit in toc -->

-   [Right-to-left](#right-to-left)
-   [Relevant files](#relevant-files)

CSS files are built with Webpack, which gathers all SCSS files in the app and processes them with SASS and some PostCSS plugins like Autoprefixer. The resulting stylesheets are merged into three files for the whole plugin:

-   `style.css`: loaded in the editor and the frontend, it includes the basic styles needed for the blocks frontend.
-   `editor.css`: only loaded in the editor, it includes styles only relevant to the block editor like specific editor components.
-   `vendors-style.css`: loaded in the editor and the frontend of some blocks, it includes external stylesheets which are required by some blocks but are not part of our codebase.

> Details on which stylesheets are included in each output file can be found in [`webpack-configs.js`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8befaccf35cac958c2d222e89facb84f9b675525/bin/webpack-configs.js#L655-L680).

## Right-to-left

All files described above are generated in a LTR version and a RTL version. The RTL version is generated automatically with the internal `WebpackRTLPlugin` exported from `@woocommerce/internal-build/style-build` and has a `-rtl.css` suffix at the end of the file name.

## Relevant files

Webpack config is split between several files, some relevant ones for the CSS build system are:

-   [`webpack.config.js`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/webpack.config.js): Top level webpack config.
    -   [`bin/webpack-configs.js`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/bin/webpack-configs.js): Code for generating each build config. This most closely resembles a classic webpack config - if you're looking for something, start here.
        -   [`bin/webpack-entries.js`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/bin/webpack-entries.js): Code for generating [webpack `entry` definitions](https://webpack.js.org/concepts/entry-points/) and mapping source files to entry points. If you're adding a new block or module to the build, start here.

<!-- FEEDBACK -->

---
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/contributors/documentation-guidelines.md">
# Documentation Guidelines <!-- omit in toc -->

## Table of contents <!-- omit in toc -->

-   [Use active instead of passive voice](#use-active-instead-of-passive-voice)
    -   [Example](#example)
-   [Use the personal pronoun “you”](#use-the-personal-pronoun-you)
-   [Don’t use gendered pronouns](#dont-use-gendered-pronouns)
-   [Filename must resemble the title](#filename-must-resemble-the-title)
    -   [Example](#example-1)
-   [Use correct heading hierarchy](#use-correct-heading-hierarchy)
    -   [Example](#example-2)
-   [Use semantically correct markup](#use-semantically-correct-markup)
-   [Use correct spelling](#use-correct-spelling)
    -   [Example](#example-3)
-   [Use images not wider than 50% width](#use-images-not-wider-than-50-width)
-   [Use descriptive links](#use-descriptive-links)
    -   [Example](#example-4)
-   [Explain arguments](#explain-arguments)
    -   [Example](#example-5)
-   [Explicitly define language for code examples](#explicitly-define-language-for-code-examples)
    -   [Example](#example-6)
        -   [CSS code example](#css-code-example)
        -   [JS code example](#js-code-example)
-   [Import from global imports rather than alias](#import-from-global-imports-rather-than-alias)
-   [Use table of contents for top-level readme](#use-table-of-contents-for-top-level-readme)
-   [Use internal links](#use-internal-links)
-   [Sort releases descending](#sort-releases-descending)
    -   [Example](#example-7)
-   [Structure “How to” instructions](#structure-how-to-instructions)
... (151 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/contributors/e2e-guidelines.md">
# WooCommerce Blocks End-to-End Tests

This living document serves as a guide for writing end-to-end (E2E) tests with Playwright in the WooCommerce Blocks project.

## Preparing the environment

Please refer to [the Getting Started section of the main `README.md`](https://github.com/woocommerce/woocommerce/blob/trunk/README.md) for a general-purpose guide on getting started. The rest of this document will assume that you've installed all of the prerequisites and setup described there.

Run the following command from the repository root to build the WooCommerce plugin:

```sh
pnpm --filter='@woocommerce/plugin-woocommerce' watch:build
```

Next, run the following command from the [`blocks` client folder](../../../blocks/) to start a `wp-env` instance and install all the testing products, languages, etc.:

```sh
cd plugins/woocommerce/client/blocks/
pnpm env:start
```

> [!TIP]
> If you want to start/stop the environment without running the whole setup, use the native `wp-env` commands directly, e.g. `npx wp-env start` and `npx wp-env stop`.

The testing environment should now be ready under [localhost:8889](http://localhost:8889).

### Resetting the environment

Occasionally, you'll need to reset the environment, e.g., when testing products have been updated. To do that, run the following command and go make yourself some coffee:

... (257 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/contributors/folder-structure.md">
# Folder Structure

The following snippet explains how the WooCommerce Blocks repository is structured omitting irrelevant or obvious items with further explanations:

```text
│
├── LICENSE
├── README.md
├── .github/CODEOWNERS
├── .github/CODE*OF_CONDUCT.md
├── .github/CONTRIBUTING.md
├── .github/SECURITY.md
│
├── .distignore
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitattributes
├── .gitignore
├── .prettierrc.js
├── .stylelintrc.json
├── phpcs.xml.dist
│ Dot files and config files used to configure the various linting tools
│ used in the repository (PHP, JS, styles...).
│
├── .nvmrc
│ Required Node version of the project.
│
├── babel.config.js
├── global.d.ts
... (171 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/contributors/getting-started.md">
# Getting Started <!-- omit in toc -->

## Table of contents <!-- omit in toc -->

-   [Cloning the Git Repository](#cloning-the-git-repository)
-   [Configuring your WordPress site](#configuring-your-wordpress-site)
-   [Installing dependencies](#installing-dependencies)
-   [Building the plugin files](#building-the-plugin-files)
-   [Create a plugin package in ZIP format](#create-a-plugin-package-in-zip-format)
-   [Linting](#linting)
-   [Running the Blocks plugin](#running-the-blocks-plugin)
-   [Developer Tools (Visual Studio Code)](#developer-tools-visual-studio-code)
    -   [EditorConfig](#editorconfig)
    -   [ESLint](#eslint)
    -   [Prettier](#prettier)
-   [Testing](#testing)

Before you can begin contributing to the Blocks plugin there are several steps and tools required to setup your local development environment.

## Cloning the Git Repository

Before you can start modifying files you'll want to clone this repository locally, either via the command line, or using a Git client such as [GitHub Desktop](https://desktop.github.com/).

To do so from the command line, ensure you have [`git`](https://git-scm.com) installed on your machine, and run the clone command:

```sh
git clone https://github.com/woocommerce/woocommerce-blocks.git
```

## Configuring your WordPress site
... (124 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/contributors/javascript-build-system.md">
# JavaScript Build System <!-- omit in toc -->

## Table of contents <!-- omit in toc -->

-   [Environment variables](#environment-variables)
-   [Babel](#babel)
-   [External scripts](#external-scripts)
-   [Aliases](#aliases)
-   [Styling](#styling)
-   [Relevant files](#relevant-files)

WooCommerce Blocks uses Webpack to build the files that will be consumed by browsers. There are several different Webpack configs in order to build files for different contexts of the plugin. They can all be found in [`webpack.config.js`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/6da64165025e7a2afc1782e4b278d72536e7b754/webpack.config.js#L162-L169), but this is a quick summary:

-   `CoreConfig`: config for shared libraries like settings, blocks data or some HOCs and context.
-   `MainConfig`: config that builds the JS files used by blocks in the editor and is responsible for registering the blocks in Gutenberg.
-   `FrontendConfig`: config that builds the JS files used by blocks in the store frontend.
-   `PaymentsConfig`: config that builds the JS files used by payment methods in the Cart and Checkout blocks.
-   `ExtensionsConfig`: config that builds extension integrations.
-   `StylingConfig`: config that builds CSS files. You can read more about it in the page [CSS build system](css-build-system.md).

Details on each config can be found in [`webpack-configs.js`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/bin/webpack-configs.js). Entry points are declared in [`webpack-entries.js`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/bin/webpack-entries.js).

## Environment variables

Different builds are generated depending on the variable `NODE_ENV`. It can have two values: `production` or `development`. Production builds include tree-shaking, minification and other performance enhancements, while development builds are focused on development and include source maps. You can read more about [environment variables](https://webpack.js.org/guides/environment-variables/) in Webpack docs.

## Babel

Most of our code is transpiled by Babel. This allows us to use the latest JavaScript technologies without affecting browser support.

... (63 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/contributors/javascript-testing.md">
# JavaScript Testing <!-- omit in toc -->

## Table of contents <!-- omit in toc -->

-   [How to run JavaScript unit tests](#how-to-run-javascript-unit-tests)
-   [How to run end-to-end tests](#how-to-run-end-to-end-tests)
    -   [Debugging e2e tests using generated reports](#debugging-e2e-tests-using-generated-reports)
    -   [WordPress versions and end-to-end tests suites](#wordpress-versions-and-end-to-end-tests-suites)

Tests for JavaScript in the Blocks plugin are powered by [Jest](https://jestjs.io/). The Blocks plugin follows the same patterns as Gutenberg, therefore for instructions on writing tests you can [refer to this page in the Gutenberg Handbook](https://developer.wordpress.org/block-editor/contributors/develop/testing-overview/).

We have two kinds of JavaScript tests:

-   JavaScript unit tests - test APIs, hooks, library functionality that we use to build blocks or expose to plugin authors.
-   End-to-end (e2e) tests - test blocks from the user interface.

These tests are all run automatically on open PRs by Travis CI.

All the following tests require that the dependencies are installed (`npm install` `composer install`). Ensure you've followed the [Getting Started Guide](getting-started.md) to set up node and other dependencies before running any tests.

## How to run JavaScript unit tests

Unit tests are implemented near the code they test, in `*.test.js` files.

Use the following command to run the unit tests:

```sh
npm run test
```

... (60 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/contributors/README.md">
# Contributing

If you're a developer or contributor eager to get started with WooCommerce Block Development, this documentation folder is your perfect starting point.

## Navigating this section

### [Getting Started](getting-started.md)

The [Getting Started](getting-started.md) guide is your first step in this journey. This document provides comprehensive information about the tooling you'll need and the process of creating builds during the development phase.

### [Coding Guidelines](coding-guidelines.md)

A set of guidelines exist to ensure development consistency and quality. The [Coding Guidelines](coding-guidelines.md) doc is your resource for understanding these best practices.

### [JavaScript Testing](javascript-testing.md)

Testing plays a crucial role in development. Our [JavaScript Testing](javascript-testing.md) guide will walk you through the process of running automated JavaScript tests, providing a robust framework to ensure your code meets the requisite standards.

### [E2E Testing Guidelines](e2e-guidelines.md)

The [E2E Testing Guidelines](e2e-guidelines.md) document offers a detailed understanding of the best practices related to End-to-End tests. E2E testing is a critical aspect of ensuring overall system integrity and functionality.

### [Developing Components (& Storybook)](components.md)

For insight into our reusable components, their usage, and how to test them in Storybook, refer to the [Developing Components (& Storybook)](components.md) guide.

### [Block Script Assets](block-assets.md)

The [Block Script Assets](block-assets.md) document elucidates how Block Script Assets are loaded and used in the development process. This guide is vital to understanding the role of script assets in block development.

... (18 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/contributors/storybook-and-components.md">
# Storybook & Components <!-- omit in toc -->

## Table of contents <!-- omit in toc -->

-   [Where are our components?](#where-are-our-components)
-   [How to run Storybook locally and test components](#how-to-run-storybook-locally-and-test-components)
-   [How to add a story for a component](#how-to-add-a-story-for-a-component)

This repo includes [Storybook](https://storybook.js.org) tooling so we can test and develop components in isolation. The storybook is automatically built and published to [GitHub pages](https://woocommerce.github.io/woocommerce-blocks/) on every push to the main branch.

## Where are our components?

We have components in a few folders, for different contexts.

-   [`assets/js/base/components`](../../assets/js/base/components)
-   [`assets/js/editor-components`](../../assets/js/editor-components)
-   [`assets/js/icons`](../../assets/js/icons)

**`assets/js/base/components`** are used in front-end code, as well as editor & admin.
These components help us build consistent interfaces across the front end (shopper) experience and elsewhere.
Because they can be used in the front end and editor, components in this folder should:

-   Perform efficiently - i.e. not adversely affect page performance/experience.
-   Have lean dependencies - i.e. not bloat the payload unnecessarily.
-   Look consistent in common themes; ideally should allow themes to adjust appearance as necessary.

**`assets/js/editor-components`** are used in the editor UI for our blocks.
They allow us to build a consistent and powerful UI for merchants for authoring content relating to Woo data - e.g. selecting products or product attributes. Because they are focused on the editor, they can rely on known editor dependencies and optimise styling for the editor only.

**`assets/js/icons`** is a suite of icons and SVG images that we use in our interfaces.
... (26 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/designers/theming/class-names-update-280.md">
# Class names update in 2.8.0 <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

-   [Replaced classes](#replaced-classes)
-   [Deprecated classes](#deprecated-classes)

In [WooCommerce Blocks 2.8.0](https://developer.woocommerce.com/2020/06/24/woocommerce-blocks-2-8-release-notes/), we replaced and deprecated some some class names to simplify them, fix inconsistencies, and make it easier to differentiate frontend components from editor components.

## Replaced classes

Some classes that were introduced in 2.6.0 and 2.7.0 and didn't ship in WooCommerce Core have been replaced by new ones. They can be found in this table:

| Removed                                | New class name                                        |
| -------------------------------------- | ----------------------------------------------------- |
| `wc-block-address-form`                | `wc-block-components-address-form`                    |
| `wc-block-checkout-form`               | `wc-block-components-checkout-form`                   |
| `wc-block-checkout-step`               | `wc-block-components-checkout-step`                   |
| `wc-block-cart__payment-method-icons`  | `wc-block-components-payment-method-icons`            |
| `wc-blocks-payment-method-icon`        | `wc-block-components-payment-method-icon`             |
| `wc-block-cart__payment-method-label`  | `wc-block-components-payment-method-label`            |
| `wc-block-low-stock-badge`             | `wc-block-components-product-low-stock-badge`         |
| `wc-block-product-metadata`            | `wc-block-components-product-metadata`                |
| `wc-block-product-name`                | `wc-block-components-product-name`                    |
| `wc-block-product-price`               | `wc-block-components-product-price`                   |
| `wc-block-product-price--regular`      | `wc-block-components-product-price__regular`          |
| `wc-block-sale-badge`                  | `wc-block-components-sale-badge`                      |
| `wc-block-product-variation-data`      | `wc-block-components-product-variation-data`          |
| `wc-block-cart__shipping-calculator`   | `wc-block-components-shipping-calculator`             |
| `wc-block-shipping-calculator`         | `wc-block-components-shipping-calculator`             |
... (70 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/designers/theming/class-names-update-330.md">
# Class names update in 3.3.0

In [WooCommerce Blocks 3.3.0](https://developer.woocommerce.com/2020/09/02/woocommerce-blocks-3-3-0-release-notes/), we introduced express payment methods in the Cart block. In order to make it easy to write styles for express payment methods for the Cart and Checkout blocks separately, we updated several class names:

## Replaced classes

| Removed                                                      | New class name                                                                 |
| ------------------------------------------------------------ | ------------------------------------------------------------------------------ |
| `wc-block-components-express-checkout`                       | `wc-block-components-express-payment` (generic)                                |
| `wc-block-components-express-checkout`                       | `wc-block-components-express-payment--checkout` (Checkout block)               |
| `wc-block-components-express-checkout`                       | `wc-block-components-express-payment--cart` (Cart block)                       |
| `wc-block-components-express-checkout__title-container`      | `wc-block-components-express-payment__title-container`                         |
| `wc-block-components-express-checkout__title`                | `wc-block-components-express-payment__title`                                   |
| `wc-block-components-express-checkout__content`              | `wc-block-components-express-payment__content`                                 |
| `wc-block-components-express-checkout-continue-rule`         | `wc-block-components-express-payment-continue-rule` (generic)                  |
| `wc-block-components-express-checkout-continue-rule`         | `wc-block-components-express-payment-continue-rule--checkout` (Checkout block) |
| `wc-block-components-express-checkout-continue-rule`         | `wc-block-components-express-payment-continue-rule--cart` (Cart block)         |
| `wc-block-components-express-checkout-payment-event-buttons` | `wc-block-components-express-payment__event-buttons`                           |

<!-- FEEDBACK -->

---

[We're hiring!](https://woocommerce.com/careers/) Come work with us!

🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce/issues/new?assignees=&labels=type%3A+documentation&template=suggestion-for-documentation-improvement-correction.md&title=Feedback%20on%20./docs/designers/theming/class-names-update-330.md)

<!-- /FEEDBACK -->
</file>

<file path="plugins/woocommerce/client/blocks/docs/designers/theming/class-names-update-340.md">
# Class names update in 3.4.0

In [WooCommerce Blocks 3.4.0](https://developer.woocommerce.com/2020/09/15/woocommerce-blocks-3-4-0-release-notes/), we replaced the class as listed below.

## Replaced classes

| Removed                             | New class name            |
| ----------------------------------- | ------------------------- |
| `wc-block-components-checkout-form` | `wc-block-checkout__form` |

<!-- FEEDBACK -->

---

[We're hiring!](https://woocommerce.com/careers/) Come work with us!

🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce/issues/new?assignees=&labels=type%3A+documentation&template=suggestion-for-documentation-improvement-correction.md&title=Feedback%20on%20./docs/designers/theming/class-names-update-340.md)

<!-- /FEEDBACK -->
</file>

<file path="plugins/woocommerce/client/blocks/docs/designers/theming/class-names-update-460.md">
# Class names update in 4.6.0

In [WooCommerce Blocks 4.6.0](https://developer.woocommerce.com/2021/03/02/woocommerce-blocks-4-6-0-release-notes/) we replaced the classes as listed below.

## Replaced classes

| Removed                                   | New class name                           |
| ----------------------------------------- | ---------------------------------------- |
| `wc-blocks-components-panel`              | `wc-block-components-panel`              |
| `wc-blocks-components-panel__button`      | `wc-block-components-panel__button`      |
| `wc-blocks-components-panel__button-icon` | `wc-block-components-panel__button-icon` |
| `wc-blocks-components-panel__content`     | `wc-block-components-panel__content`     |

<!-- FEEDBACK -->

---

[We're hiring!](https://woocommerce.com/careers/) Come work with us!

🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce/issues/new?assignees=&labels=type%3A+documentation&template=suggestion-for-documentation-improvement-correction.md&title=Feedback%20on%20./docs/designers/theming/class-names-update-460.md)

<!-- /FEEDBACK -->
</file>

<file path="plugins/woocommerce/client/blocks/docs/designers/theming/filter-blocks.md">
# Filter blocks

> [!IMPORTANT]
> We strongly discourage writing CSS code based on existing block class names and prioritize using global styles when possible. We especially discourage writing CSS selectors that rely on a specific block being a descendant of another one, as users can move blocks around freely, so they are prone to breaking. Similar to WordPress itself, we consider the HTML structure within components, blocks, and block templates to be “private”, and subject to further change in the future, so using CSS to target the internals of a block or a block template is _not recommended or supported_.

## Price slider accent color

The Filter by Price block includes a price slider which uses an accent color to show the selected range.

![Price filter screenshot](https://user-images.githubusercontent.com/3616980/96570001-2053f900-12ca-11eb-8a75-8a54f243bda3.png)

By default, it uses the WooCommerce purple shade, but it can be easily modified by themes with the following code:

```css
.wc-block-components-price-slider__range-input-progress,
.rtl .wc-block-components-price-slider__range-input-progress {
	--range-color: #ee6948;
}
```

![Price filter screenshot with custom styles](https://user-images.githubusercontent.com/3616980/96569858-f0a4f100-12c9-11eb-8011-05227bb60277.png)

Notice the code snippet above uses a CSS custom property, so the default color might still be available in some browsers that don't support it like Internet Explorer 11. If your theme supports IE11, you can add the following lines to target it:

```css
/* Target only IE11 */
@media all and ( -ms-high-contrast: none ), ( -ms-high-contrast: active ) {
	.wc-block-components-price-slider__range-input-progress {
		background: #ee6948;
	}
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/designers/theming/product-grid-270.md">
# Product grid blocks style update in 2.7.0 <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

-   [Product images](#product-images)
-   [All Products prices](#all-products-prices)

In WC Blocks 2.7.0, some of the styles of the product grid blocks were updated to make the experience more consistent. Below, there are CSS code snippets that can undo those changes.

## Product images

Images in product grid blocks changed so they expand to occupy all the available horizontal space if they are small. This can be undone with this CSS snippet:

```css
.wc-block-grid__products .wc-block-grid__product-image img {
	width: auto;
}
```

## All Products prices

_All Products_ block was updated so prices follow the same layout as the other product grid blocks (one line instead of two lines). It's possible to recover the old style with:

```css
.wc-block-grid__product-price .wc-block-grid__product-price__regular {
	font-size: 0.8em;
	line-height: 1;
	color: #555;
	margin-top: -0.25em;
	display: block;
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/examples/checkout-order-processed.md">
# Checkout Order Processed

```php
// The action callback function.
function my_function_callback( $order ) {
  // Do something with the $order object.
  $order->save();
}

add_action( 'woocommerce_store_api_checkout_order_processed', 'my_function_callback', 10 );
```
</file>

<file path="plugins/woocommerce/client/blocks/docs/examples/payment-gateways-features-list.md">
# Payment Gateway Featured List

```php
// The action callback function.
function my_function_callback( $features, $gateway ) {
    if ( 'my-gateway' !== $gateway->id ) {
			return $features;
		}
    $features[] = 'some-feature';
    return $features;
}

add_filter( '__experimental_woocommerce_blocks_payment_gateway_features_list', 'my_function_callback', 10, 2 );
```
</file>

<file path="plugins/woocommerce/client/blocks/docs/examples/validate-cart.md">
# Validate Cart

```php
// The action callback function.
function my_function_callback( $errors, $cart ) {

  // Validate the $cart object and add errors. For example, to create an error if the cart contains more than 10 items:
  if ( $cart->get_cart_contents_count() > 10 ) {
    $errors->add( 'my_error_code', 'Too many cart items!' );
  }
}

add_action( 'woocommerce_store_api_cart_errors', 'my_function_callback', 10 );
```
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/automations/dependabot.md">
# Dependabot

This repository uses [`Dependabot`](https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates) to help with keeping all the package dependencies (NPM, Composer, GitHub Actions) up to date. Without this in place, it's very easy to let the package versions we're using go stale and end up with a backlog of chores for updating those in the future. It is essential to keep dependencies updated to avoid security problems and lower overall upgrade costs.
The process is automated: Dependabot creates a branch and a PR with a package bump in package.json. A new package-lock.json is created. Automated tests are executed. Also, Dependabot will create a maximum of 10 PRs for each ecosystem (NPM, Composer, GitHub Actions).

It is the responsibility of the porter to review these PRs weekly and merge/reject them.

Dependabot's configuration is located at [`.github/dependabot.yml` path](https://github.com/woocommerce/woocommerce-blocks/blob/trunk/.github/dependabot.yml).

## Auto-merge

This repository also has auto-merge enabled for selected dev dependencies. Debendabot will automatically merge pull requests that pass all the required checks and meet the defined merge criteria, helping us to streamline the process of keeping dependencies up to date even further.

The list of dependencies marked for auto-merge can be found at [`.github/workflows/auto-merge-dependabot.yml`](https://github.com/woocommerce/woocommerce-blocks/blob/trunk/.github/workflows/auto-merge-dependabot.yml).
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/automations/README.md">
# Automatations

This directory contains documentation for all the automations configured in this repository.

| Document                    | Description                             |
| --------------------------- | --------------------------------------- |
| [Dependabot](dependabot.md) | This doc explains how Dependabot works. |
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/block-client-apis/checkout/checkout-api.md">
# Checkout API interface <!-- omit in toc -->

**Note on migration:** We are in the process of moving much of the data from contexts into data stores, so this portion of the docs may change often as we do this. We will try to keep it up to date while the work is carried out.

## Table of Contents <!-- omit in toc -->

-   [Data Stores](#data-stores)
    -   [Checkout Data Store](#checkout-data-store)
        -   [Selectors](../../../third-party-developers/extensibility/data-store/checkout.md#selectors)
        -   [Actions](#actions)
-   [Contexts](#contexts)
    -   [Shipping Method Data context](#shipping-method-data-context)
    -   [Payment Method Events Context](#payment-method-events-context)
    -   [Checkout Events Context](#checkout-events-context)
-   [Hooks](#hooks)
    -   [`usePaymentMethodInterface`](#usepaymentmethodinterface)
-   [Examples](#examples)
    -   [Passing a value from the client through to server side payment processing](#passing-a-value-from-the-client-through-to-server-side-payment-processing)

This document gives an overview of some of the major architectural components/APIs for the checkout block. If you haven't already, you may also want to read about the [Checkout Flow and Events](https://developer.woocommerce.com/docs/cart-and-checkout-checkout-flow-and-events/).

## Data Stores

We are transitioning much of what is now available in Contexts, to `@wordpress/data` stores.

### Checkout Data Store

This is responsible for holding all the data required for the checkout process.

For more details on the checkout data store, see the [Checkout Data Store](../../../third-party-developers/extensibility/data-store/checkout.md) docs.
... (191 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/block-client-apis/notices.md">
# Frontend notices <!-- omit in toc -->

## Table of contents <!-- omit in toc -->

-   [Notices in WooCommerce Blocks](#notices-in-woocommerce-blocks)
    -   [`StoreNoticesContainer`](#storenoticescontainer)
-   [Snackbar notices in WooCommerce Blocks](#snackbar-notices-in-woocommerce-blocks)

## Notices in WooCommerce Blocks

WooCommerce Blocks uses the [`@wordpress/notices`](https://github.com/WordPress/gutenberg/blob/d9eb36d80e05b4e45b1ad8462c8bace4e9cf1f6f/docs/reference-guides/data/data-core-notices.md) package to display notices in the frontend. For more information on the actions and selectors available on this data store, please review [the `@wordpress/notices` documentation](https://github.com/WordPress/gutenberg/blob/d9eb36d80e05b4e45b1ad8462c8bace4e9cf1f6f/docs/reference-guides/data/data-core-notices.md)

### `StoreNoticesContainer`

To display notices of a certain context, use the `StoreNoticesContainer` and pass the context as a prop to it.

The below example will show all notices with type `default` that are in the `wc/cart` context. If no context prop is passed, then the `default` context will be used.

On the Cart Block, a `StoreNoticesContainer` is already rendered with the `wc/cart` context, and on the Checkout Block, a `StoreNoticesContainer` is already rendered with the `wc/checkout` context. To display errors from other contexts, you can use the `StoreNoticesContainer` component with context passed as a prop.

`StoreNoticesContainer` also support passing an array of context strings to it, this allows you to capture several contexts at once, while filtering out similar notices.

#### Single context

```jsx
const { StoreNoticesContainer } = window.wc.blocksCheckout;

const PaymentErrors = () => {
	return <StoreNoticesContainer context="wc/payment" />;
};
... (46 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/block-client-apis/README.md">
# Block Client APIs

This folder contains documentation for API interfaces for Blocks. In _most cases_, these docs describe APIs and interfaces that are _internal_ only, and thus are provided to assist with developing the blocks in this repository. Documentation will tend to focus on high level overviews.

| Document | Description |
| --- | --- |
| [Checkout API interface](checkout/checkout-api.md) | Describes API details for the Checkout block architecture. |
| [Unified editor assets](../enqueueable-packages/README.md) | Explains the default and experimental editor asset configurations, external package boundaries, and compatibility handles. |
| [Notices](notices.md) | Explains how the notices system works and which methods can add and remove notices. |

Some of the resources from this directory were migrated to WooCommerce Developer Documentation:

- [Checkout Flow and Events](https://developer.woocommerce.com/docs/cart-and-checkout-checkout-flow-and-events/)

For more details about extensibility points in the blocks, you can reference the extensibility docs:

- [Data Store](../../third-party-developers/extensibility/data-store/README.md)
- [Hooks](../../third-party-developers/extensibility/hooks/README.md)
- [Extending the Store API](../../third-party-developers/extensibility/rest-api/README.md)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/blockified-templates/compatibility-layer.md">
# Compatibility Layer - [AbstractTemplateCompatibility.php](https://github.com/woocommerce/woocommerce-blocks/blob/trunk/src/Templates/AbstractTemplateCompatibility.php)

The Compatibility Layer ensures that blockified templates work correctly with extensions that use hooks to extend their behavior. It appends/pre-appends the corresponding hooks to each block. Also, it removes the default callbacks added to those hooks by WooCommerce.

A limitation of the Compatibility Layer is the order of hook execution. Blocks are rendered from the innermost to the outermost, meaning inner blocks are rendered first. This may cause the execution order of hooks to differ from that of the classic template.

The Compatibility Layer is disabled when either of classic template blocks are added on the page:

- `Product (Classic)`,
- `Product Attribute (Classic)`,
- `Product Category (Classic)`,
- `Product Tag (Classic)`,
- `Product's Custom Taxonomy (Classic)`,
- `Product Search Results (Classic)`,
- `Product Grid (Classic)`.

Please note these blocks represent classic templates. As an example, using Single Product block won't disable Compatibility Layer.

Furthermore, it is possible to disable the compatibility layer via the hook: [`woocommerce_disable_compatibility_layer`](https://github.com/woocommerce/woocommerce-blocks/blob/trunk/src/Templates/AbstractTemplateCompatibility.php/#L41-L42).

## Archive Product Templates - [ArchiveProductTemplatesCompatibility](https://github.com/woocommerce/woocommerce-blocks/blob/trunk/src/Templates/ArchiveProductTemplatesCompatibility.php)

The compatibility is built around the Product Collection block because the loop is the main element of archive templates and hooks are placed inside and around the loop. The Compatibility Layer injects custom attributes for the Product Collection block that **inherit query from the template** and their inner blocks.

The following table shows where the hooks are injected into the page.


| Hook Name                               | Block Name       | Position |
|-----------------------------------------|------------------|----------|
| woocommerce_before_main_content         | Products         | before   |
... (32 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md">
# Feature Flags and Experimental Interfaces <!-- omit in toc -->

WooCommerce Blocks uses feature flags to control access to in-progress features and experimental prefixes to identify interfaces that can change without notice. These are separate concepts: a feature can be behind a flag without exposing an experimental interface, and an experimental interface can remain available regardless of a feature flag.

This document covers flags used by Blocks and WooCommerce-owned experimental interfaces in the Blocks and Store API code. It does not inventory experimental components, properties, or supports imported from WordPress packages. The source code linked below remains the source of truth.

## Feature flags

WooCommerce currently uses two feature-flag systems in Blocks:

- Build-configured flags are defined for each build environment in the [WooCommerce Admin configuration](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/client/admin/config) and checked with `Automattic\WooCommerce\Admin\Features\Features::is_enabled()`.
- Runtime feature definitions are registered in [`FeaturesController`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Internal/Features/FeaturesController.php), exposed on the **WooCommerce > Settings > Advanced > Features** screen when applicable, and checked with `FeaturesUtil::feature_is_enabled()`.

### Build-configured flags

| Flag | Defaults | Current Blocks usage |
| --- | --- | --- |
| `experimental-blocks` | Enabled in [development](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/admin/config/development.json) and disabled in [core builds](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/admin/config/core.json). | Exposed to the editor through [`isExperimentalBlocksEnabled()`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/assets/js/settings/blocks/feature-flags.ts). It currently gates the **Disable product descriptions** editor control in Checkout Order Summary Cart Items. It does not determine which block scripts webpack builds or which general block types are registered. |
| `rest-api-v4` | Disabled in both development and core build configurations. | Exposed through [`isExperimentalWcRestApiV4Enabled()`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/assets/js/settings/blocks/feature-flags.ts). It switches product entities from `/wc/v3/products` to `/wc/v4/products`, registers the settings entity, and enables the v4 product-data paths used by Product Price and Product Button in the editor. |

### Runtime feature flags

These flags are experimental, disabled by default, and registered in [`FeaturesController`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Internal/Features/FeaturesController.php).

| Flag | Current Blocks usage |
| --- | --- |
| `cart_save_for_later` | Registers the `woocommerce/saved-for-later` block through [`BlockTypesController`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Blocks/BlockTypesController.php), enables the related shopper-list APIs, and exposes the Save for later action in Cart when the block is present. |
| `product_wishlist` | Registers the `woocommerce/wishlist` and `woocommerce/add-to-wishlist-button` blocks and enables the related shopper-list APIs and My Account endpoint. |
| `wc-visual-attribute` | Enables the experimental `wc-visual` product attribute type for block themes. The Product Filters and Add to Cart + Options blocks read the resulting attribute data to display visual variation choices. |

... (186 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/blocks/inner-block-protocols.md">
# Inner Block Protocols

> **Experimental:** These protocols are internal and may change without notice.

WooCommerce reusable inner blocks use small context protocols so they can render UI for different parent blocks without coupling to a specific parent store.

| Context key | Purpose | Inner blocks |
| --- | --- | --- |
| `woocommerce/selectableItems` | Select/deselect items (filters, variation attributes) | checkbox-list, chips, dropdown |
| `woocommerce/removableItems` | Remove individual items (active filters) | removable-chips |
| `woocommerce/rangeInput` | Numeric range input (price, slider) | price-slider |

## Shared pattern

- Parent provides protocol context and owns business state.
- Inner block reads the protocol context, renders UI, and calls fixed parent actions.
- Every context includes `storeNamespace`, which points to the parent Interactivity API store.
- Parent stores expose protocol-scoped getters such as `state.selectableItems` or `state.removableItems`; generic `state.items` is avoided so protocols can coexist.
- Parent stores should assert conformance with the matching `*ParentStore` TypeScript interface via `satisfies`.
- Inner blocks may derive presentation-only data locally. Parent data should not include child-owned fields such as list indexes.
- Server-rendered fallback items use `data-wp-each-child` with per-item `data-wp-context`; hydration reconciles them with the inner store.

## Display styles

A display style block is an inner block that renders a protocol context for a specific parent block. Display style blocks opt in through block support metadata:

```json
{
    "supports": {
        "woocommerce": {
... (196 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/blocks/README.md">
# Blocks

This folder contains documentation for specific Blocks and Blocks functionality.

| Document                                                                                  | Description                                                                                                    |
| ----------------------------------------------------------------------------------------  | -------------------------------------------------------------------------------------------------------------- |
| [Stock Reservation during Checkout](stock-reservation.md)                                 | This doc covers the Checkout Stock Reservation system.                                                         |
| [Feature Flags and Experimental Interfaces](feature-flags-and-experimental-interfaces.md) | This doc describes current Blocks feature flags and experimental interface.                                    |
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/blocks/stock-reservation.md">
# Stock Reservation during Checkout <!-- omit in toc -->

## Table of contents <!-- omit in toc -->

-   [The Reserved Stock Database Table](#the-reserved-stock-database-table)
    -   [Usage Example](#usage-example)
    -   [What about concurrency?](#what-about-concurrency)
-   [The Reserve Stock Process](#the-reserve-stock-process)
    -   [How the queries work](#how-the-queries-work)
-   [How this all fits into Checkout Block vs Traditional Checkout](#how-this-all-fits-into-checkout-block-vs-traditional-checkout)

To prevent multiple customers trying to purchase the same stock when limits are in place, both WooCommerce ([4.3+](https://github.com/woocommerce/woocommerce/pull/26395#pullrequestreview-430633490)) and the Blocks plugin have a stock reservation system which is used during checkout.

## The Reserved Stock Database Table

The table which tracks reserved stock is named `wc_reserved_stock`, and the schema contains the following columns:

| Key              | Type         | Description                         |
| ---------------- | ------------ | ----------------------------------- |
| `order_id`       | `bigint(20)` | ID of the order.                    |
| `product_id`     | `bigint(20)` | ID of the product or variation.     |
| `stock_quantity` | `double`     | The amount of stock reserved.       |
| `timestamp`      | `datetime`   | The timestamp the hold was created. |
| `expires`        | `datetime`   | The timestamp the hold expires.     |

The primary key is a combination of order and product ID to prevent multiple holds being created for the same order if checkout is performed multiple times.

### Usage Example

This example shows how stock would be reserved programmatically for an order using the `ReserveStock` class which acts as an interface between the checkout and the `wc_reserved_stock` table.
... (73 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/data-store/checkout.md">
# Checkout Store <!-- omit in toc -->

See also [third-party developers' Checkout Store documentation](../../third-party-developers/extensibility/data-store/checkout.md).

The checkout data store is used to track the status of the **checkout** (not including payment), it stores things like the order ID, the customer ID, the order notes, whether the "use shipping as billing" box is checked etc.

The initial state of the checkout store is:

```js
{
	redirectUrl: '',
	status: STATUS.PRISTINE,
	hasError: false,
	orderId: checkoutData.order_id,
	customerId: checkoutData.customer_id,
	calculatingCount: 0,
	orderNotes: '',
	useShippingAsBilling: isSameAddress(
	checkoutData.billing_address,
	checkoutData.shipping_address
	),
	shouldCreateAccount: false,
	extensionData: {},
};
```

## Properties

-   `redirectUrl` - Set when the checkout is completed. The payment method being used can set this, and it will be sent back to the block in the checkout response.
-   `status` - one of:
... (20 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/data-store/README.md">
# Data stores in WooCommerce Blocks <!-- omit in toc -->

## Table of contents <!-- omit in toc -->

-   [Checkout](./checkout.md)
-   [Validation](./validation.md)

In our project, we leverage [`@wordpress/data`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/) data stores to hold information about the state of various WooCommerce blocks.

More information on the actions and selectors available on each data store can be found in the [third-party developer's data store documentation](../../third-party-developers/extensibility/data-store).
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/data-store/validation.md">
# Validation Store <!-- omit in toc -->

See also [third-party developers' Validation Store documentation](../../third-party-developers/extensibility/data-store/validation.md).

The `wc/store/validation` store contains information about the current validity, visibility, and associated error message of _something_.

That _something_ is usually a field in the Checkout form, however the data store can be leveraged in other creative ways.

The data store begins as an empty object. Using the `setValidationErrors` action, errors can be added to the store.

An error is represented by an object and contains two entries, `hidden` and `message`. `hidden` is used by our code to determine whether to show an error or not. Other extensions reading the data store may not honour this and show it anyway regardless of if it is hidden. `message` contains the message to show to the user.

When the Checkout block loads, various entries are added to the data store for each required field that does not already have a value. These errors have the `hidden` property set to `true`.

<img width="478" alt="image" src="https://user-images.githubusercontent.com/5656702/210558764-cc271b30-03a0-444f-8cac-4c16179c8165.png">

The reason for this is so we can show an error if a required field is not completed, but showing these errors immediately on page load would be a bad user experience, we keep them hidden until the user interacts with the field, or tries to submit the form.

When the "Place order" button is pressed, the [checkout processor reads the value of `hasValidationErrors`](https://github.com/woocommerce/woocommerce-blocks/blob/4ead2e9a6ee567a3a868feae988c6c21edd00d12/assets/js/base/context/providers/cart-checkout/checkout-processor.ts#L160) and if it returns true then the checkout process is aborted.

Any fields that were hidden get shown when the "Place order" button is pressed too. This is done using `showAllValidationErrors`. [See the code here](https://github.com/woocommerce/woocommerce-blocks/blob/4ead2e9a6ee567a3a868feae988c6c21edd00d12/assets/js/blocks/checkout/block.tsx#L139)

The Checkout processor does not discriminate between errors added by WooCommerce Blocks, and those added by extensions. If the store contains any errors at all, then the checkout will halt and those errors will be shown.

Errors are explicitly shown. i.e. we don't arbitrarily display errors in the data store. Instead, we render specific errors in the place they belong by using their ID. For example, in the checkout form we use [`ValidatedTextInput`s](https://github.com/woocommerce/woocommerce-blocks/blob/2848a4b11025d9095511c6a92e68f4a2d05d21da/packages/checkout/components/text-input/validated-text-input.tsx) which have a [`ValidationInputError`](https://github.com/woocommerce/woocommerce-blocks/blob/d8ff1ce08a17a29d9f63a6fa4eeb894eea5dd609/packages/checkout/components/validation-input-error/index.tsx) component associated with them. The text input has an ID, and the associated `ValidationInputError` renders the error with that ID.
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/enqueueable-packages/README.md">
# WooCommerce Blocks editor assets

WooCommerce includes an experimental configuration that replaces its per-block editor scripts and styles with shared editor assets. The experiment is disabled by default, so existing per-block assets and handles continue to work unchanged.

Enable **Unified block editor assets** under **WooCommerce > Settings > Advanced > Features** to test the shared configuration. The feature flag is `block_editor_unified_assets`, its setting is stored in `woocommerce_feature_block_editor_unified_assets_enabled`, and changes take effect on the next request.

## Asset configurations

### Default

When the experiment is disabled, WooCommerce uses:

- Per-block scripts such as `wc-cart-block` and `wc-checkout-block`.
- Per-block styles declared by block metadata.
- The `wc-blocks-vendors` and `wc-blocks` bundles.
- The `wc-blocks-editor-style` stylesheet.

### Unified

When the experiment is enabled, WooCommerce block types use:

| Handle | Type | What it contains |
| --- | --- | --- |
| `wc-block-library` | Script | WooCommerce block editor entry points and internal package imports. |
| `wc-block-library-style` | Stylesheet | Editor styles for blocks shipped by WooCommerce. Styles registered by third-party blocks remain separate. |

These assets replace WooCommerce's per-block editor assets. They do not combine every script loaded by the editor: shared WordPress dependencies and the enqueueable WooCommerce packages below remain external.

The legacy per-block handles, such as `wc-cart-block` and `wc-checkout-block`, remain registered as compatibility placeholders. They preserve their dependency on `wc-blocks` but do not load the former per-block files, and log a deprecation warning when enqueued.

... (58 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/rest-api/extend-rest-api-new-endpoint.md">
# Adding an endpoint to ExtendSchema <!-- omit in toc -->

## Table of contents <!-- omit in toc -->

-   [Extending `GET` endpoints in Store API](#extending-get-endpoints-in-store-api)
-   [Use cases for adding new endpoints](#use-cases-for-adding-new-endpoints)
    -   [Extending an existing schema](#extending-an-existing-schema)
    -   [Adding a new schema](#adding-a-new-schema)

This document is intended for internal developers of the WooCommerce Blocks plugin. If you feel like a new endpoint should be added, feel free to open an issue or a PR detailing why.

## Extending `GET` endpoints in Store API

ExtendSchema needs to expose each endpoint individually. If you want to expose a new endpoint, you have to follow these steps:

1. In `ExtendSchema` class, add your endpoint `IDENTIFIER` to the `$endpoints` variable.

```php

use Automattic\WooCommerce\StoreApi\Schemas\BillingAddressSchema;

private $endpoints = [ /* other identifiers */, BillingAddressSchema::IDENTIFIER ];

```

This is to prevent accidentally exposing new endpoints.

2. Inside your endpoint schema class (for this example, inside `BillingAddressSchema`), in its `get_properties` method, add this call at the end of the returned array.

You can pass extra parameters to `get_extended_schema` and those would be passed to third party code.
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/rest-api/README.md">
# REST API

| Document                                                                | Description                                                                        |
| ----------------------------------------------------------------------- |------------------------------------------------------------------------------------|
| [Adding an endpoint to ExtendSchema](./extend-rest-api-new-endpoint.md) | A step by step process for contributors to expose a new endpoint via ExtendSchema. |
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/templates/block-template-controller.md">
# BlockTemplateController.php <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

-   [Overview](#overview)
-   [add_block_templates( $query_result, $query, \$template_type )](#add_block_templates-query_result-query-template_type-)
-   [get_block_file_template( $template, $id, \$template_type )](#get_block_file_template-template-id-template_type-)

The `BlockTemplateController` class contains all the business logic which loads the templates into the Site Editor or on the front-end through various hooks available in WordPress & WooCommerce core. Without documenting every method individually, I will look to provide some insight into key functionality.

## Overview

In the initialization of the class, we hook into the three hooks listed below. These provide us with all of the extensibility points necessary in order to load our own block templates alongside the themes.

Within each method section, I will explain in what scenarios they are executed.

-   filter: `get_block_templates` with `add_block_templates`.
-   filter: `pre_get_block_file_template` with `get_block_file_template`.
-   action: `template_redirect` with `render_block_template`.

## add_block_templates( $query_result, $query, \$template_type )

This method is applied to the filter `get_block_templates`, which is executed before returning a unified list of template objects based on a query.

**Typically executed when:**

-   Loading the "All Templates" view in the Site Editor
-   Loading one of the templates on the front-end where the query would build a list of relevant templates based on a hierarchy (for example, the product page hierarchy could be an array containing `single-product-[product-name].html`, `single-product.html`, `single.html`).
-   Loading the "Edit Product" view.

... (34 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/templates/classic-template.md">
# ClassicTemplate.php <!-- omit in toc -->

Please read the [Classic Template block docs](../../../assets/js/blocks/classic-template/README.md) for information about the `ClassicTemplate.php` file.
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/templates/individual-template-classes.md">
# Individual template classes <!-- omit in toc -->

Each WooCommerce template has its own individual PHP class, which are all registered in BlockTemplatesRegistry.

## Overview

These classes have several purposes:

* define the template metadata like title and description
* hook into `template_redirect` to decide when to render the template (more on this below)
* any other hook or logic specific to that template

## render_block_template()

This method is applied to the filter `template_redirect` and executed before WordPress determines which template to load.

This allows us to hook into WooCommerce core through the filter `woocommerce_has_block_template` where we can determine if the block template should be loaded.

**Typically executed when:**

* A user loads a page on the front-end.

**This method is responsible for:**

* Determining if the block template has to be rendered in the current page. If so, we override the value through `woocommerce_has_block_template` to resolve `true`.
* Determining if the page that will be rendered contains a Legacy Template block, in which case we disable the compatibility layer through the `woocommerce_disable_compatibility_layer` filter.
* Running other template-specific logic.

**Return value:**

... (2 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/templates/README.md">
# Templates <!-- omit in toc -->

## Table of contents <!-- omit in toc -->

-   [Overview](#overview)
    -   [Requirements](#requirements)
-   [Technical Overview](#technical-overview)
    -   [The Problem](#the-problem)
    -   [The Solution](#the-solution)
    -   [Some things to be aware of](#some-things-to-be-aware-of)
-   [Related files](#related-files)

This page includes documentation related to WooCommerce Block Templates.

## Overview

WooCommerce Block Templates are a collection of WooCommerce Core templates for the WordPress Full Site Editing experience introduced in WordPress 5.9. You can customize these templates in the Site Editor.

You can read more about the [Full Site Editing (FSE) experience](https://developer.wordpress.org/block-editor/getting-started/full-site-editing/) in the docs.

### Requirements

| Software    | Minimum Version                                                                                                                  |
|-------------|----------------------------------------------------------------------------------------------------------------------------------|
| WordPress   | 5.9                                                                                                                              |
| WooCommerce | 6.0                                                                                                                              |
| Theme       | Any [block theme](https://developer.wordpress.org/block-editor/how-to-guides/themes/block-theme-overview/#what-is-a-block-theme) |

## Technical Overview

... (28 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/cart-checkout/compatibility.md">
# Compatibility <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

- [Setup](#setup)
- [What to test](#what-to-test)

The main goal of this is to test in a variety of themes, browsers, platforms, and setups, this is a list of things you can test with, with sane expectations.

## Setup

-   WordPress 5.4 and up.
-   WooCommerce 4.2 and up.
-   [Storefront](https://wordpress.org/themes/storefront/), [Twenty Twenty-Two](https://wordpress.org/themes/twentytwentytwo/), and [Twenty Twenty-One](https://wordpress.org/themes/twentytwentyone/) themes.
-   All Browsers supported by [those two versions](https://make.wordpress.org/core/handbook/best-practices/browser-support/) so this includes Internet Explorer 11, and latest two versions of each browser.

## What to test

Test the WooCommerce Blocks plugin against the versions as listed above.
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/cart-checkout/coupons.md">
# Coupons

## Setup

To conduct these tests, please set up the following coupons:

- `generalCoupon`: A general-purpose coupon
- `expiredCoupon`: An expired coupon
- `emailRestrictedCoupon`: An email-limited coupon, applicable to `*@automattic.com` emails
- `thresholdCoupon`: A cart condition coupon, applicable to carts above a certain threshold (e.g., $200)
- `individualCoupon`: An individually used coupon
- `freeShippingCoupon`: A free shipping coupon

## Test cases

To execute the following test cases, you will need to toggle the coupon functionality. You can enable or disable coupons via `WP Admin » WooCommerce » Settings » General » Enable coupons`:

<img width="650" alt="Screenshot 2023-09-27 at 21 26 30" src="https://github.com/woocommerce/woocommerce-blocks/assets/3323310/b79cbc87-0609-4306-90a0-e6666f738433">

### With coupons disabled

- [ ] Verify that the 'Add Coupon' section is not visible in your cart, checkout, and in the editor.

### With coupons enabled

- [ ] Ensure the ability to apply coupons in both Cart and Checkout blocks.
- [ ] A valid coupon, `generalCoupon`, should accurately reduce your totals.
- [ ] An expired coupon, `expiredCoupon`, should generate an error upon application.
- [ ] Attempting to apply an invalid coupon should generate an error message.
- [ ] An email-limited coupon, `emailRestrictedCoupon`, should be applicable to your cart.
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/cart-checkout/cross-browser.md">
# Cross-platform and browser compatibility

The primary goal here is to conduct tests across a range of themes, browsers, platforms, and setups. Below is a list of elements you can test, with reasonable expectations:

The baseline for testing includes:

-   The latest stable version of WordPress.
-   The latest stable version of WooCommerce.
-   The latest stable core theme (for testing block-themes), and Storefront (for testing classic themes).
-   The latest two versions of [all browsers supported by WordPress](https://make.wordpress.org/core/handbook/best-practices/browser-support/).
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/cart-checkout/data-stores.md">
# Testing

## Payments

In general, perform smoke tests, ensure you can check out with carts containing:

-   Only physical products,
-   Only virtual products,
-   A mix of physical and virtual products,
-   Products on sale,
-   Products with different tax rates.
-   Check out using coupons, and the amount charged to the payment method is correct.

Ensure the amount charged is correct.

### Subscriptions

-   Check out using WooCommerce Subscriptions products, ensure the checkout works and the stripe key is saved to the order.
-   Go to the Subscription in the dashboard, process a renewal for it, ensure the payment goes through and is collected in your stripe account. (This check is to ensure the tokens are saved correctly)

### Stripe failures

Check out using the following cards to ensure following scenarios happen: (use any CVV and expiration date in the future)

-   `4242 4242 4242 4242` - Checkout succeeds
-   `4000 0025 0000 3155` - SCA prompt appears, if you choose to fail, then checkout fails, if you choose to succeed then the checkout succeeds
-   `4000 0082 6000 3178` - Choose to succeed, but the payment should still fail because of insufficient funds
-   `4000 0000 0000 9979`- Checkout fails with generic card error. (This card is marked stolen).

### Express Payment methods
... (159 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/cart-checkout/editor.md">
# Editor experience <!-- omit in toc -->

## What to test

-   [ ] You should be able to add one and only one Cart or Checkout block to a page.
-   [ ] The preview in the inserter should show a skeleton of how the block structure should look like.
-   [ ] When inserting any of the blocks, it should have some data already in it.
-   [ ] You should not be able to interact directly with the block (except for some sections).
-   [ ] You should be able to see block settings on the sidebar when it is focused.
-   [ ] Proceed to Checkout and Back to cart block settings should present you with a list of your website pages.

[![Create Todo list](https://raw.githubusercontent.com/senadir/todo-my-markdown/master/public/github-button.svg?sanitize=true)](https://git-todo.netlify.app/create)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/cart-checkout/general-flow.md">
# General Flows <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

- [Setup](#setup)
- [What to test](#what-to-test)

## Setup

This is a general flow of the main functionality of the blocks without going too much into details, you're expected to set your store as is, with your current flow, products, taxes (if you have any), shipping and so on.

## What to test

-   [ ] Create pages with Cart and Checkout blocks.
-   [ ] Set the continue to checkout link your Cart settings to the Checkout page you created.
-   [ ] In WooCommerce -> Settings -> Advanced, set the new pages to your default Cart and Checkout.
-   [ ] Add some products to your cart.
-   [ ] Mix in a limited stock product or a coupon.
-   [ ] Continue to checkout.
-   [ ] You should be able to fix your info, if you have them saved, they will show up.
-   [ ] Depending on what payment method you enabled (Credit Card, Check, Express payment), you can place the order.
-   [ ] You should see an order received page.

[![Create Todo list](https://raw.githubusercontent.com/senadir/todo-my-markdown/master/public/github-button.svg?sanitize=true)](https://git-todo.netlify.app/create)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/cart-checkout/items.md">
# Cart Items <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

- [Setup](#setup)
- [What to test](#what-to-test)

## Setup

-   You will need an item that is [sold individually](https://docs.woocommerce.com/wp-content/uploads/2016/06/disable-stock-mgmt.png).
-   You will need a low stock item with a [low threshold quantity](https://docs.woocommerce.com/wp-content/uploads/2016/06/simpleproduct-inventory.png) below the stock quantity.
-   You will need a low stock item with a [low threshold quantity](https://docs.woocommerce.com/wp-content/uploads/2016/06/simpleproduct-inventory.png) above 0 and a stock quantity below the threshold.

## What to test

-   [ ] You should be able to add items to your cart.
-   [ ] You should be able to change item quantity in your Cart.
-   [ ] You should not be able to change "sold individually" items quantity.
-   [ ] Items that have quantity lower than the threshold should show "x Left in stock". - [ ] You should not be able to increase that item quantity to above that is left in stock.
-   [ ] If you try to increase an item quantity to above its stock quantity, you get an error. **Note:** This is not something that can be tested with a single browser instance. To test you need to do the following:
    -   [ ] Set a stock of 4 on an item.
    -   [ ] Open tabs in two different browsers (so you have two different sessions in play).
    -   [ ] In both browsers add 1 of that item into the cart.
    -   [ ] In both browsers, load the cart (block).
    -   [ ] In one browser, increase the quantity of that item to the maximum you can.
    -   [ ] In the other browser, try increasing the quantity. An error should appear.
-   [ ] You should be able to remove an item.

[![Create Todo list](https://raw.githubusercontent.com/senadir/todo-my-markdown/master/public/github-button.svg?sanitize=true)](https://git-todo.netlify.app/create)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/cart-checkout/local-pickup.md">
# Local Pickup testing

## Managing Local Pickup

### Enabling local pickup

1. In a fresh website that uses Checkout shortcode as its main Checkout, go to **WooCommerce -> Settings -> Shipping**, you should **not** see a local pickup tab there.
2. Switch to using Checkout block for your main Checkout by removing the shortcode and adding Checkout block.
3. In your Checkout block, you should not see the shipping method toggle or pickup options block.
3. Visit **WooCommerce -> Settings -> Shipping** again, you should see a Local Pickup tab there.
4. You should be able to toggle local pickup on from that screen.
5. In your Checkout page in the editor, you should see your shipping method and pickup options block.

### Adding locations

1. In **WooCommerce -> Settings -> Shipping -> Local Pickup**, you should see Pickup locations section below.
2. If you don't have any pickup locations, you should see the message "When you add a pickup location, it will appear here".
3. Clicking "Add pickup location" should open up a modal.
4. You should be able to fill up the title, address, and details.
5. States would change depending on what country you select.
6. Countries shouldn't be limited to the ones your store sell to, it should provide all possible countries.
7. Hitting save should add a new location.
8. You can repeat the above flow several times for several pickup locations.
9. Persist your changes by hitting "save changes".
10. Refresh the page after you saved, locations you added should be there.

### Editing locations

1. On a location, you can edit it by clicking "edit".
2. The modal will load with the location details.
... (183 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/cart-checkout/payment.md">
# Payments <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

- [Setup](#setup)
    - [Special Cases](#special-cases)
    - [Unsupported](#unsupported)
- [What to test](#what-to-test)

## Setup

The Checkout Block supports three methods of payments:

-   Check Payment, found in WooCommerce payment section.
-   Stripe Credit Card payments, provided by [Stripe Gateway](https://woocommerce.com/products/stripe/).
-   Express Payment methods, provided by [Stripe Gateway](https://woocommerce.com/products/stripe/).

To test Stripe and Express payment methods, you will need API keys, you can get them by creating a testing account in stripe.

### Special Cases

To test Express payment methods there are some special requirements like

-   You need to be serving the website over https, try ephemeral websites.
-   You need to be from a supported country.
-   To test Apple Pay you will need to have an iOS or device.
-   To test Google Pay you will need to have Chrome installed and a payment method setup.
-   To test Microsoft Pay you will need to have Edge installed.
-   You will also need to be on a supported country, to better verify your compatibility visit [this page](https://stripe.com/docs/stripe-js/elements/payment-request-button#react-overview). You should see if you're on a supported platform or not.

... (19 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/cart-checkout/README.md">
# Cart and Checkout testing plan <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

- [Introduction](#introduction)
    - [Known limitations](#known-limitations)
- [How to report issues](#how-to-report-issues)
- [What are we testing?](#what-are-we-testing)
    - [Cart Block](#cart-block)
    - [Checkout Block](#checkout-block)
    - [Data Stores](#data-stores)
- [Testing Checklist](#testing-checklist)

## Introduction

Welcome, and thank you for helping us test the Cart and Checkout blocks,
in this document, we will outline the general checklist for how to test
the blocks, any requirements, and expectations and feature parity, some
will require simple coding skills, and some are straightforward, we will
separate them.

### Known limitations

<!-- Debating on where to put this section -->

This is a list of all known limitation for Cart and Checkout blocks, it means
we're aware of them, and will probably not tackle them in this first release:

-   Cart and Checkout blocks do not support third-party plugins that integrate with
    regular Cart and Checkout shortcode, if you somehow see a third party plugin working
... (60 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/cart-checkout/shipping.md">
# Shipping <!-- omit in toc -->

## Setup

-   You will need to setup shipping zones for a couple of countries.
-   You will need to have a free shipping method that is enabled with a coupon or a threshold.

## What to test

### With shipping zones available

-   [ ] You should be able to see preview rates (that are not your actual rates) in the editor.
-   [ ] You should be able to see your actual rates on the frontend.
-   [ ] Selecting a shipping rate should update the totals.
-   [ ] Changing the address in Cart block should update the rates.
-   [ ] Try entering an address that does not have rates for, you should:
    -   [ ] See an error saying "No options were found".
    -   [ ] See the default shipping option if you have it setup.
-   [ ] The countries in the shipping rates form should reflect the countries you have in WooCommerce -> Settings -> General -> Shipping location(s).
-   [ ] If your cart has only digital products, the Cart and Checkout blocks should act like shipping is disabled.
-   [ ] Your free shipping method should show up when you increase the cart quantity to above that limit.
    -   [ ] Once you decrease it, the shipping rate will disappear, the next rate will be selected.
-   [ ] The rate you select in Cart should still be selected in Checkout.
-   [ ] Updating your shipping address in Checkout should give you live updates about rates in your cart.

### If you don't have any shipping zones set up, and shipping is disabled

-   [ ] You should only see the billing form in both editor and frontend for the Checkout Block.
-   [ ] The shipping options step should not be visible.
-   [ ] The shipping cost should not be visible in the sidebar.
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/cart-checkout/taxes.md">
# Taxes <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

- [Setup](#setup)
- [What to test](#what-to-test)
    - [With taxes disabled](#with-taxes-disabled)
    - [With taxes enabled](#with-taxes-enabled)

## Setup

-   You will need to have taxes setup for a region.

## What to test

### With taxes disabled

-   [ ] You should not see "Taxes" line in the cart or checkout.

### With taxes enabled

-   [ ] You should see "Taxes" line in the cart or checkout.
-   [ ] If the user address or store settings country doesn't have taxes in it, the value will be 0.

[![Create Todo list](https://raw.githubusercontent.com/senadir/todo-my-markdown/master/public/github-button.svg?sanitize=true)](https://git-todo.netlify.app/create)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/README.md">
# Testing

This folder contains documentation around manual testing of WooCommerce Blocks.

| Document                                                           | Description                                                                              |
| ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| [When to employ end to end testing](when-to-employ-e2e-testing.md) | This doc explains when End to End tests should be used and when unit tests will suffice. |
| [Smoke Testing](smoke-testing.md)                                  | This doc explains how to smoke test key Blocks functionality.                            |
| [Cart and Checkout Testing](cart-checkout/README.md)               | Various testing flows for Cart and Checkout Blocks                                       |
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/smoke-testing.md">
# Smoke Testing

We generally consider smoke testing using this definition [from Wikipedia](<https://href.li/?https://en.wikipedia.org/wiki/Smoke_testing_(software)>):

> **Smoke Testing** is a subset of test cases that cover the most important functionality of a component or system, used to aid assessment of whether the main functions of the software appear to work correctly. It is a set of tests run on each new build of a product to verify that the build is testable before the build is released into the hands of the test team

When testing builds the following things should be tested to ensure critical parts of the Blocks plugin are still functional.

## Setup

To make future testing more efficient, we recommend setting up some Blocks in advance so you can repeat tests on them whenever smoke testing.

### 1. Create a page with most blocks

<details><!-- markdownlint-disable-line no-inline-html -->
<summary>You can copy and paste (<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>V</kbd>) the following code into a new page to add all the blocks (click):</summary><!-- markdownlint-disable-line no-inline-html -->

Note: some blocks might fail to render because they are based on products having a specific id or depend on the site URL. You will need to remove and re-insert them.

```html
<!-- wp:woocommerce/featured-product {"editMode":false,"productId":15} -->
<!-- wp:button {"align":"center"} -->
<div class="wp-block-button aligncenter">
	<a
		class="wp-block-button__link"
		href=""
		>Shop now</a
	>
</div>
<!-- /wp:button -->
... (208 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/testing/when-to-employ-e2e-testing.md">
# When to employ end to end (E2E) testing

We use [Playwright](https://playwright.dev/) to run tests in a real browser, these are called End to End tests. These tests are fairly expensive to run and often fail randomly due to flaky browser behaviour, with this in mind, we should be careful about when we use them.

Ultimately, the front-end is a representation of our application's state, and in most cases we will be able to reliably determine that it is behaving the way we want it to without setting up a full browser environment to verify this. For example, if we want to test that the quantity of an item in the cart is increased when the `+` button is pressed, we can mock the store and ensure the correct action is dispatched, we can also mock the function used to make requests to the API and test that it is called with the correct parameters. We can then use PHP tests to ensure the API returns the correct response, and then test the cart to ensure receiving new cart data results in an updated DOM (with the new quantity in the quantity selector!)

If the functionality you're testing relies on a third party library whose functions would be difficult to mock, then setting it up as an E2E test would be a good way to check your code is working as intended. An example of this is testing how our blocks behave in the Gutenberg block editor. It would be too difficult to mock all of the interfaces of Gutenberg that would be required to test our blocks.

If the functionality you're testing doesn't rely on a browser function (e.g. the browser back/forward buttons, or local storage) then you may be able to forego using an E2E test and instead write a unit test or integration test using [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/).

An example of things that _should_ be tested with E2E tests:

1.  Blocks cannot be added to the block editor more than once. Reason: **We cannot really mock the Gutenberg functionality to test that this happens without some serious effort.**
2.  Fresh cart data is fetched when using the browser's back buttons. Reason: **We need to emulate the behaviour of a browser when the back button is pressed and this can't be done in unit tests.**
3.  The compatibility notice is shown when first adding the checkout block. Reason: **same as 1**
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/translations/README.md">
# Translations

This folder contains documentation around translation handling of WooCommerce Blocks:

-   [Translation basics](./translation-basics.md)
-   [Translations in PHP files](./translations-in-PHP-files.md)
-   [Translations in JS/TS files](./translations-in-JS-TS-files.md)
-   [Translations in FSE templates](./translations-in-FSE-templates.md)
-   [Translations for lazy-loaded components](./translations-for-lazy-loaded-components.md)
-   [Translation loading](./translation-loading.md)
-   [Translation management](./translation-management.md)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/translations/translation-basics.md">
# Translation basics

## Localization functions

Since [WordPress 2.1 "Ella"](https://wordpress.org/support/wordpress-version/version-2-1/), WordPress offers [internationalization (i18n)](https://developer.wordpress.org/plugins/internationalization/) for PHP files, and since [WordPress 5.0 "Bebo"](https://wordpress.org/support/wordpress-version/version-5-0/), it also offers i18n for JS files. Handling translations is pretty straight forward. Both PHP and JS handle translations similar. WordPress offers the functions:

-   [`__()`](https://developer.wordpress.org/reference/functions/__/) → Available in PHP & JS/TS.
-   [`_e()`](https://developer.wordpress.org/reference/functions/_e/) → Available in PHP only.
-   [`_ex()`](https://developer.wordpress.org/reference/functions/_ex/) → Available in PHP only.
-   [`_n()`](https://developer.wordpress.org/reference/functions/_n/) → Available in PHP & JS/TS.
-   [`_x()`](https://developer.wordpress.org/reference/functions/_x/) → Available in PHP & JS/TS.
-   [`_nx()`](https://developer.wordpress.org/reference/functions/_nx/) → Available in PHP & JS/TS.
-   [`esc_html__()`](https://developer.wordpress.org/reference/functions/esc_html__/) → Available in PHP only.
-   [`esc_html_e()`](https://developer.wordpress.org/reference/functions/esc_html_e/) → Available in PHP only.
-   [`esc_html_x()`](https://developer.wordpress.org/reference/functions/esc_html_x/) → Available in PHP only.
-   [`esc_attr__()`](https://developer.wordpress.org/reference/functions/esc_attr__/) → Available in PHP only.
-   [`esc_attr_e()`](https://developer.wordpress.org/reference/functions/esc_attr_e/) → Available in PHP only.
-   [`esc_attr_x()`](https://developer.wordpress.org/reference/functions/esc_attr_x/) → Available in PHP only.

## GlotPress

All translations are handled using [GlotPress](https://wordpress.org/plugins/glotpress/). As the WooCommerce Blocks plugin is hosted on <https://wordpress.org/>, all plugin-related translations can be found and managed on <https://translate.wordpress.org/projects/wp-plugins/woo-gutenberg-products-block/>.

## Text domain

Prior to [WordPress 4.6 “Pepper Adams”](https://wordpress.org/support/wordpress-version/version-4-6/), a text domain had to be defined to make the strings translatable. While it’s no longer a requirement to have a text domain, it does no harm to still include it. If the text domain is available, it has to match the slug of the plugin and is defined in the header of the main plugin file `woocommerce-gutenberg-products-block.php`:

```php
<?php
/**
... (20 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/translations/translation-loading.md">
# Translation files and loading

## Translation files

### POT (Portable Object Template) file

POT stands for `Portable Object Template` and contains all original strings, in English. It can be created manually using [WP-CLI](https://wp-cli.org/) or [Poedit](https://poedit.net/). As the WooCommerce Blocks plugin is hosted on WordPress.org, we don't need to manually create the POT file. GlotPress automatically generates that file in the background, once we release a new version of the plugin.

The POT file is human-readable and named `woo-gutenberg-products-block.pot`. It will not be downloaded to the site that is using the WooCommerce Blocks plugin. If we would generate the POT file manually, it would look like this:

```pot
"Project-Id-Version: WooCommerce Blocks\n"
"POT-Creation-Date: 2022-05-25 19:01+0700\n"
"PO-Revision-Date: 2022-05-25 19:00+0700\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
"X-Generator: Poedit 3.0.1\n"
"X-Poedit-Basepath: ..\n"
"X-Poedit-Flags-xgettext: --add-comments=translators:\n"
"X-Poedit-WPHeader: woocommerce-gutenberg-products-block.php\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;"
"_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
"X-Poedit-SearchPath-0: .\n"
"X-Poedit-SearchPathExcluded-0: *.min.js\n"
... (264 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/translations/translation-management.md">
# Translation management

As mentioned in [Translation basics](../../internal-developers/translations/translation-basics.md), all translations are managed using [GlotPress](https://wordpress.org/plugins/glotpress/). The translations of the WooCommerce Blocks plugin can be found on <https://translate.wordpress.org/projects/wp-plugins/woo-gutenberg-products-block/>.

## Roles

-   [Translation Contributors](#translation-contributors)
-   [Project Translation Editor (PTE)](#project-translation-editor-pte)
-   [General Translation Editor (GTE)](#general-translation-editor-gte)

### Translation Contributors

A Translation Contributors can suggest translations. These suggested translations need to be verified by a General Translation Editor (GTE) or a Project Translation Editor (PTE).

See also <https://make.wordpress.org/polyglots/handbook/about/roles-and-capabilities/#translation-contributor>.

### Project Translation Editor (PTE)

A Project Translation Editor can:

-   approve translations that are suggested by a Translation Contributor
-   change existing translations
-   add new translations

PTE permissions need to be requested via <https://make.wordpress.org/polyglots/>. If you're a developer of the WooCommerce Blocks plugin, you can request PTE permissions using the following template:

```text
PTE Request for WooCommerce Blocks

I am the plugin co-author for WooCommerce Blocks, and I’d like to be able to approve translation for our plugin. Please add my WordPress.org user account as translation editor for their respective locales:
... (35 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/translations/translations-for-lazy-loaded-components.md">
# Translations for lazy-loaded components

The inner blocks of the Cart and Checkout blocks are lazy-loaded. To lazy-load them, the translation chunks need to be registered. This takes place in `src/Blocks/BlockTypes/AbstractBlock.php`:

```php
/**
 * Injects Chunk Translations into the page so translations work for lazy loaded components.
 *
 * The chunk names are defined when creating lazy loaded components using webpackChunkName.
 *
 * @param string[] $chunks Array of chunk names.
 */
protected function register_chunk_translations( $chunks ) {
  foreach ( $chunks as $chunk ) {
    $handle = 'wc-blocks-' . $chunk . '-chunk';
    $this->asset_api->register_script( $handle, $this->asset_api->get_block_asset_build_path( $chunk ), [], true );
    wp_add_inline_script(
      $this->get_block_type_script( 'handle' ),
      wp_scripts()->print_translations( $handle, false ),
      'before'
    );
    wp_deregister_script( $handle );
  }
}
```

## Lazy-loaded translations of the Cart block

The translations of the inner blocks of the Cart block are loaded in this function in `src/Blocks/BlockTypes/Cart.php`:

... (82 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/translations/translations-in-FSE-templates.md">
# Translations in FSE templates

To make the WooCommerce Blocks plugin inclusive, all user-facing strings should be translatable. Managing [Translations in PHP files](../../internal-developers/translations/translations-in-PHP-files.md) and [Translations in JS/TS files](../../internal-developers/translations/translations-in-JS-TS-files.md) is simple as PHP and JS/TS are languages are programming languages which contain translation function. In comparison, FSE-templates are using plain HTML. As HTML is a markup language and not a programming language, translation functions such as `__()` and `_n()` are not available in HTML. Therefore, translations within FSE-templates require a different approach.

Let's take a look at `templates/parts/mini-cart.html`:

```html
<!-- wp:woocommerce/mini-cart-contents -->
<div class="wp-block-woocommerce-mini-cart-contents">
	<!-- wp:woocommerce/filled-mini-cart-contents-block -->
	<div class="wp-block-woocommerce-filled-mini-cart-contents-block">
		<!-- wp:woocommerce/mini-cart-title-block -->
		<div class="wp-block-woocommerce-mini-cart-title-block"></div>
		<!-- /wp:woocommerce/mini-cart-title-block -->
		<!-- wp:woocommerce/mini-cart-items-block -->
		<div class="wp-block-woocommerce-mini-cart-items-block">
			<!-- wp:woocommerce/mini-cart-products-table-block -->
			<div
				class="wp-block-woocommerce-mini-cart-products-table-block"
			></div>
			<!-- /wp:woocommerce/mini-cart-products-table-block -->
		</div>
		<!-- /wp:woocommerce/mini-cart-items-block -->
		<!-- wp:woocommerce/mini-cart-footer-block -->
		<div class="wp-block-woocommerce-mini-cart-footer-block"></div>
		<!-- /wp:woocommerce/mini-cart-footer-block -->
	</div>
	<!-- /wp:woocommerce/filled-mini-cart-contents-block -->

	<!-- wp:woocommerce/empty-mini-cart-contents-block -->
... (80 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/translations/translations-in-JS-TS-files.md">
# Translations in JS/TS files

In comparison to PHP files, translations in JS/TS files require a few additional steps. To use translation functions in JS/TS, the dependency `@wordpress/i18n` needs to be included at the top of the corresponding file:

```ts
const { sprintf, _n } = window.wp.i18n;
```

Once that dependency had been included, the translation function can than be used.

## Usage of localization functions

### `__()`

The function `__()` retrieves the translation of `$text`.

```ts
// Schema
const translation = __( string text, string domain = 'default' );

// Example
const { __ } = window.wp.i18n;

const translation = __( 'Place Order', 'woo-gutenberg-products-block' );
```

See also <https://developer.wordpress.org/reference/functions/__/>.

### `_n()`

... (71 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/internal-developers/translations/translations-in-PHP-files.md">
# Translations in PHP files

Translations in PHP files work straight-forward. Translations functions such as `__()` and `_n()` are part of the WordPress core. Therefore, they are available globally and do not have to be imported.

## Usage of localization functions

### `__()`

The function `__()` retrieves the translation of `$text`. This function is available both for PHP & JS/TS.

```php
// Schema
$translation = __( string $text, string $domain = 'default' );

// Example
$translation = __( 'Place Order', 'woo-gutenberg-products-block' );
```

See also <https://developer.wordpress.org/reference/functions/__/>.

### `_e()`

The function `_e()` displays the translation of `$text`. This function is only available for PHP.

```php
// Schema
_e( string $text, string $domain = 'default' );

// Example
_e( 'Place Order', 'woo-gutenberg-products-block' );
... (163 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/data-store/cart.md">
# Cart Data Store Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Cart Data Store Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/block-development/reference/data-store/cart.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/data-store/checkout.md">
# Checkout Data Store Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Checkout Data Store Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/block-development/reference/data-store/checkout.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/data-store/collections.md">
# Collections Data Store Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Collections Data Store Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/block-development/reference/data-store/collections.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/data-store/payment.md">
# Payments Data Store Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Payments Data Store Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/block-development/reference/data-store/payment.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/data-store/query-state.md">
# Query State Data Store Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Query State Data Store Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/block-development/reference/data-store/query-state.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/data-store/README.md">
# Data Store Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Data Store Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/block-development/reference/data-store/README.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/data-store/schema.md">
# Schema Data Store Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Schema Data Store Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/block-development/reference/data-store/schema.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/data-store/store-notices.md">
# Store Notices Data Store Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Store Notices Data Store Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/block-development/reference/data-store/store-notices.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/data-store/validation.md">
# Validation Data Store Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Validation Data Store Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/block-development/reference/data-store/validation.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/actions.md">
<!-- DO NOT UPDATE THIS DOC DIRECTLY -->

<!-- Use `npm run build:docs` to automatically build hook documentation -->

# Actions

## Table of Contents

- [deprecated_function_run](#deprecated_function_run)
- [woocommerce_add_to_cart](#woocommerce_add_to_cart)
- [woocommerce_after_add_to_cart_button](#woocommerce_after_add_to_cart_button)
- [woocommerce_after_add_to_cart_form](#woocommerce_after_add_to_cart_form)
- [woocommerce_after_add_to_cart_quantity](#woocommerce_after_add_to_cart_quantity)
- [woocommerce_after_main_content](#woocommerce_after_main_content)
- [woocommerce_after_shop_loop](#woocommerce_after_shop_loop)
- [woocommerce_after_single_variation](#woocommerce_after_single_variation)
- [woocommerce_after_variations_form](#woocommerce_after_variations_form)
- [woocommerce_after_variations_table](#woocommerce_after_variations_table)
- [woocommerce_applied_coupon](#woocommerce_applied_coupon)
- [woocommerce_archive_description](#woocommerce_archive_description)
- [woocommerce_before_add_to_cart_button](#woocommerce_before_add_to_cart_button)
- [woocommerce_before_add_to_cart_form](#woocommerce_before_add_to_cart_form)
- [woocommerce_before_add_to_cart_quantity](#woocommerce_before_add_to_cart_quantity)
- [woocommerce_before_main_content](#woocommerce_before_main_content)
- [woocommerce_before_shop_loop](#woocommerce_before_shop_loop)
- [woocommerce_before_single_variation](#woocommerce_before_single_variation)
- [woocommerce_before_variations_form](#woocommerce_before_variations_form)
- [woocommerce_blocks_cart_enqueue_data](#woocommerce_blocks_cart_enqueue_data)
- [woocommerce_blocks_checkout_enqueue_data](#woocommerce_blocks_checkout_enqueue_data)
- [woocommerce_blocks_enqueue_cart_block_scripts_after](#woocommerce_blocks_enqueue_cart_block_scripts_after)
... (1120 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/filters.md">
<!-- DO NOT UPDATE THIS DOC DIRECTLY -->

<!-- Use `npm run build:docs` to automatically build hook documentation -->

# Filters

## Table of Contents

- [__experimental_woocommerce_blocks_add_data_attributes_to_block](#__experimental_woocommerce_blocks_add_data_attributes_to_block)
- [__experimental_woocommerce_blocks_add_data_attributes_to_namespace](#__experimental_woocommerce_blocks_add_data_attributes_to_namespace)
- [__experimental_woocommerce_blocks_payment_gateway_features_list](#__experimental_woocommerce_blocks_payment_gateway_features_list)
- [__experimental_woocommerce_store_api_batch_request_methods](#__experimental_woocommerce_store_api_batch_request_methods)
- [`__experimental_woocommerce_{$product_type}_add_to_cart_with_options_block_template_part`](#__experimental_woocommerce_product_type_add_to_cart_with_options_block_template_part)
- [comment_text](#comment_text)
- [deprecated_function_trigger_error](#deprecated_function_trigger_error)
- [wc_session_expiration](#wc_session_expiration)
- [woocommerce_add_cart_item](#woocommerce_add_cart_item)
- [woocommerce_add_cart_item_data](#woocommerce_add_cart_item_data)
- [woocommerce_add_to_cart_form_action](#woocommerce_add_to_cart_form_action)
- [woocommerce_add_to_cart_quantity](#woocommerce_add_to_cart_quantity)
- [woocommerce_add_to_cart_sold_individually_quantity](#woocommerce_add_to_cart_sold_individually_quantity)
- [woocommerce_add_to_cart_validation](#woocommerce_add_to_cart_validation)
- [woocommerce_adjust_non_base_location_prices](#woocommerce_adjust_non_base_location_prices)
- [woocommerce_apply_individual_use_coupon](#woocommerce_apply_individual_use_coupon)
- [woocommerce_apply_with_individual_use_coupon](#woocommerce_apply_with_individual_use_coupon)
- [woocommerce_blocks_hook_compatibility_additional_data](#woocommerce_blocks_hook_compatibility_additional_data)
- [woocommerce_blocks_pre_get_routes_from_namespace](#woocommerce_blocks_pre_get_routes_from_namespace)
- [woocommerce_blocks_product_filters_selected_items](#woocommerce_blocks_product_filters_selected_items)
- [woocommerce_blocks_product_grid_add_to_cart_attributes](#woocommerce_blocks_product_grid_add_to_cart_attributes)
- [woocommerce_blocks_product_grid_is_cacheable](#woocommerce_blocks_product_grid_is_cacheable)
... (1960 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/hook-alternatives.md">
# Hook Alternatives Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Hook Alternatives Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/block-development/reference/hooks/hook-alternatives.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/migrated-hooks.md">
# Migrated Hooks Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Migrated Hooks Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/block-development/reference/hooks/migrated-hooks.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/hooks/README.md">
# Hooks

We have several hooks that can be used by extensions, some are new and some are hooks that already exist in WooCommerce core.

- [Filters](./filters.md)
- [Actions](./actions.md)

We also have a list of hooks that have been migrated from WooCommerce Core, but that have been renamed.

- [List of migrated hooks](./migrated-hooks.md)
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/rest-api/available-endpoints-to-extend.md">
# Available Endpoints to Extend

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Available Endpoints to Extend](https://github.com/woocommerce/woocommerce/tree/trunk/docs/apis/store-api/extending-store-api/available-endpoints-to-extend.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-add-custom-fields.md">
# Add Custom Fields Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Add Custom Fields Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/apis/store-api/extending-store-api/extend-store-api-add-custom-fields.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-add-data.md">
# Add Data Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Add Data Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/apis/store-api/extending-store-api/extend-store-api-add-data.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-formatters.md">
# Formatters Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Formatters Documentation](docs/apis/store-api/extending-store-api/extend-store-api-formatters.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-update-cart.md">
# Update Cart Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Update Cart Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/apis/store-api/extending-store-api/extend-store-api-update-cart.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/third-party-developers/extensibility/rest-api/README.md">
# Extending the Store API Documentation

> **⚠️ Document Moved**
> 
> This document has been moved to the main WooCommerce documentation repository. You can find the updated version at:
> 
> **[Extending the Store API Documentation](https://github.com/woocommerce/woocommerce/tree/trunk/docs/apis/store-api/extending-store-api/README.md)**
> 
> Please update your bookmarks and references to the new location.
</file>

<file path="plugins/woocommerce/client/blocks/docs/README.md">
# WooCommerce Blocks Handbook <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

-   [Contributors](#contributors)
-   [Internal developers](#internal-developers)
-   [Third-party developers](#third-party-developers)
-   [Designers and theme developers](#designers-and-theme-developers)
-   [Block References](#block-references)
-   [Developer Resources](#developer-resources)
    -   [Tools](#tools)
    -   [Articles](#articles)
    -   [Tutorials](#tutorials)

The WooCommerce Blocks Handbook provides documentation for designers and developers on how to extend or contribute to blocks, and how internal developers should handle new releases.

## Contributors

> Want to contribute to the WooCommerce Blocks plugin? The following documents offer information that can help you get started.

-   [Contributing](contributors/README.md)
    -   [Getting Started](contributors/getting-started.md)
    -   [Coding Guidelines](contributors/coding-guidelines.md)
    -   [Block Script Assets](contributors/block-assets.md)
    -   [CSS Build System](contributors/css-build-system.md)
    -   [JavaScript Build System](contributors/javascript-build-system.md)
    -   [JavaScript Testing](contributors/javascript-testing.md)
    -   [Storybook & Components](contributors/storybook-and-components.md)

## Internal developers
... (118 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/internal/entities/product/constants.ts">
import { __ } from '@wordpress/i18n';
import { isExperimentalWcRestApiV4Enabled } from '@woocommerce/block-settings';
⋮----
import { Entity } from '../types';
import { ProductEntityResponse } from './types';
</file>

<file path="plugins/woocommerce/client/blocks/packages/internal/entities/product/guards.ts">
import { ProductResponseItem } from '@woocommerce/types';
⋮----
import { ExternalProductResponse, ProductEntityResponse } from './types';
⋮----
export const isExternalProduct = (
	product: ProductEntityResponse
): product is ExternalProductResponse =>
⋮----
export const isProductResponseItem = (
	product: ProductResponseItem | ProductEntityResponse | undefined
): product is ProductResponseItem =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/internal/entities/product/hooks.ts">
import { store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
⋮----
import { ProductEntityResponse } from './types';
⋮----
export const useProduct = ( postId: number | string | undefined ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/internal/entities/product/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/internal/entities/product/types.ts">
export interface ProductEntityResponseImage {
	id: number;
	date_created: string;
	date_created_gmt: string;
	date_modified: string;
	date_modified_gmt: string;
	src: string;
	name: string;
	alt: string;
	srcset: string;
	sizes: string;
	thumbnail: string;
}
⋮----
interface ProductEntityResponseBase {
	id: number;
	name: string;
	slug: string;
	permalink: string;
	date_created: string;
	date_created_gmt: string;
	date_modified: string;
	date_modified_gmt: string;
	type: 'simple' | 'grouped' | 'external' | 'variable' | 'variation';
	status: 'draft' | 'pending' | 'private' | 'publish' | 'trash';
	featured: boolean;
	catalog_visibility: 'visible' | 'catalog' | 'search' | 'hidden';
	description: string;
	short_description: string;
	sku: string;
... (40 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/internal/entities/settings/constants.ts">
import { __ } from '@wordpress/i18n';
⋮----
import { Entity } from '../types';
import { SettingsEntityRecord } from './types';
</file>

<file path="plugins/woocommerce/client/blocks/packages/internal/entities/settings/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/internal/entities/settings/types.ts">
export type SettingsEntityValue = string | number | boolean | unknown[];
⋮----
export interface SettingsEntityRecord {
	id: string;
	title?: string;
	description?: string;
	values?: Record< string, SettingsEntityValue >;
	groups?: Record<
		string,
		{
			title?: string;
			description?: string;
		}
	>;
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/internal/entities/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/internal/entities/README.md">
# WooCommerce Block Entities

This module contains the entity helpers for WooCommerce. Entities provide a standardized way to interact with WordPress data stores and enable consistent data access patterns across the admin interface.

## Overview

The pure entity helpers in this directory are bundled into their consumers and can be tree-shaken. Registration lives separately in `../entity-registration` and builds as a dedicated script that loads consistently on every admin screen.

For backward compatibility, the registration script continues to expose the runtime helpers on `wc.wcEntities`. That global API is deprecated as of WooCommerce 11.1.0 and emits a warning when a helper is called.

## Available Entities

### Product Entity

The product entity provides access to WooCommerce product data through WordPress's core data store. It includes:

-   **Constants**: Entity name, kind, and configuration
-   **Types**: TypeScript interfaces for product data structures
-   **Guards**: Runtime type checking utilities
-   **Hooks**: React hooks for data fetching and manipulation

## Usage

### Automatic Registration

Entities are automatically registered on every admin page through the `wc-entities` script. The script performs registration as a side effect and temporarily retains the deprecated `wc.wcEntities` global for backward compatibility.

### Deprecated manual registration

The manual registration functions remain exported temporarily for compatibility:
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/internal/entities/register-entities.ts">
import deprecated from '@wordpress/deprecated';
⋮----
import {
	registerProductEntity as registerProductEntityInternal,
	registerSettingsEntity as registerSettingsEntityInternal,
} from '../../public-api/entity-registration/register-entities';
⋮----
const showDeprecationNotice = ( functionName: string ) =>
⋮----
export const registerProductEntity = () =>
⋮----
export const registerSettingsEntity = () =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/internal/entities/types.ts">
export type Entity = {
	name: string;
	kind: string;
	baseURL: string;
	label: string;
	plural: string;
	key: string;
	supportsPagination: boolean;
	getTitle: ( record: unknown ) => string;
};
</file>

<file path="plugins/woocommerce/client/blocks/packages/internal/README.md">
# WooCommerce Blocks internal packages

This directory contains package-shaped implementation details that are not
supported extension APIs.

An internal package may remain externalized to preserve a singleton or shared
runtime instance. Its script handle or browser global is an implementation
detail and does not provide a backward-compatibility guarantee.

`@woocommerce/entities` currently remains a separate script under the
`wc-entities` handle and the `wc.wcEntities` global. Extensions should not
consume it directly.

See the [public API packages](../public-api/README.md) for supported extension
contracts.
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/action-types.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/actions.ts">
import type {
	ApiErrorResponse,
	Cart,
	CartResponseItem,
} from '@woocommerce/types';
import { BillingAddress, ShippingAddress } from '@woocommerce/settings';
⋮----
import { ACTION_TYPES as types } from './action-types';
⋮----
export function setCartData( cart: Partial< Cart > )
⋮----
export function setErrorData( error: ApiErrorResponse | null )
⋮----
export function receiveApplyingCoupon( couponCode: string )
⋮----
export function receiveRemovingCoupon( couponCode: string )
⋮----
export function receiveCartItem( response: CartResponseItem | null = null )
⋮----
export function itemIsPendingQuantity(
	cartItemKey: string,
	isPendingQuantity = true
)
⋮----
export function itemIsPendingDelete(
	cartItemKey: string,
	isPendingDelete = true
)
⋮----
export function setIsCartDataStale( isCartDataStale = true )
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/constants.ts">
import { __ } from '@wordpress/i18n';
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/default-state.ts">
import type {
	Cart,
	CartMeta,
	ApiErrorResponse,
	CartShippingAddress,
	CartBillingAddress,
} from '@woocommerce/types';
import { AddressFormValues } from '@woocommerce/settings';
import { ADDRESS_FORM_KEYS } from '@woocommerce/block-settings';
⋮----
import {
	EMPTY_CART_COUPONS,
	EMPTY_CART_ITEMS,
	EMPTY_CART_CROSS_SELLS,
	EMPTY_CART_FEES,
	EMPTY_CART_ITEM_ERRORS,
	EMPTY_CART_ERRORS,
	EMPTY_SHIPPING_RATES,
	EMPTY_TAX_LINES,
	EMPTY_PAYMENT_METHODS,
	EMPTY_PAYMENT_REQUIREMENTS,
	EMPTY_EXTENSIONS,
} from '../constants';
⋮----
export interface CartState {
	cartItemsPendingQuantity: string[];
	cartItemsPendingDelete: string[];
	productsPendingAdd: number[];
	cartData: Cart;
	metaData: CartMeta;
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/index.ts">
import {
	register,
	subscribe,
	createReduxStore,
	dispatch as wpDispatch,
	select,
} from '@wordpress/data';
import { controls as dataControls } from '@wordpress/data-controls';
⋮----
import { STORE_KEY } from './constants';
⋮----
import reducer from './reducers';
import { pushChanges, flushChanges } from './push-changes';
import {
	updatePaymentMethods,
	debouncedUpdatePaymentMethods,
} from './update-payment-methods';
import {
	hasCartSession,
	persistenceLayer,
	isAddingToCart,
} from './persistence-layer';
import { defaultCartState } from './default-state';
import { getTriggerStoreSyncEvent } from './utils';
import type { QuantityChanges } from './notify-quantity-changes';
import { isEditor } from '../utils';
⋮----
export type CartStoreDescriptor = typeof store;
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/notify-errors.ts">
import { ApiErrorResponse, isApiErrorResponse } from '@woocommerce/types';
import { createNotice } from '@woocommerce/base-utils';
import { decodeEntities } from '@wordpress/html-entities';
import { dispatch } from '@wordpress/data';
⋮----
import { getNoticeContextFromErrorResponse } from '../utils/process-error-response';
⋮----
const filterValidErrors = ( errors: ApiErrorResponse[] ) =>
⋮----
const createNoticesFromErrors = ( errors: ApiErrorResponse[] ) =>
⋮----
const dismissNoticeByOptions = ( options:
⋮----
export const updateCartErrorNotices = (
	errors: ApiErrorResponse[] | null = null,
	oldErrors: ApiErrorResponse[] | null = null
) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/notify-quantity-changes.ts">
import { Cart, CartItem } from '@woocommerce/types';
import { dispatch, select } from '@wordpress/data';
import { decodeEntities } from '@wordpress/html-entities';
import { __, sprintf } from '@wordpress/i18n';
import { applyFilters } from '@wordpress/hooks';
import { CurriedSelectorsOf } from '@wordpress/data/build-types/types';
⋮----
import { __unstableStripHTML as stripHTML } from '@wordpress/dom';
⋮----
import type { CartStoreDescriptor } from '@woocommerce/block-data/cart';
import { STORE_KEY as CART_STORE_KEY } from './constants';
⋮----
export type QuantityChanges = {
	cartItemsPendingQuantity?: string[] | undefined;
	cartItemsPendingDelete?: string[] | undefined;
	productsPendingAdd?: number[] | undefined;
};
⋮----
type NotifyQuantityChangesArgs = {
	oldCart: Cart;
	newCart: Cart;
} & QuantityChanges;
⋮----
const isWithinQuantityLimits = ( cartItem: CartItem ) =>
⋮----
const stripAndDecode = ( text: string ) =>
⋮----
const notifyIfQuantityChanged = (
	oldCart: Cart,
	newCart: Cart,
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/persistence-layer.ts">
import type { Cart } from '@woocommerce/types';
⋮----
const getCookie = ( name: string ): string | Record< string, string > =>
⋮----
const hasValidHash = () =>
⋮----
export const hasCartSession = () =>
⋮----
export const isAddingToCart = () =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/push-changes.ts">
import {
	debounce,
	addressFieldsForShippingRates,
} from '@woocommerce/base-utils';
import { CartBillingAddress, CartShippingAddress } from '@woocommerce/types';
import { select, dispatch } from '@wordpress/data';
import isShallowEqual from '@wordpress/is-shallow-equal';
⋮----
import { store as cartStore } from './index';
import { processErrorResponse } from '../utils';
import { getDirtyKeys, validateDirtyProps, BaseAddressKey } from './utils';
⋮----
const initialize = () =>
⋮----
const updateDirtyProps = () =>
⋮----
/**
 * Fields a country change resets, since their values only make sense for the previous country.
 */
⋮----
const getDirtyPropsToValidate = (
	dirtyProps: BaseAddressKey[],
	address: CartBillingAddress | CartShippingAddress
): BaseAddressKey[] =>
⋮----
const updateCustomerData = (): void =>
⋮----
export const pushChanges = ( debounced = true ): void =>
⋮----
export const flushChanges = (): void =>
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/README.md">
# Cart Store

The docs for the Cart Store can be found in [docs/third-party-developers/extensibility/data-store/cart.md](../../../../docs/third-party-developers/extensibility/data-store/cart.md).
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/reducers.ts">
import type { Reducer, AnyAction } from 'redux';
⋮----
import { ACTION_TYPES as types } from './action-types';
import { defaultCartState, CartState } from './default-state';
import { EMPTY_CART_ERRORS } from '../constants';
import { setIsCustomerDataDirty } from './utils';
import { persistenceLayer } from './persistence-layer';
import { isEditor } from '../utils';
⋮----
const reducer: Reducer< CartState > = ( state = defaultCartState, action ) =>
⋮----
export type State = ReturnType< typeof reducer >;
⋮----
function withPersistenceLayer( cartReducer: Reducer< CartState > )
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/resolvers.ts">
import apiFetch from '@wordpress/api-fetch';
import { CartResponse } from '@woocommerce/types';
import { previewCart } from '@woocommerce/resource-previews';
⋮----
import { CART_API_ERROR } from './constants';
import type { CartDispatchFromMap, CartResolveSelectFromMap } from './index';
import { setTriggerStoreSyncEvent } from './utils';
import { isEditor } from '../utils';
⋮----
export const getCartData =
()
⋮----
export const getCartTotals =
()
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/selectors.ts">
import type {
	Cart,
	CartTotals,
	CartMeta,
	CartItem,
	CartShippingRate,
	ApiErrorResponse,
} from '@woocommerce/types';
import { BillingAddress, ShippingAddress } from '@woocommerce/settings';
import { createSelector } from '@wordpress/data';
⋮----
import { CartState, defaultCartState } from './default-state';
⋮----
export const getCartData = ( state: CartState ): Cart =>
⋮----
export const getShippingRates = ( state: CartState ): CartShippingRate[] =>
⋮----
export const getNeedsShipping = ( state: CartState ): boolean =>
⋮----
export const getHasCalculatedShipping = ( state: CartState ): boolean =>
⋮----
export const getCartTotals = ( state: CartState ): CartTotals =>
⋮----
export const getCartMeta = ( state: CartState ): CartMeta =>
⋮----
export const getCartErrors = ( state: CartState ): ApiErrorResponse[] =>
⋮----
export const isApplyingCoupon = ( state: CartState ): boolean =>
⋮----
export const isCartDataStale = ( state: CartState ): boolean =>
... (50 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/thunks.ts">
import {
	Cart,
	CartResponse,
	ApiErrorResponse,
	isApiErrorResponse,
	ExtensionCartUpdateArgs,
	CartShippingPackageShippingRate,
	CartShippingRate,
	BillingAddressShippingAddress,
} from '@woocommerce/types';
import {
	camelCaseKeys,
	hasCollectableRate,
	triggerAddedToCartEvent,
	triggerAddingToCartEvent,
} from '@woocommerce/base-utils';
import {
	type CurriedSelectorsOf,
	type ConfigOf,
	type ActionCreatorsOf,
	type DispatchFunction,
} from '@wordpress/data/build-types/types';
import { __ } from '@wordpress/i18n';
import { cartStore } from '@woocommerce/block-data';
⋮----
import { isObject } from '../../types/type-guards/object';
import {
	notifyQuantityChanges,
	QuantityChanges,
} from './notify-quantity-changes';
... (118 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/update-payment-methods.ts">
import { dispatch, select } from '@wordpress/data';
import { debounce } from '@woocommerce/base-utils';
⋮----
import { store as paymentStore } from '../payment';
import { store as cartStore } from './index';
⋮----
export const updatePaymentMethods = async () =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/cart/utils.ts">
import { select } from '@wordpress/data';
import { camelCaseKeys, debounce } from '@woocommerce/base-utils';
import { isEmail } from '@wordpress/url';
import {
	CartBillingAddress,
	CartShippingAddress,
	Cart,
	CartResponse,
} from '@woocommerce/types';
import { CurriedSelectorsOf } from '@wordpress/data/build-types/types';
⋮----
import type { ValidationStoreDescriptor } from '../validation';
import { STORE_KEY as VALIDATION_STORE_KEY } from '../validation/constants';
⋮----
export const mapCartResponseToCart = ( responseCart: CartResponse ): Cart =>
⋮----
export const shippingAddressHasValidationErrors = () =>
⋮----
export type BaseAddressKey =
	| keyof CartBillingAddress
	| keyof CartShippingAddress;
⋮----
export const normalizeAddressProp = (
	key: BaseAddressKey,
	value?: string | undefined
) =>
⋮----
/**
 * Compares two address objects and returns an array of keys that have changed.
 */
... (26 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/checkout/action-types.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/checkout/actions.ts">
import type { AddressFormType, OrderFormValues } from '@woocommerce/settings';
import deprecated from '@wordpress/deprecated';
⋮----
import { ACTION_TYPES as types } from './action-types';
⋮----
export const __internalSetIdle = () => (
⋮----
export const __internalSetBeforeProcessing = () => (
⋮----
export const __internalSetProcessing = () => (
⋮----
export const __internalSetAfterProcessing = () => (
⋮----
export const __internalSetComplete = (
	data: Record< string, unknown > = {}
) => (
⋮----
export const __internalSetRedirectUrl = ( redirectUrl: string ) => (
⋮----
export const __internalSetHasError = ( hasError = true ) => (
⋮----
export const __internalStartCalculation = () => (
⋮----
export const __internalFinishCalculation = () => (
⋮----
export const __internalIncrementCalculating = () =>
⋮----
export const __internalDecrementCalculating = () =>
⋮----
export const __internalSetCustomerId = ( customerId: number ) => (
... (38 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/checkout/constants.ts">
import {
	BillingAddress,
	getSetting,
	ShippingAddress,
	OrderFormValues,
} from '@woocommerce/settings';
⋮----
import { CheckoutResponseSuccess } from '@woocommerce/types';
⋮----
export enum STATUS {
	IDLE = 'idle',
	COMPLETE = 'complete',
	BEFORE_PROCESSING = 'before_processing',
	PROCESSING = 'processing',
	AFTER_PROCESSING = 'after_processing',
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/checkout/default-state.ts">
import { isSameAddress } from '@woocommerce/base-utils';
import type { AddressFormType, OrderFormValues } from '@woocommerce/settings';
⋮----
import { STATUS, checkoutData } from './constants';
⋮----
export type CheckoutState = {
	additionalFields: OrderFormValues;
	calculatingCount: number;
	customerId: number;
	customerPassword: string;
	extensionData: Record< string, Record< string, unknown > >;
	hasError: boolean;
	orderId: number;
	orderNotes: string;
	prefersCollection?: boolean | undefined;
	redirectUrl: string;
	shouldCreateAccount: boolean;
	status: STATUS;
	useShippingAsBilling: boolean;
	editingBillingAddress: boolean;
	editingShippingAddress: boolean;
	addressAutocompleteProviders: string[];
	activeAddressAutocompleteProvider: { [ key in AddressFormType ]: string };
};
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/checkout/index.ts">
import { createReduxStore, register, subscribe } from '@wordpress/data';
⋮----
import { STORE_KEY } from './constants';
⋮----
import reducer from './reducers';
import { pushChanges } from './push-changes';
⋮----
export type CheckoutStoreDescriptor = typeof store;
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/checkout/push-changes.ts">
import { debounce } from '@woocommerce/base-utils';
import { select, dispatch } from '@wordpress/data';
import type { OrderFormValues } from '@woocommerce/settings';
import { ApiErrorResponse } from '@woocommerce/types';
import { getSetting } from '@woocommerce/settings';
⋮----
import { STORE_KEY as CHECKOUT_STORE_KEY } from './constants';
import { STORE_KEY as PAYMENT_STORE_KEY } from '../payment/constants';
import { processErrorResponse } from '../utils';
import { CheckoutPutData } from './types';
import {
	clearFieldErrorNotices,
	hasValidationError,
	validateAdditionalFields,
} from './utils';
⋮----
const initialize = () =>
⋮----
const updateCheckoutData = (): void =>
⋮----
// Figure out which additional fields have changed and only send those to the server
⋮----
// Fields with errors should be ignored
⋮----
// Fields that are not present in the original checkout data and have an empty value should be ignored (happens when a field is hidden on mount).
⋮----
// Fields that have not changed should be ignored
⋮----
// Validate additional fields before proceeding
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/checkout/README.md">
# Checkout Store

The docs for the Checkout Store can be found in [docs/third-party-developers/extensibility/data-store/checkout.md](../../../../docs/third-party-developers/extensibility/data-store/checkout.md).
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/checkout/reducers.ts">
import type { Reducer } from 'redux';
⋮----
import { ACTION_TYPES as types } from './action-types';
import { STATUS } from './constants';
import { CheckoutState, defaultState } from './default-state';
⋮----
const reducer: Reducer< CheckoutState > = ( state = defaultState, action ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/checkout/selectors.ts">
import { select } from '@wordpress/data';
import { hasCollectableRate } from '@woocommerce/base-utils';
import { isString, objectHasProp } from '@woocommerce/types';
import type { AddressFormType } from '@woocommerce/settings';
⋮----
import { STATUS } from './constants';
import { CheckoutState } from './default-state';
import { STORE_KEY as cartStoreKey } from '../cart/constants';
⋮----
export const getCustomerId = ( state: CheckoutState ) =>
⋮----
export const getCustomerPassword = ( state: CheckoutState ) =>
⋮----
export const getOrderId = ( state: CheckoutState ) =>
⋮----
export const getOrderNotes = ( state: CheckoutState ) =>
⋮----
export const getRedirectUrl = ( state: CheckoutState ) =>
⋮----
export const getUseShippingAsBilling = ( state: CheckoutState ) =>
⋮----
export const getEditingBillingAddress = ( state: CheckoutState ) =>
⋮----
export const getEditingShippingAddress = ( state: CheckoutState ) =>
⋮----
export const getExtensionData = ( state: CheckoutState ) =>
⋮----
export const getShouldCreateAccount = ( state: CheckoutState ) =>
⋮----
export const getAdditionalFields = ( state: CheckoutState ) =>
... (28 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/checkout/thunks.ts">
import {
	isValidValidationErrorsObject,
	type CheckoutResponse,
	isSuccessResponse,
} from '@woocommerce/types';
import { store as noticesStore } from '@wordpress/notices';
import { dispatch as wpDispatch, select as wpSelect } from '@wordpress/data';
import type {
	ActionCreatorsOf,
	ConfigOf,
	CurriedSelectorsOf,
	DispatchFunction,
	SelectFunction,
} from '@wordpress/data/build-types/types';
import {
	CHECKOUT_EVENTS,
	checkoutEventsEmitter,
} from '@woocommerce/blocks-checkout-events';
⋮----
import { removeNoticesByStatus } from '../../../../assets/js/utils/notices';
import { store as paymentStore } from '../payment';
import type { CheckoutStoreDescriptor } from './index';
import {
	getPaymentResultFromCheckoutResponse,
	runCheckoutFailObservers,
	runCheckoutSuccessObservers,
} from './utils';
import type {
	emitValidateEventType,
	emitAfterProcessingEventsType,
... (34 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/checkout/types.ts">
import type { WPNotice } from '@wordpress/notices/build-types/store/selectors';
import type { FieldValidationStatus } from '@woocommerce/types';
import { AdditionalValues } from '@woocommerce/settings';
⋮----
import type { CheckoutState } from './default-state';
import type { PaymentState } from '../payment/default-state';
import type { CheckoutThunkArgs } from './thunks';
⋮----
export type CheckoutAfterProcessingWithErrorEventData = {
	redirectUrl: CheckoutState[ 'redirectUrl' ];
	orderId: CheckoutState[ 'orderId' ];
	customerId: CheckoutState[ 'customerId' ];
	orderNotes: CheckoutState[ 'orderNotes' ];
	processingResponse: PaymentState[ 'paymentResult' ];
};
export type CheckoutAndPaymentNotices = {
	checkoutNotices: WPNotice[];
	paymentNotices: WPNotice[];
	expressPaymentNotices: WPNotice[];
};
⋮----
export type emitAfterProcessingEventsType = ( {
	notices,
}: {
	notices: CheckoutAndPaymentNotices;
} ) => ( { select, dispatch, registry }: CheckoutThunkArgs ) => void;
⋮----
export type emitValidateEventType = ( {
	setValidationErrors,
}: {
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/checkout/utils.ts">
import { __ } from '@wordpress/i18n';
import { decodeEntities } from '@wordpress/html-entities';
import {
	type PaymentResult,
	type CheckoutResponse,
	type ObserverSuccessResponse,
	type ObserverFailResponse,
	type ObserverErrorResponse,
	isString,
	isObject,
	isErrorResponse,
	isFailResponse,
	isSuccessResponse,
} from '@woocommerce/types';
import type { createErrorNotice as originalCreateErrorNotice } from '@wordpress/notices/store/actions';
import {
	type ActionCreatorsOf,
	type ConfigOf,
} from '@wordpress/data/build-types/types';
import { checkoutStore } from '@woocommerce/block-data';
import { select } from '@wordpress/data';
import type {
	ContactForm,
	ContactFormValues,
	OrderForm,
	OrderFormValues,
} from '@woocommerce/settings';
import { removeNoticesForField } from '@woocommerce/base-utils';
⋮----
import { shouldRetry } from '../../../../assets/js/base/context/event-emit';
... (59 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/collections/action-types.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/collections/actions.js">
:
⋮----
export function receiveCollection(
	namespace,
	resourceName,
	queryString = '',
	ids = [],
	response = { items: [], headers: Headers },
	replace = false
)
⋮----
export function receiveCollectionError(
	namespace,
	resourceName,
	queryString,
	ids,
	error
)
⋮----
export function receiveLastModified( timestamp )
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/collections/constants.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/collections/index.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/collections/README.md">
# Collections Store

The docs for the Collections Store can be found in [docs/third-party-developers/extensibility/data-store/collections.md](../../../../docs/third-party-developers/extensibility/data-store/collections.md).
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/collections/reducers.js">
const receiveCollection = ( state =
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/collections/resolvers.js">
function* invalidateModifiedCollection( timestamp )
⋮----
export function* getCollection( namespace, resourceName, query, ids )
⋮----
export function* getCollectionHeader(
	header,
	namespace,
	resourceName,
	query,
	ids
)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/collections/selectors.js">
const getFromState = ( {
	state,
	namespace,
	resourceName,
	query,
	ids,
	type = 'items',
	fallback = DEFAULT_EMPTY_ARRAY,
} ) =>
⋮----
const getCollectionHeaders = (
	state,
	namespace,
	resourceName,
	query = null,
	ids = DEFAULT_EMPTY_ARRAY
) =>
⋮----
export const getCollection = (
	state,
	namespace,
	resourceName,
	query = null,
	ids = DEFAULT_EMPTY_ARRAY
) =>
⋮----
export const getCollectionError = (
	state,
	namespace,
	resourceName,
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/utils/check-payment-methods.ts">
import {
	CanMakePaymentArgument,
	ExpressPaymentMethodConfigInstance,
	PaymentMethodConfigInstance,
} from '@woocommerce/types';
import { CURRENT_USER_IS_ADMIN, getSetting } from '@woocommerce/settings';
import { dispatch, select } from '@wordpress/data';
import {
	deriveSelectedShippingRates,
	emptyHiddenAddressFields,
} from '@woocommerce/base-utils';
import { __, sprintf } from '@wordpress/i18n';
import {
	getExpressPaymentMethods,
	getPaymentMethods,
} from '@woocommerce/blocks-registry';
import { previewCart } from '@woocommerce/resource-previews';
import {
	ActionCreatorsOf,
	ConfigOf,
	CurriedSelectorsOf,
} from '@wordpress/data/build-types/types';
⋮----
import { noticeContexts } from '../../../../../assets/js/base/context/event-emit';
import {
	EMPTY_CART_ERRORS,
	EMPTY_CART_ITEM_ERRORS,
	EMPTY_EXTENSIONS,
} from '../../constants';
import { defaultCartState } from '../../cart/default-state';
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/utils/filter-active-saved-payment-methods.ts">
import { getPaymentMethods } from '@woocommerce/blocks-registry';
⋮----
import type { SavedPaymentMethods } from '../types';
⋮----
export const filterActiveSavedPaymentMethods = (
	availablePaymentMethods: string[] = [],
	savedPaymentMethods: SavedPaymentMethods
): SavedPaymentMethods =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/utils/set-default-payment-method.ts">
import { select, dispatch } from '@wordpress/data';
import { PlainPaymentMethods } from '@woocommerce/types';
⋮----
import { store as paymentStore } from '../index';
⋮----
export const setDefaultPaymentMethod = async (
	paymentMethods: PlainPaymentMethods
) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/action-types.ts">
export enum ACTION_TYPES {
	SET_PAYMENT_IDLE = 'SET_PAYMENT_IDLE',
	SET_EXPRESS_PAYMENT_STARTED = 'SET_EXPRESS_PAYMENT_STARTED',
	SET_PAYMENT_READY = 'SET_PAYMENT_READY',
	SET_PAYMENT_PROCESSING = 'SET_PAYMENT_PROCESSING',
	SET_PAYMENT_ERROR = 'SET_PAYMENT_ERROR',
	SET_PAYMENT_METHODS_INITIALIZED = 'SET_PAYMENT_METHODS_INITIALIZED',
	SET_EXPRESS_PAYMENT_METHODS_INITIALIZED = 'SET_EXPRESS_PAYMENT_METHODS_INITIALIZED',
	SET_ACTIVE_PAYMENT_METHOD = 'SET_ACTIVE_PAYMENT_METHOD',
	SET_SHOULD_SAVE_PAYMENT_METHOD = 'SET_SHOULD_SAVE_PAYMENT_METHOD',
	SET_AVAILABLE_PAYMENT_METHODS = 'SET_AVAILABLE_PAYMENT_METHODS',
	SET_AVAILABLE_EXPRESS_PAYMENT_METHODS = 'SET_AVAILABLE_EXPRESS_PAYMENT_METHODS',
	SET_REGISTERED_EXPRESS_PAYMENT_METHODS = 'SET_REGISTERED_EXPRESS_PAYMENT_METHODS',
	REMOVE_AVAILABLE_PAYMENT_METHOD = 'REMOVE_AVAILABLE_PAYMENT_METHOD',
	REMOVE_AVAILABLE_EXPRESS_PAYMENT_METHOD = 'REMOVE_AVAILABLE_EXPRESS_PAYMENT_METHOD',
	INITIALIZE_PAYMENT_METHODS = 'INITIALIZE_PAYMENT_METHODS',
	SET_PAYMENT_METHOD_DATA = 'SET_PAYMENT_METHOD_DATA',
	SET_PAYMENT_RESULT = 'SET_PAYMENT_RESULT',
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/actions.ts">
import {
	PlainPaymentMethods,
	PlainExpressPaymentMethods,
} from '@woocommerce/types';
import type { PaymentResult } from '@woocommerce/types';
⋮----
import { ACTION_TYPES } from './action-types';
import { checkPaymentMethodsCanPay } from './utils/check-payment-methods';
import { setDefaultPaymentMethod } from './utils/set-default-payment-method';
⋮----
export const __internalSetPaymentIdle = () => (
⋮----
export const __internalSetExpressPaymentStarted = () => (
⋮----
export const __internalSetPaymentProcessing = () => (
⋮----
export const __internalSetPaymentError = () => (
⋮----
export const __internalSetPaymentReady = () => (
⋮----
export const __internalSetPaymentMethodsInitialized = (
	initialized: boolean
) =>
⋮----
export const __internalSetExpressPaymentMethodsInitialized = (
	initialized: boolean
) => (
⋮----
export const __internalSetShouldSavePaymentMethod = (
	shouldSavePaymentMethod: boolean
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/constants.ts">
export enum STATUS {
	IDLE = 'idle',
	EXPRESS_STARTED = 'express_started',
	PROCESSING = 'processing',
	READY = 'ready',
	ERROR = 'has_error',
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/default-state.ts">
import type {
	EmptyObjectType,
	PaymentResult,
	GlobalPaymentMethod,
} from '@woocommerce/types';
import { getSetting } from '@woocommerce/settings';
import {
	PlainPaymentMethods,
	PlainExpressPaymentMethods,
} from '@woocommerce/types';
⋮----
import { SavedPaymentMethod } from './types';
import { isEditor } from '../utils';
import { STATUS as PAYMENT_STATUS } from './constants';
import { checkoutData } from '../checkout/constants';
⋮----
function getDefaultPaymentMethod()
⋮----
/**
 * Set the default payment method data. This can be in two places,
 * Either as part of the `defaultPaymentMethod` object or
 * as a token stored in `wcSettings`.
 */
function getDefaultPaymentMethodData()
⋮----
// Check if default payment method exists in saved payment methods
⋮----
// If a saved payment method is found that matches the default payment method,
// use it.
⋮----
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/index.ts">
import { createReduxStore, register, subscribe } from '@wordpress/data';
import { controls as dataControls } from '@wordpress/data-controls';
⋮----
import reducer from './reducers';
import { STORE_KEY } from './constants';
⋮----
import { controls as sharedControls } from '../shared-controls';
⋮----
import { pushChanges } from '../checkout/push-changes';
⋮----
export type PaymentStoreDescriptor = typeof store;
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/README.md">
# Payment Store

The docs for the Payment Store can be found in [docs/third-party-developers/extensibility/data-store/payment.md](../../../../docs/third-party-developers/extensibility/data-store/payment.md).
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/reducers.ts">
import type { Reducer } from 'redux';
import { PaymentResult } from '@woocommerce/types';
⋮----
import { defaultPaymentState, PaymentState } from './default-state';
import { ACTION_TYPES } from './action-types';
import { STATUS } from './constants';
⋮----
const reducer: Reducer< PaymentState > = (
	state = defaultPaymentState,
	action
) =>
export type State = ReturnType< typeof reducer >;
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/selectors.ts">
import { objectHasProp } from '@woocommerce/types';
import deprecated from '@wordpress/deprecated';
import { getSetting } from '@woocommerce/settings';
import type { GlobalPaymentMethod } from '@woocommerce/types';
import { createSelector } from '@wordpress/data';
⋮----
import { PaymentState } from './default-state';
import { filterActiveSavedPaymentMethods } from './utils/filter-active-saved-payment-methods';
import { STATUS as PAYMENT_STATUS } from './constants';
⋮----
export const isPaymentPristine = ( state: PaymentState ) =>
⋮----
export const isPaymentIdle = ( state: PaymentState )
⋮----
export const isPaymentStarted = ( state: PaymentState ) =>
⋮----
export const isExpressPaymentStarted = ( state: PaymentState ) =>
⋮----
export const isPaymentProcessing = ( state: PaymentState )
⋮----
export const isPaymentReady = ( state: PaymentState )
⋮----
export const isPaymentSuccess = ( state: PaymentState ) =>
⋮----
export const hasPaymentError = ( state: PaymentState )
⋮----
export const isPaymentFailed = ( state: PaymentState ) =>
⋮----
export const isExpressPaymentMethodActive = ( state: PaymentState ) =>
⋮----
... (38 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/store-config.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/thunks.ts">
import { store as noticesStore } from '@wordpress/notices';
import deprecated from '@wordpress/deprecated';
import type { BillingAddress, ShippingAddress } from '@woocommerce/settings';
import {
	isObject,
	isString,
	objectHasProp,
	ObserverResponse,
	isErrorResponse,
	isFailResponse,
	isSuccessResponse,
} from '@woocommerce/types';
import type {
	ActionCreatorsOf,
	ConfigOf,
	CurriedSelectorsOf,
	DispatchFunction,
	SelectFunction,
} from '@wordpress/data/build-types/types';
import { paymentStore } from '@woocommerce/block-data';
⋮----
import {
	emitEventWithAbort,
	noticeContexts,
} from '../../../../assets/js/base/context/event-emit';
import { EMIT_TYPES } from '../../../../assets/js/base/context/providers/cart-checkout/payment-events/event-emit';
import type { emitProcessingEventType } from './types';
import { store as cartStore } from '../cart';
import {
	isBillingAddress,
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/payment/types.ts">
import {
	PlainPaymentMethods,
	PlainExpressPaymentMethods,
} from '@woocommerce/types';
import type {
	EmptyObjectType,
	ObjectType,
	FieldValidationStatus,
} from '@woocommerce/types';
import { DataRegistry } from '@wordpress/data';
⋮----
import type { EventObserversType } from '@woocommerce/base-context/event-emit';
import type { DispatchFromMap } from '../mapped-types';
⋮----
export interface CardNetworks {
	preferred: string;
}
⋮----
export interface CustomerPaymentMethodConfiguration {
	gateway: string;
	brand: string;
	last4: string;
	display_brand?: string;
	networks?: CardNetworks;
}
export interface SavedPaymentMethod {
	method: CustomerPaymentMethodConfiguration;
	expires: string;
	is_default: boolean;
	tokenId: number;
... (63 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/query-state/action-types.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/query-state/actions.js">
export const setQueryValue = ( context, queryKey, value ) =>
⋮----
export const setValueForQueryContext = ( context, value ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/query-state/constants.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/query-state/index.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/query-state/README.md">
# Query State Store

The docs for the Query State Store can be found in [docs/third-party-developers/extensibility/data-store/query-state.md](../../../../docs/third-party-developers/extensibility/data-store/query-state.md).
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/query-state/reducers.js">
const queryStateReducer = ( state =
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/query-state/selectors.js">
const getParsedContext = ( serialized ) =>
⋮----
export const getValueForQueryKey = (
	state,
	context,
	queryKey,
	defaultValue = {}
) =>
⋮----
export const getValueForQueryContext = (
	state,
	context,
	defaultValue = {}
) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/query-state/utils.js">
export const getStateForContext = ( state, context ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/schema/action-types.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/schema/actions.js">
export function receiveRoutes( routes, namespace = API_BLOCK_NAMESPACE )
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/schema/constants.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/schema/index.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/schema/README.md">
# Schema Store

The docs for the Schema Store can be found in [docs/third-party-developers/extensibility/data-store/schema.md](../../../../docs/third-party-developers/extensibility/data-store/schema.md).
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/schema/reducers.js">
export const receiveRoutes = ( state =
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/schema/resolvers.js">
export function* getRoute( namespace )
⋮----
export function* getRoutes( namespace )
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/schema/selectors.js">
const assembleRouteWithPlaceholders = ( route, routePlaceholders, ids ) =>
⋮----
const getRouteFromResourceEntries = ( stateSlice, ids = [] ) =>
⋮----
/**
 * Returns the requested route for the given arguments.
 *
 * @param {Object} state        The original state.
 * @param {string} namespace    The namespace for the route.
 * @param {string} resourceName The resource being requested
 *                              (eg. products/attributes)
 * @param {Array}  [ids]        This is for any ids that might be implemented in
 *                              the route request. It is not for any query
 *                              parameters.
 *
 *                              Ids example:
 *                              If you are looking for the route for a single product on the `wc/blocks`
 *                              namespace, then you'd have `[ 20 ]` as the ids.  This would produce something
 *                              like `/wc/blocks/products/20`
 *
 *
 * @throws {Error}  If there is no route for the given arguments, then this will
 *                  throw
 *
 * @return {string} The route if it is available.
 */
⋮----
/**
 * Return all the routes for a given namespace.
 *
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/schema/utils.js">
export const extractResourceNameFromRoute = ( namespace, route ) =>
⋮----
/**
 * Returns an array of the identifier for the named capture groups in a given
 * route.
 *
 * For example, if the route was this:
 * /wc/blocks/products/attributes/(?P<attribute_id>[\d]+)/terms/(?P<id>[\d]+)
 *
 * ...then the following would get returned
 * [ 'attribute_id', 'id' ]
 *
 * @param {string} route - The route to extract identifier names from.
 *
 * @return {Array}  An array of named route identifier names.
 */
export const getRouteIds = ( route ) =>
⋮----
export const simplifyRouteWithId = ( route, matchIds ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/store-notices/action-types.ts">
export enum ACTION_TYPES {
	REGISTER_CONTAINER = 'REGISTER_CONTAINER',
	UNREGISTER_CONTAINER = 'UNREGISTER_CONTAINER',
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/store-notices/actions.ts">
import { ACTION_TYPES } from './action-types';
⋮----
export const registerContainer = ( containerContext: string ) =>
⋮----
export const unregisterContainer = ( containerContext: string ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/store-notices/default-state.ts">
export interface StoreNoticesState {
	containers: string[];
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/store-notices/index.ts">
import { createReduxStore, register } from '@wordpress/data';
⋮----
import reducer from './reducers';
⋮----
export type StoreNoticesStoreDescriptor = typeof store;
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/store-notices/README.md">
# Store-Notice Store

The docs for the Schema Store can be found in [docs/third-party-developers/extensibility/data-store/store-notices.md](../../../../docs/third-party-developers/extensibility/data-store/store-notices.md).
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/store-notices/reducers.ts">
import type { Reducer } from 'redux';
⋮----
import { defaultStoreNoticesState, StoreNoticesState } from './default-state';
import { ACTION_TYPES } from './action-types';
⋮----
const reducer: Reducer< StoreNoticesState > = (
	state = defaultStoreNoticesState,
	action
) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/store-notices/selectors.ts">
import { StoreNoticesState } from './default-state';
⋮----
export const getRegisteredContainers = (
	state: StoreNoticesState
): StoreNoticesState[ 'containers' ]
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/utils/clear-put-requests.ts">
import { clearChanges as clearCheckoutChanges } from '../checkout/push-changes';
⋮----
export function clearCheckoutPutRequests(): void
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/utils/has-in-state.ts">
const has = ( obj: Record< string, unknown >, path: string[] ): boolean =>
⋮----
export default function hasInState(
	state: Record< string, unknown >,
	path: string[]
): boolean
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/utils/index.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/utils/is-editor.ts">
import { getPath } from '@wordpress/url';
import { select } from '@wordpress/data';
⋮----
export const isEditor = (): boolean =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/utils/process-error-response.ts">
import { createNotice, DEFAULT_ERROR_MESSAGE } from '@woocommerce/base-utils';
import { decodeEntities } from '@wordpress/html-entities';
import {
	objectHasProp,
	ApiErrorResponse,
	isApiErrorResponse,
	ApiErrorResponseData,
	isObject,
	isString,
} from '@woocommerce/types';
import { noticeContexts } from '@woocommerce/base-context/event-emit/utils';
⋮----
type ApiParamError = {
	param: string;
	id: string;
	code: string;
	message: string;
	data?: ApiErrorResponseData;
};
⋮----
export const getErrorDetails = (
	response: ApiErrorResponse
): ApiParamError[] =>
⋮----
const getErrorContextFromCode = ( code: string ): string =>
⋮----
const getErrorContextFromParam = (
	param: string,
	code: string
): string | undefined =>
... (32 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/utils/update-state.ts">
function updateNested< T >(
	state: T,
	path: string[],
	value: unknown,
	index = 0
): T
⋮----
export default function updateState< T >(
	state: T,
	path: string[],
	value: unknown
): T
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/validation/action-types.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/validation/actions.ts">
import deprecated from '@wordpress/deprecated';
import { FieldValidationStatus } from '@woocommerce/types';
⋮----
import { ACTION_TYPES as types } from './action-types';
⋮----
export const setValidationErrors = (
	errors: Record< string, FieldValidationStatus >
) => (
⋮----
export const clearValidationErrors = ( errors?: string[] | undefined ) => (
⋮----
export const clearAllValidationErrors = () =>
⋮----
export const clearValidationError = ( error: string ) => (
⋮----
export const hideValidationError = ( error: string ) => (
⋮----
export const showValidationError = ( error: string ) => (
⋮----
export const showAllValidationErrors = () => (
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/validation/constants.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/validation/index.ts">
import { createReduxStore, register } from '@wordpress/data';
⋮----
import reducer from './reducers';
import { STORE_KEY } from './constants';
⋮----
export type ValidationStoreDescriptor = typeof store;
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/validation/README.md">
# Validation Store

The docs for the Validation Store can be found in [docs/third-party-developers/extensibility/data-store/validation.md](../../../../docs/third-party-developers/extensibility/data-store/validation.md).
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/validation/reducers.ts">
import type { Reducer } from 'redux';
import isShallowEqual from '@wordpress/is-shallow-equal';
import { isString, FieldValidationStatus } from '@woocommerce/types';
⋮----
import { ACTION_TYPES as types } from './action-types';
⋮----
const reducer: Reducer< Record< string, FieldValidationStatus > > = (
	state: Record< string, FieldValidationStatus > = {},
	action
) =>
⋮----
export type State = ReturnType< typeof reducer >;
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/validation/selectors.ts">
import type { FieldValidationStatus } from '@woocommerce/types';
⋮----
import type { State } from './reducers';
⋮----
export const getValidationError = ( state: State, errorId: string )
⋮----
export const getValidationErrorId = ( state: State, errorId: string ) =>
⋮----
export const hasValidationErrors = ( state: State ) =>
⋮----
export const getValidationErrors = (
	state: State
): Record< string, FieldValidationStatus >
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/constants.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/README.md">
# Data Stores

The docs for the Data Stores can be found in [docs/third-party-developers/extensibility/data-store/README.md](../../../docs/third-party-developers/extensibility/data-store/README.md)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/block-data/shared-controls.ts">
import { __ } from '@wordpress/i18n';
import triggerFetch, { APIFetchOptions } from '@wordpress/api-fetch';
import DataLoader from 'dataloader';
import {
	ApiResponse,
	assertBatchResponseIsValid,
	assertResponseIsValid,
} from '@woocommerce/types';
⋮----
const processHeadersOnFetch = ( headers: Headers ): void =>
⋮----
const triggerBatchFetch = ( keys: readonly APIFetchOptions[] ) =>
⋮----
const batchFetch = async ( request: APIFetchOptions ) =>
⋮----
export const apiFetchWithHeadersControl = ( options: APIFetchOptions )
⋮----
const doApiFetchWithHeaders = ( options: APIFetchOptions )
⋮----
// Parse is disabled here to avoid returning just the body--we also need headers.
⋮----
// Propagate AbortError directly so callers can detect cancelled requests.
⋮----
export const apiFetchWithHeaders = < T = unknown >(
	options: APIFetchOptions
): Promise< T > =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/blocks-registry/get-registered-blocks.ts">
import { innerBlockAreas, RegisteredBlock } from './types';
import { registeredBlocks } from './registered-blocks';
⋮----
export const hasInnerBlocks = ( block: string ): block is innerBlockAreas =>
⋮----
export const getRegisteredBlocks = (
	block: string
): Array< RegisteredBlock > =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/blocks-registry/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/blocks-registry/README.md">
# Blocks Registry <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

-   [How Inner Blocks Work](#how-inner-blocks-work)
-   [Inner Block Areas](#inner-block-areas)
-   [Registering a Block](#registering-a-block)
    -   [Registering a Forced Block](#registering-a-forced-block)
    -   [Passing attributes to your frontend block](#passing-attributes-to-your-frontend-block)
    -   [Registering a Block Component](#registering-a-block-component)
-   [`registerCheckoutBlock( options )`](#registercheckoutblock-options-)
    -   [Usage](#usage)
    -   [Options](#options)
        -   [`metadata` (object, required)](#metadata-object-required)
        -   [`component` (function, required)](#component-function-required)
-   [`getRegisteredBlocks( blockName )`](#getregisteredblocks-blockname-)
    -   [Usage](#usage-1)
-   [`hasInnerBlocks( blockName )`](#hasinnerblocks-blockname-)
    -   [Usage](#usage-2)

This directory contains the Checkout Blocks Registry. This provides functions to **register new Inner Blocks** that can be inserted automatically, or optionally, within the Mini-Cart, Cart and Checkout blocks in certain areas.

Registered Inner Blocks can either be forced within the layout of the Cart/Checkout Block, or they can just be made available to merchants so they can be inserted manually. Inner Blocks registered in this way can also define a component to render on the frontend in place of the Block.

## How Inner Blocks Work

The Checkout Block has several areas in which inner blocks can be registered and added. Once registered, blocks can be inserted by merchants:

![Inner Block Inserter](inserter.png)

... (185 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/blocks-registry/register-checkout-block.ts">
import { registerBlockComponent } from '@woocommerce/blocks-registry';
⋮----
import {
	assertBlockName,
	assertBlockParent,
	assertOption,
	assertBlockComponent,
} from './utils';
import { registeredBlocks } from './registered-blocks';
import type { CheckoutBlockOptions } from './types';
⋮----
export const registerCheckoutBlock = (
	options: CheckoutBlockOptions
): void =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/blocks-registry/registered-blocks.ts">
import type { RegisteredBlocks } from './types';
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/blocks-registry/types.ts">
import type { LazyExoticComponent } from '@wordpress/element';
import type { BlockConfiguration } from '@wordpress/blocks';
import type { RegisteredBlockComponent } from '@woocommerce/types';
⋮----
export enum innerBlockAreas {
	CHECKOUT = 'woocommerce/checkout',
	CHECKOUT_FIELDS = 'woocommerce/checkout-fields-block',
	CHECKOUT_TOTALS = 'woocommerce/checkout-totals-block',
	CONTACT_INFORMATION = 'woocommerce/checkout-contact-information-block',
	SHIPPING_ADDRESS = 'woocommerce/checkout-shipping-address-block',
	BILLING_ADDRESS = 'woocommerce/checkout-billing-address-block',
	SHIPPING_METHOD = 'woocommerce/checkout-shipping-method-block',
	SHIPPING_METHODS = 'woocommerce/checkout-shipping-methods-block',
	PICKUP_LOCATION = 'woocommerce/checkout-pickup-options-block',
	PAYMENT_METHODS = 'woocommerce/checkout-payment-block',
	CART = 'woocommerce/cart',
	EMPTY_CART = 'woocommerce/empty-cart-block',
	FILLED_CART = 'woocommerce/filled-cart-block',
	CART_ITEMS = 'woocommerce/cart-items-block',
	CART_CROSS_SELLS = 'woocommerce/cart-cross-sells-block',
	CART_TOTALS = 'woocommerce/cart-totals-block',
	MINI_CART = 'woocommerce/mini-cart-contents',
	EMPTY_MINI_CART = 'woocommerce/empty-mini-cart-contents-block',
	FILLED_MINI_CART = 'woocommerce/filled-mini-cart-contents-block',
	MINI_CART_TITLE = 'woocommerce/mini-cart-title-block',
	MINI_CART_ITEMS = 'woocommerce/mini-cart-items-block',
	MINI_CART_FOOTER = 'woocommerce/mini-cart-footer-block',
	CART_ORDER_SUMMARY = 'woocommerce/cart-order-summary-block',
	CART_ORDER_SUMMARY_TOTALS = 'woocommerce/cart-order-summary-totals-block',
	CHECKOUT_ORDER_SUMMARY = 'woocommerce/checkout-order-summary-block',
... (26 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/blocks-registry/utils.ts">
import { isObject } from '@woocommerce/types';
⋮----
import { hasInnerBlocks } from './get-registered-blocks';
⋮----
export const assertType = (
	optionName: string,
	option: unknown,
	expectedType: unknown
): void =>
⋮----
export const assertBlockName = ( blockName: string ): void =>
⋮----
export const assertBlockParent = ( blockParent: string | string[] ): void =>
⋮----
export const assertOption = (
	options: unknown,
	optionName: string,
	expectedType: string
): void =>
⋮----
export const assertBlockComponent = (
	options: Record< string, unknown >,
	optionName: string
): void =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/components/checkbox-control/index.tsx">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/components/discounts-meta/index.js">
const Slot = (
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/components/error-boundary/index.js">
class CheckoutSlotErrorBoundary extends Component
⋮----
static getDerivedStateFromError( error )
⋮----
render()
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/components/label/index.ts">
import Label from '../../../blocks-components/label';
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/components/order-local-pickup-packages/index.tsx">
import clsx from 'clsx';
import {
	Cart,
	CartShippingPackageShippingRate,
} from '@woocommerce/type-defs/cart';
import { Component } from '@wordpress/element';
⋮----
import { createSlotFill } from '../../slot';
import type { RadioControlOption } from '../../../blocks-components/radio-control/types';
⋮----
interface ExperimentalOrderLocalPickupPackagesProps {
	extensions: Record< string, unknown >;
	cart: Cart;
	components: Record< string, Component >;
	renderPickupLocation: (
		option: CartShippingPackageShippingRate,
		packageCount: number,
		clientSelectedOption?: string
	) => RadioControlOption;
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/components/order-meta/index.js">
const Slot = (
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/components/order-shipping-packages/index.js">
const Slot = ( {
	className,
	noResultsMessage,
	renderOption,
	extensions,
	cart,
	components,
	context,
	collapsible,
	showItems,
} ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/components/text-input/index.tsx">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/components/validation-input-error/index.tsx">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/components/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/components/README.md">
# Components <!-- omit in toc -->

A library of components to be used for creating common UI elements shared between features of the WooCommerce Cart and Checkout Blocks.

## Usage

When WooCommerce Blocks is installed and activated, these components can be accessed by importing from the `blocks-checkout` package.

```ts
// Aliased import
import { Button } from '@woocommerce/blocks-components';

// Global import
// const { Button } = wc.blocksCheckout;

export default function MyButton() {
	return <Button>Click Me!</Button>;
}
```

These components are here so they can be consumed by extensions.

<!-- FEEDBACK -->

---

[We're hiring!](https://woocommerce.com/careers/) Come work with us!

🐞 Found a mistake, or have a suggestion? [Leave feedback about this document here.](https://github.com/woocommerce/woocommerce/issues/new?assignees=&labels=type%3A+documentation&template=suggestion-for-documentation-improvement-correction.md&title=Feedback%20on%20./packages/public-api/blocks-checkout/components/README.md)

... (2 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/filter-registry/index.ts">
import { __, sprintf } from '@wordpress/i18n';
import { CURRENT_USER_IS_ADMIN } from '@woocommerce/settings';
import deprecated from '@wordpress/deprecated';
import isShallowEqual from '@wordpress/is-shallow-equal';
import type { ComparableObject } from '@wordpress/is-shallow-equal';
import { isNull, isObject, objectHasProp } from '@woocommerce/types';
⋮----
const returnTrue = (): true
⋮----
type CheckoutFilterFunction< U = unknown > = < T >(
	value: T | U,
	extensions: Record< string, unknown >,
	args?: CheckoutFilterArguments
) => T | U;
⋮----
type CheckoutFilterArguments =
	| ( Record< string, unknown > & {
			context?: string;
	  } )
	| null;
⋮----
export const registerCheckoutFilters = (
	namespace: string,
	filters: Record< string, CheckoutFilterFunction >
): void =>
⋮----
export const __experimentalRegisterCheckoutFilters = (
	namespace: string,
	filters: Record< string, CheckoutFilterFunction >
) =>
... (51 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/filter-registry/README.md">
# Filter Registry <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

-   [registerCheckoutFilters](#registercheckoutfilters)
    -   [Usage](#usage)
    -   [Options](#options)
        -   [`namespace (string)`](#namespace-string)
        -   [`filters (object)`](#filters-object)
-   [applyCheckoutFilter](#applycheckoutfilter)
    -   [Usage](#usage-1)
    -   [Options](#options-1)
        -   [`filterName (string, required)`](#filtername-string-required)
        -   [`defaultValue (mixed, required)`](#defaultvalue-mixed-required)
        -   [`extensions`](#extensions)
        -   [`arg (object)`](#arg-object)
        -   [`validation (function)`](#validation-function)
-   [Available Filters](#available-filters)

The filter registry allows callbacks to be registered to manipulate certain values. This is similar to the traditional filter system in WordPress (where you register a callback with a specific filter and return a modified value).

## registerCheckoutFilters

Registers a callback function with an available filter. This function has the following signature:

```ts
(
  namespace: string,
  filters: Record< string, CheckoutFilterFunction >
)
... (105 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/hooks/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/hooks/README.md">
# Checkout Hooks <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

-   [`useValidateCheckout`](#usevalidatecheckout)
    -   [Usage](#usage)
    -   [Return Value](#return-value)

React hooks for checkout functionality.

## `useValidateCheckout`

A hook that validates the checkout form and automatically scrolls to the first validation error if any are found.

This hook is primarily used internally by the `PlaceOrderButton` component to provide the `validate` prop to custom place order button components. However, it can also be used directly if needed.

### Usage

```jsx
// Aliased import
import { useValidateCheckout } from '@woocommerce/blocks-checkout';

// Global import
// const { useValidateCheckout } = wc.blocksCheckout;

const MyComponent = () => {
	const validateCheckout = useValidateCheckout();

	const handleClick = async () => {
		const { hasError } = await validateCheckout();
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/hooks/use-validate-checkout.ts">
import { useCallback } from '@wordpress/element';
import { useDispatch, select } from '@wordpress/data';
import { validationStore } from '@woocommerce/block-data';
import {
	checkoutEventsEmitter,
	CHECKOUT_EVENTS,
} from '@woocommerce/blocks-checkout-events';
import {
	isErrorResponse,
	isFailResponse,
	isSuccessResponse,
} from '@woocommerce/types';
⋮----
const scrollToFirstValidationError = (): void =>
⋮----
export const useValidateCheckout = (): ( () => Promise<
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/slot/index.tsx">
import { CURRENT_USER_IS_ADMIN } from '@woocommerce/settings';
import { Children, cloneElement } from '@wordpress/element';
⋮----
import {
	createSlotFill as baseCreateSlotFill,
	useSlot,
	useSlotFills,
} from 'wordpress-components-slotfill/build-module/slot-fill';
⋮----
import BlockErrorBoundary from '../components/error-boundary';
⋮----
export const hasValidFills = ( fills: [] )
⋮----
type SlotFill = {
	Fill: (
		props: Partial< {
			bubblesVirtually: boolean;
			children: React.ReactNode;
		} >
	) => JSX.Element;
	Slot: (
		props: Partial< {
			bubblesVirtually: boolean;
			children: React.ReactNode;
		} >
	) => JSX.Element;
};
⋮----
export const createSlotFill = ( slotName: string, onError = null ) =>
⋮----
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/slot/README.md">
# Slot and Fill <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

-   [`createSlotFill( slotName )`](#createslotfill-slotname-)
    -   [Usage](#usage)
    -   [Options](#options)
        -   [`slotName (string, required)`](#slotname-string-required)
        -   [`onError (Function)`](#onerror-function)
    -   [`Slot` Component](#slot-component)
        -   [Usage](#usage-1)
        -   [Options](#options-1)
            -   [`as (string|element)`](#as-stringelement)
            -   [`className (string)`](#classname-string)
            -   [`fillProps (object)`](#fillprops-object)
        -   [`Fill` Component](#fill-component)
-   [Extending Checkout via Slot Fills](#extending-checkout-via-slot-fills)
-   [Available Slot Fills](#available-slot-fills)

Slot and Fill are a pair of components which enable developers to render elsewhere in a React element tree, a pattern often referred to as "portal" rendering. It is a pattern for component extensibility, where a single Slot may be occupied by an indeterminate number of Fills elsewhere in the application.

This module is an abstraction on top of the Slot and Fill implementation in WordPress and is meant to be used internally, therefore the documentation only touches the abstraction part. You can read more about Slot and Fill in [@wordpress/components documentation](https://github.com/WordPress/gutenberg/tree/c53d26ea79bdcb1a3007a994078e1fc9e0195466/packages/components/src/slot-fill).

## `createSlotFill( slotName )`

Calling `createSlotFill` with a `slotName` returns two components: `Slot` and `Fill`. Slots are implemented in WooCommerce Blocks, while Fills can be used by extensions to add content within the Slot. A Slot must be called in a tree that has `SlotFillProvider` in it.

### Usage

```jsx
... (165 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/slot/test-utils.tsx">
import { render } from '@testing-library/react';
import { Provider as SlotFillProvider } from 'wordpress-components-slotfill/build-module/slot-fill';
⋮----
type SlotFillComponent = {
	( props: { children: React.ReactNode } ): JSX.Element;
	Slot: ( props: Record< string, unknown > ) => JSX.Element;
};
⋮----
export const renderSlotFill = (
	Fill: SlotFillComponent,
	slotProps: Record< string, unknown > = {}
) =>
⋮----
const FillPropsSpy = ( props: Record< string, unknown > ) =>
⋮----
export const getFillProps = (
	Fill: SlotFillComponent,
	slotProps: Record< string, unknown > = {}
): Record< string, unknown > =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/utils/validation/get-validity-message-for-input.ts">
import { __, sprintf, getLocaleData } from '@wordpress/i18n';
⋮----
export const getFieldLabel = ( label: string | undefined ) =>
⋮----
const defaultValidityMessage =
( label: string | undefined, inputElement: HTMLInputElement )
⋮----
export const getValidityMessageForInput = (
	label: string | undefined,
	inputElement: HTMLInputElement,
	customValidityMessage?: ( validity: ValidityState ) => string
): string =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/utils/validation/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/utils/validation/is-postcode.ts">
import {
	postcodeValidator,
	postcodeValidatorExistsForCountry,
} from 'postcode-validator';
⋮----
import postcodeValidationData from '../../../../../../../i18n/postcode-validation-rules.json';
⋮----
type PostcodeValidationRule = {
	pattern: string;
	flags?: string;
	normalization?: 'removeSpaces' | 'removeSpacesAndHyphens';
};
⋮----
const normalizePostcode = (
	postcode: string,
	normalization?: PostcodeValidationRule[ 'normalization' ]
): string =>
⋮----
export interface IsPostcodeProps {
	postcode: string;
	country: string;
}
⋮----
const isPostcode = (
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/utils/validation/must-contain.ts">
import { __, sprintf } from '@wordpress/i18n';
⋮----
const mustContain = ( value: string, requiredValue: string ): true | never =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/utils/validation/validate-filter.ts">
import mustContain from './must-contain';
⋮----
export const productPriceValidation = ( value: string )
⋮----
export const productPriceScreenReaderValidation = (
	value: string
): true | never =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/utils/extension-cart-update.ts">
import { dispatch } from '@wordpress/data';
import { CartResponse, ExtensionCartUpdateArgs } from '@woocommerce/types';
import { processErrorResponse } from '@woocommerce/block-data';
⋮----
import { STORE_KEY } from '../../block-data/cart/constants';
⋮----
export const extensionCartUpdate = (
	args: ExtensionCartUpdateArgs
): Promise< CartResponse > =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/utils/index.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/utils/README.md">
# Utilities <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

- [`extensionCartUpdate`](#extensioncartupdate)
   	- [`extensionCartUpdate` Usage](#extensioncartupdate-usage)
   	- [`extensionCartUpdate` Options](#extensioncartupdate-options)
      		- [`args (object, required)`](#args-object-required)
- [`mustContain`](#mustcontain)
   	- [`mustContain` Usage](#mustcontain-usage)
   	- [`mustContain` Options](#mustcontain-options)
      		- [`value (string, required)`](#value-string-required)
      		- [`requiredValue (string, required)`](#requiredvalue-string-required)

Miscellaneous utility functions for dealing with checkout functionality.

## `extensionCartUpdate`

When executed, this will call the cart/extensions REST API endpoint. The new cart is then received into the client-side store. `extensionCartUpdate` returns a promise that resolves when the cart is updated which should also be used for error handling.

### `extensionCartUpdate` Usage

```ts
// Aliased import
import { extensionCartUpdate } from '@woocommerce/blocks-checkout';

// Global import
// const { extensionCartUpdate } = wc.blocksCheckout;

extensionCartUpdate( {
... (58 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/index.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/README.md">
# Checkout <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

-   [Installation](#installation)
-   [Usage](#usage)
    -   [Aliased imports](#aliased-imports)
-   [Folder Structure Overview](#folder-structure-overview)

Components and utilities making it possible to integrate with the WooCommerce Mini-Cart, Cart and Checkout Blocks.

## Installation

This package is available as an external when the [WooCommerce Blocks Feature Plugin](https://wordpress.org/plugins/woo-gutenberg-products-block/) is installed and activated.

## Usage

Package components can be accessed via the `wc` global:

```js
const { ... } = wc.blocksCheckout;
```

### Aliased imports

Alternatively, you can map this to externals (or aliases) using the [WooCommerce Dependency Extraction Webpack Plugin](https://github.com/woocommerce/woocommerce-admin/tree/main/packages/dependency-extraction-webpack-plugin). Just add the above Webpack plugin to your package.json:

```bash
npm install @woocommerce/dependency-extraction-webpack-plugin --save-dev
```
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout-events/checkout-events.ts">
import { createEmitter } from './event-emitter';
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout-events/event-emitter.ts">
import {
	isErrorResponse,
	isFailResponse,
	isObserverResponse,
	type ObserverResponse,
	responseTypes,
} from '@woocommerce/types';
⋮----
export type EventListener = (
	data: unknown
) => Promise< ObserverResponse | boolean > | ObserverResponse | boolean;
⋮----
export type EventListenerRegistrationFunction = (
	listener: EventListener,
	priority?: number
) => VoidFunction;
⋮----
export interface EventEmitter {
	emit: (
		eventName: string,
		data?: unknown
	) => Promise< ObserverResponse[] >;
	emitWithAbort: (
		eventName: string,
		data?: unknown
	) => Promise< ObserverResponse[] >;
	subscribe: (
		listener: EventListener,
		priority: number,
		eventName: string
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout-events/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/button/index.ts">
import Button from '@woocommerce/base-components/button';
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/checkbox-control/stories/index.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
import { useEffect, useState } from '@wordpress/element';
⋮----
import CheckboxControl, { CheckboxControlProps } from '..';
⋮----
const Template: StoryFn< CheckboxControlProps > = ( args ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/checkbox-control/index.tsx">
import clsx from 'clsx';
import { useInstanceId } from '@wordpress/compose';
import type { ReactNode, InputHTMLAttributes } from 'react';
import { forwardRef } from '@wordpress/element';
⋮----
export type CheckboxControlProps = {
	label?: ReactNode;
	onChange: ( value: boolean ) => void;
	children?: ReactNode;
	hasError?: boolean;
	errorId?: string;
	errorMessage?: string;
} & Pick<
	InputHTMLAttributes< HTMLInputElement >,
	| 'value'
	| 'name'
	| 'aria-label'
	| 'aria-describedby'
	| 'className'
	| 'id'
	| 'disabled'
	| 'checked'
>;
⋮----
className=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/checkbox-control/validated-checkbox-control.tsx">
import {
	useEffect,
	useCallback,
	forwardRef,
	useImperativeHandle,
	useRef,
	useId,
} from '@wordpress/element';
import clsx from 'clsx';
import { isObject } from '@woocommerce/types';
import { useDispatch, useSelect } from '@wordpress/data';
import { validationStore } from '@woocommerce/block-data';
import type { InputHTMLAttributes } from 'react';
⋮----
import CheckboxControl from './index';
⋮----
import { ValidationInputError } from '../validation-input-error';
import { getValidityMessageForInput } from '../../blocks-checkout/utils';
⋮----
export interface ValidatedCheckboxControlProps
	extends Omit< InputHTMLAttributes< HTMLInputElement >, 'onChange' > {
	instanceId?: string;
	errorId?: string;
	onChange: ( newValue: boolean ) => void;
	label?: string;
	showError?: boolean;
	errorMessage?: string;
	customValidation?:
		| ( ( inputObject: HTMLInputElement ) => boolean )
		| undefined;
... (31 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/checkbox-list/stories/index.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
import { useArgs } from 'storybook/preview-api';
⋮----
import CheckboxList, { type CheckboxListProps } from '..';
⋮----
const Template: StoryFn< CheckboxListProps > = ( args ) =>
⋮----
const onChange = ( checkedOption: string ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/checkbox-list/checkbox-list-option-control.tsx">
import { useInstanceId } from '@wordpress/compose';
⋮----
import { CheckboxControl } from '../checkbox-control';
import type { CheckboxListOptions } from './types';
⋮----
export type CheckboxListOptionControlProps = {
	option: CheckboxListOptions;
	shouldTruncateOptions: boolean;
	showExpanded: boolean;
	index: number;
	limit: number;
	checked: boolean;
	disabled: boolean;
	renderedShowMore: false | JSX.Element;
	onChange: ( value: string ) => void;
};
⋮----
export function CheckboxListOptionControl( {
	option,
	shouldTruncateOptions,
	showExpanded,
	index,
	limit,
	checked,
	disabled,
	renderedShowMore,
	onChange,
}: CheckboxListOptionControlProps )
⋮----
onChange( option.value );
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/checkbox-list/index.tsx">
import { __, _n, sprintf } from '@wordpress/i18n';
import { useMemo, useState } from '@wordpress/element';
import clsx from 'clsx';
⋮----
import { CheckboxListOptionControl } from './checkbox-list-option-control';
import type { CheckboxListOptions } from './types';
⋮----
export interface CheckboxListProps {
	className?: string | undefined;
	isLoading?: boolean | undefined;
	isDisabled?: boolean | undefined;
	limit?: number | undefined;
	checked?: string[] | undefined;
	onChange: ( value: string ) => void | undefined;
	options?: CheckboxListOptions[] | undefined;
}
⋮----
setShowExpanded( true );
⋮----
aria-label=
⋮----
setShowExpanded( false );
⋮----
checked=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/checkbox-list/types.ts">
export interface CheckboxListOptions {
	label: React.ReactNode;
	value: string;
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/chip/stories/chip.stories.tsx">
import type { Meta, StoryFn } from '@storybook/react-webpack5';
⋮----
import Chip, { ChipProps } from '../chip';
⋮----
const Template: StoryFn< ChipProps > = ( args ) => <Chip
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/chip/stories/removable-chip.stories.tsx">
import type { Meta, StoryFn } from '@storybook/react-webpack5';
import { useState } from '@wordpress/element';
⋮----
import { RemovableChip, RemovableChipProps } from '../removable-chip';
⋮----
const Template: StoryFn< RemovableChipProps > = ( args ) =>
⋮----
const handleRemove = () =>
⋮----
<button onClick=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/chip/chip.tsx">
import clsx from 'clsx';
import type { ElementType, HTMLAttributes } from 'react';
⋮----
export interface ChipProps extends HTMLAttributes< HTMLElement > {
	text: string | JSX.Element;
	screenReaderText?: string;
	element?: ElementType;
	className?: string;
	children?: React.ReactNode | React.ReactNode[];
	radius?: 'none' | 'small' | 'medium' | 'large';
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/chip/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/chip/removable-chip.tsx">
import clsx from 'clsx';
import { __, sprintf } from '@wordpress/i18n';
import { Icon, closeSmall } from '@wordpress/icons';
import type { ComponentProps } from 'react';
⋮----
interface IconProps extends Partial< ComponentProps< 'div' > > {
		icon: JSX.Element;
		size?: number;
	}
⋮----
import Chip, { ChipProps } from './chip';
⋮----
export interface RemovableChipProps extends ChipProps {
	ariaLabel?: string;
	className?: string;
	disabled?: boolean;
	onRemove?: () => void;
	removeOnAnyClick?: boolean;
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/form-step/stories/index.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
import { ValidatedTextInput } from '@woocommerce/blocks-checkout';
import { useState } from '@wordpress/element';
⋮----
import FormStep, { type FormStepProps } from '..';
⋮----
const InputWithState = () =>
const Template: StoryFn< FormStepProps > = ( args ) => (
	<div className="wc-block-components-form">
		<FormStep { ...args }>
			<InputWithState />
		</FormStep>
	</div>
);
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/form-step/index.tsx">
import clsx from 'clsx';
⋮----
import Title from '../title';
⋮----
interface StepHeadingProps {
	title: string;
	stepHeadingContent?: JSX.Element | undefined;
}
⋮----
const StepHeading = ( { title, stepHeadingContent }: StepHeadingProps ) => (
	<div className="wc-block-components-checkout-step__heading">
		<Title
			className="wc-block-components-checkout-step__title"
			headingLevel="2"
		>
			{ title }
		</Title>
		{ !! stepHeadingContent && (
			<span className="wc-block-components-checkout-step__heading-content">
				{ stepHeadingContent }
			</span>
		) }
	</div>
);
⋮----
className=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/formatted-monetary-amount/stories/index.stories.tsx">
import type { Meta, StoryFn } from '@storybook/react-webpack5';
import { useArgs } from 'storybook/preview-api';
⋮----
import FormattedMonetaryAmount, { type FormattedMonetaryAmountProps } from '..';
⋮----
const Template: StoryFn< FormattedMonetaryAmountProps > = ( args ) =>
⋮----
const onValueChange = ( unit: number ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/formatted-monetary-amount/index.tsx">
import { NumericFormat } from 'react-number-format';
import type {
	NumberFormatValues,
	NumericFormatProps,
} from 'react-number-format';
import clsx from 'clsx';
import type { ReactElement } from 'react';
import type { Currency } from '@woocommerce/types';
import { SITE_CURRENCY } from '@woocommerce/settings';
import { decodeHtmlEntities } from '@woocommerce/utils';
⋮----
export interface FormattedMonetaryAmountProps
	extends Omit< NumericFormatProps, 'onValueChange' | 'displayType' > {
	className?: string;
	displayType?: NumericFormatProps[ 'displayType' ] | undefined;
	allowNegative?: boolean;
	isAllowed?: ( formattedValue: NumberFormatValues ) => boolean;
	value: number | string;
	currency?: Currency | undefined;
	onValueChange?: ( unit: number ) => void;
	style?: React.CSSProperties | undefined;
	renderText?: NonNullable< NumericFormatProps[ 'renderText' ] >;
}
⋮----
const currencyToNumericFormatProps = ( currency: Currency ) =>
⋮----
/**
 * FormattedMonetaryAmount component.
 *
 * Takes a price and returns a formatted price using the NumericFormat component.
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/label/stories/index.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
⋮----
import Label, { LabelProps } from '..';
⋮----
const Template: StoryFn = ( args ) => <Label
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/label/index.tsx">
import { Fragment, RawHTML } from '@wordpress/element';
import { sanitizeHTML } from '@woocommerce/sanitize';
import clsx from 'clsx';
import type { ReactElement, HTMLProps } from 'react';
⋮----
export interface LabelProps extends HTMLProps< HTMLElement > {
	label?: string | undefined;
	allowHTML?: boolean | undefined;
	screenReaderLabel?: string | undefined;
	wrapperElement?: string | undefined;
	wrapperProps?: HTMLProps< HTMLElement > | undefined;
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/panel/stories/index.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
import { useArgs } from 'storybook/preview-api';
⋮----
import Panel, { type PanelProps } from '..';
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/panel/index.tsx">
import { useState } from '@wordpress/element';
import clsx from 'clsx';
import { Icon, chevronUp, chevronDown } from '@wordpress/icons';
import type { ReactNode, ReactElement } from 'react';
import { Button } from '@ariakit/react';
import deprecated from '@wordpress/deprecated';
⋮----
export interface PanelProps {
	children: ReactNode;
	className?: string | undefined;
	initialOpen?: boolean;
	hasBorder?: boolean;
	headingLevel?: 2 | 3 | 4 | 5 | 6;
	title: ReactNode;
	titleTag?: keyof JSX.IntrinsicElements;
	state?: [ boolean, React.Dispatch< React.SetStateAction< boolean > > ];
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/radio-control/stories/index.stories.tsx">
import type { Meta, StoryFn } from '@storybook/react-webpack5';
import { useArgs } from 'storybook/preview-api';
⋮----
import RadioControl from '..';
import { RadioControlProps } from '../types';
⋮----
const Template: StoryFn< RadioControlProps > = ( args ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/radio-control/index.tsx">
import clsx from 'clsx';
import { useInstanceId } from '@wordpress/compose';
import { useMemo } from '@wordpress/element';
⋮----
import RadioControlOption from './option';
import type { RadioControlProps } from './types';
⋮----
className=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/radio-control/option-layout.tsx">
import clsx from 'clsx';
⋮----
import type { RadioControlOptionLayout } from './types';
⋮----
className=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/radio-control/option.tsx">
import clsx from 'clsx';
⋮----
import OptionLayout from './option-layout';
import type { RadioControlOptionProps } from './types';
⋮----
const Option = ( {
	checked,
	name,
	onChange,
	option,
	disabled = false,
	highlightChecked = false,
	descriptionStackingDirection,
}: RadioControlOptionProps ) =>
⋮----
const onChangeValue = ( event: React.ChangeEvent< HTMLInputElement > )
⋮----
className=
⋮----
aria-describedby={ clsx( {
					[ `${ name }-${ value }__secondary-label` ]: secondaryLabel,
					[ `${ name }-${ value }__description` ]: description,
					[ `${ name }-${ value }__secondary-description` ]:
						secondaryDescription,
					[ `${ name }-${ value }__content` ]: content,
				} ) }
				aria-disabled={ disabled }
onKeyDown=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/radio-control/types.ts">
import type { ReactElement } from 'react';
⋮----
export interface RadioControlProps {
	className?: string;
	id?: string;
	selected: string;
	onChange: ( value: string ) => void;
	options: RadioControlOption[];
	disabled?: boolean;
	highlightChecked?: boolean;
	descriptionStackingDirection?: 'column' | 'row';
}
⋮----
export interface RadioControlOptionProps {
	checked: boolean;
	name?: string;
	onChange: ( value: string ) => void;
	option: RadioControlOption;
	disabled?: boolean;
	highlightChecked?: boolean;
	descriptionStackingDirection?: 'column' | 'row' | undefined;
}
⋮----
interface RadioControlOptionContent {
	label: string | JSX.Element;
	content?: string | JSX.Element;
	description?: string | ReactElement | undefined;
	secondaryLabel?: string | ReactElement | undefined;
	secondaryDescription?: string | ReactElement | undefined;
}
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/radio-control-accordion/stories/index.stories.tsx">
import type { Meta, StoryFn } from '@storybook/react-webpack5';
import { useArgs } from 'storybook/preview-api';
⋮----
import { RadioControlAccordion, RadioControlAccordionProps } from '..';
⋮----
const Template: StoryFn< RadioControlAccordionProps > = ( args ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/radio-control-accordion/index.tsx">
import clsx from 'clsx';
import { withInstanceId } from '@wordpress/compose';
import { useMemo } from '@wordpress/element';
⋮----
import { RadioControlOption } from '../radio-control';
⋮----
export interface RadioControlAccordionProps {
	className?: string;
	instanceId: number;
	id: string;
	onChange: ( value: string ) => void;
	options: Array< {
		value: string;
		label: string | JSX.Element;
		onChange?: ( value: string ) => void;
		name: string;
		content: JSX.Element;
	} >;
	selected: string | null;
	highlightChecked?: boolean;
}
⋮----
className=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/sort-select/stories/index.stories.tsx">
import type { Meta, StoryFn } from '@storybook/react-webpack5';
import { useArgs } from 'storybook/preview-api';
⋮----
import { SortSelect, type SortSelectProps } from '..';
⋮----
const Template: StoryFn< SortSelectProps > = ( args ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/sort-select/index.tsx">
import clsx from 'clsx';
import { withInstanceId } from '@wordpress/compose';
import type { ChangeEventHandler } from 'react';
⋮----
import Label from '../label';
⋮----
export interface SortSelectProps {
	instanceId: number;
	className?: string;
	label?: string;
	onChange: ChangeEventHandler< HTMLSelectElement >;
	options: {
		key: string;
		label: string;
	}[];
	screenReaderLabel: string;
	value?: string;
	readOnly?: boolean;
}
⋮----
export const SortSelect = ( {
	className,
	instanceId,
	label = '',
	onChange,
	options,
	screenReaderLabel,
	value = '',
	readOnly = false,
}: SortSelectProps ): JSX.Element =>
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/spinner/stories/index.stories.tsx">
import type { Meta, StoryFn } from '@storybook/react-webpack5';
⋮----
import Spinner from '..';
⋮----
const Template: StoryFn = ()
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/spinner/index.tsx">
const Spinner = (): JSX.Element =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/store-notice/stories/index.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
import { NoticeBannerProps } from '@woocommerce/base-components/notice-banner';
⋮----
import StoreNotice from '../';
⋮----
const Template: StoryFn< NoticeBannerProps > = (
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/store-notice/index.tsx">
import clsx from 'clsx';
import NoticeBanner, {
	NoticeBannerProps,
} from '@woocommerce/base-components/notice-banner';
⋮----
const StoreNotice = ( {
	className,
	children,
	status,
	...props
}: NoticeBannerProps ) =>
⋮----
className=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/store-notices-container/index.tsx">
import { useSelect, useDispatch } from '@wordpress/data';
import { paymentStore, storeNoticesStore } from '@woocommerce/block-data';
import { getNoticeContexts } from '@woocommerce/base-utils';
import type { WPNotice } from '@wordpress/notices/build-types/store/selectors';
import { useMemo, useEffect } from '@wordpress/element';
import type { NoticeType } from '@woocommerce/types';
import { store as noticesStore } from '@wordpress/notices';
⋮----
import StoreNotices from './store-notices';
import SnackbarNotices from './snackbar-notices';
import type { StoreNoticesContainerProps } from './types';
⋮----
const formatNotices = (
	notices: WPNotice[],
	context: string
): NoticeType[] =>
⋮----
// Find sub-contexts that have not been registered. We will show notices from those contexts here too.
⋮----
// Pull the raw notices arrays out of the notices store, keyed by context.
// Keeping the shape flat (a plain object of stable array references) lets
// @wordpress/data's SCRIPT_DEBUG unstable-reference check pass — the
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/store-notices-container/snackbar-notices.tsx">
import clsx from 'clsx';
import SnackbarList from '@woocommerce/base-components/snackbar-list';
import { useDispatch } from '@wordpress/data';
import type { NoticeType } from '@woocommerce/types';
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/store-notices-container/store-notices.tsx">
import { _n } from '@wordpress/i18n';
import clsx from 'clsx';
import { useRef, useEffect, RawHTML } from '@wordpress/element';
import { sanitizeHTML } from '@woocommerce/sanitize';
import { useDispatch } from '@wordpress/data';
import { usePrevious } from '@woocommerce/base-hooks';
import { decodeEntities } from '@wordpress/html-entities';
import type { NoticeStatus, NoticeType } from '@woocommerce/types';
import type { NoticeBannerProps } from '@woocommerce/base-components/notice-banner';
⋮----
import StoreNotice from '../store-notice';
⋮----
const StoreNoticeList = ( {
	notices,
}: {
	notices: ( Pick< NoticeType, 'id' | 'content' > &
		Partial< Pick< NoticeType, 'context' > > )[];
⋮----
? _n(
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/store-notices-container/types.ts">
import type { NoticeType } from '@woocommerce/types';
⋮----
export interface StoreNoticesContainerProps {
	className?: string | undefined;
	context?: string | string[];
	additionalNotices?: NoticeType[];
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/text-input/stories/text-input.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
import { action } from 'storybook/actions';
import { useArgs } from 'storybook/preview-api';
⋮----
import TextInput, { type TextInputProps } from '../text-input';
⋮----
const Template: StoryFn< TextInputProps > = ( args ) =>
⋮----
const onChange = ( value: string ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/text-input/stories/validated-text-input.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
import { action } from 'storybook/actions';
import { useArgs } from 'storybook/preview-api';
import { useDispatch } from '@wordpress/data';
import { validationStore } from '@woocommerce/block-data';
import { useState, useEffect } from '@wordpress/element';
⋮----
import ValidatedTextInput from '../validated-text-input';
⋮----
import { ValidatedTextInputProps } from '../types';
⋮----
const getFormattedValue = (
	val: string | number | readonly string[] | undefined,
	customFormatter?: ValidatedTextInputProps[ 'customFormatter' ]
) =>
⋮----
const Template: StoryFn< ValidatedTextInputProps > = ( args ) =>
⋮----
const onChange = ( newValue: string ) =>
⋮----
// Always show error for WithError story.
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/text-input/text-input.tsx">
import clsx from 'clsx';
import {
	forwardRef,
	isValidElement,
	useMemo,
	useState,
} from '@wordpress/element';
import { decodeEntities } from '@wordpress/html-entities';
import type { InputHTMLAttributes, ReactNode } from 'react';
⋮----
import Label from '../label';
⋮----
export interface TextInputProps
	extends Omit<
		InputHTMLAttributes< HTMLInputElement >,
		'onChange' | 'onBlur'
	> {
	id: string;
	ariaLabel?: string;
	label?: string | undefined;
	ariaDescribedBy?: string | undefined;
	screenReaderLabel?: string | undefined;
	help?: string;
	feedback?: ReactNode | null;
	autoComplete?: string | undefined;
	onChange: ( newValue: string ) => void;
	onBlur?: ( newValue: string ) => void;
	icon?: ReactNode;
}
⋮----
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/text-input/types.ts">
import type { InputHTMLAttributes, ReactNode } from 'react';
⋮----
export interface ValidatedTextInputProps
	extends Omit<
		InputHTMLAttributes< HTMLInputElement >,
		'onChange' | 'onBlur'
	> {
	instanceId?: string;
	ariaDescribedBy?: string;
	errorId?: string;
	feedback?: JSX.Element | null;
	focusOnMount?: boolean;
	onChange: ( newValue: string ) => void;
	label?: string;
	showError?: boolean;
	errorMessage?: string | undefined;
	customValidation?: ( inputObject: HTMLInputElement ) => boolean;
	customValidityMessage?: ( validity: ValidityState ) => string;
	customFormatter?: ( value: string ) => string;
	validateOnMount?: boolean;
	icon?: ReactNode;
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/text-input/validated-text-input.tsx">
import {
	useEffect,
	useState,
	useCallback,
	forwardRef,
	useImperativeHandle,
	useRef,
} from '@wordpress/element';
import clsx from 'clsx';
import { isObject } from '@woocommerce/types';
import { useDispatch, useSelect } from '@wordpress/data';
import { validationStore } from '@woocommerce/block-data';
import { usePrevious } from '@woocommerce/base-hooks';
import { useInstanceId } from '@wordpress/compose';
⋮----
import TextInput from './text-input';
⋮----
import { ValidationInputError } from '../validation-input-error';
import { getValidityMessageForInput } from '../../blocks-checkout/utils';
import { ValidatedTextInputProps } from './types';
⋮----
export type ValidatedTextInputHandle = {
	focus?: () => void;
	revalidate: () => void;
	isFocused: () => boolean;
	setErrorMessage: ( errorMessage: string ) => void;
	inputRef: React.RefObject< HTMLInputElement >;
};
⋮----
// True on mount.
... (37 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/textarea/stories/index.stories.tsx">
import type { Meta, StoryFn } from '@storybook/react-webpack5';
import { useArgs } from 'storybook/preview-api';
⋮----
import Textarea, { type TextareaProps } from '..';
⋮----
const Template: StoryFn< TextareaProps > = ( args ) =>
⋮----
onTextChange=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/textarea/index.tsx">
import clsx from 'clsx';
⋮----
export interface TextareaProps {
	className?: string;
	disabled: boolean;
	onTextChange: ( newText: string ) => void;
	placeholder: string;
	value: string;
}
⋮----
className=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/title/stories/index.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
⋮----
import Title, { type TitleProps } from '..';
⋮----
const Template: StoryFn< TitleProps > = ( args ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/title/index.tsx">
import clsx from 'clsx';
import type { ReactNode } from 'react';
⋮----
const Title = ( {
	children,
	className = '',
	headingLevel,
	...props
}: TitleProps ): JSX.Element =>
⋮----
className=
⋮----
export interface TitleProps {
	headingLevel: '1' | '2' | '3' | '4' | '5' | '6';
	className?: string | undefined;
	children: ReactNode;
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/totals/fees/stories/index.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
import {
	currenciesAPIShape,
	currencies,
	currencyControl,
} from '@woocommerce/storybook-controls';
⋮----
import Fees, { TotalsFeesProps } from '..';
⋮----
type StorybookTotalFeesProps = TotalsFeesProps & { total: string };
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/totals/fees/index.tsx">
import clsx from 'clsx';
import { __ } from '@wordpress/i18n';
import { getSetting } from '@woocommerce/settings';
import type { CartFeeItem, Currency } from '@woocommerce/types';
import type { ReactElement } from 'react';
⋮----
import TotalsItem from '../item';
⋮----
export interface TotalsFeesProps {
	currency: Currency;
	cartFees: CartFeeItem[];
	className?: string;
}
⋮----
className=
⋮----
getSetting( 'displayCartPricesIncludingTax', false )
								? feesValue + feesTaxValue
								: feesValue
						}
					/>
				);
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/totals/item/stories/index.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
import { currencies, currencyControl } from '@woocommerce/storybook-controls';
⋮----
import Item, { TotalsItemProps } from '..';
⋮----
const Template: StoryFn< TotalsItemProps > = ( args ) => <Item
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/totals/item/index.tsx">
import clsx from 'clsx';
import { isValidElement } from '@wordpress/element';
import type { ReactElement, ReactNode } from 'react';
import type { Currency } from '@woocommerce/types';
import { Skeleton } from '@woocommerce/base-components/skeleton';
import { DelayedContentWithSkeleton } from '@woocommerce/base-components/delayed-content-with-skeleton';
import { __ } from '@wordpress/i18n';
⋮----
import FormattedMonetaryAmount from '../../formatted-monetary-amount';
⋮----
export interface TotalsItemProps {
	className?: string | undefined;
	currency?: Currency | undefined;
	label: string;
	value: number | ReactNode;
	description?: ReactNode;
	showSkeleton?: boolean;
	skeleton?: ReactElement;
}
⋮----
const TotalsItemValue = ( {
	value,
	currency,
}: Partial< TotalsItemProps > ): ReactElement | null =>
⋮----
<div className=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/totals/subtotal/stories/index.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
import { currencies, currencyControl } from '@woocommerce/storybook-controls';
⋮----
import Subtotal, { SubtotalProps } from '..';
⋮----
type StorybookSubtotalProps = SubtotalProps & { total_items: string };
⋮----
const Template: StoryFn< StorybookSubtotalProps > = ( args ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/totals/subtotal/index.tsx">
import { __ } from '@wordpress/i18n';
import { getSetting } from '@woocommerce/settings';
import type { Currency } from '@woocommerce/types';
import type { ReactElement } from 'react';
⋮----
import TotalsItem from '../item';
⋮----
interface Values {
	total_items: string;
	total_items_tax: string;
}
⋮----
export interface SubtotalProps {
	className?: string;
	currency: Currency;
	values: Values | Record< string, never >;
	showSkeleton?: boolean;
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/totals/taxes/stories/index.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
import { currencies, currencyControl } from '@woocommerce/storybook-controls';
⋮----
import Taxes, { TotalsTaxesProps } from '..';
⋮----
const Template: StoryFn< TotalsTaxesProps > = ( args ) => <Taxes
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/totals/taxes/index.tsx">
import clsx from 'clsx';
import { __ } from '@wordpress/i18n';
import { getSetting } from '@woocommerce/settings';
import type { CartTotalsTaxLineItem, Currency } from '@woocommerce/types';
import type { ReactElement } from 'react';
⋮----
import TotalsItem from '../item';
⋮----
interface Values {
	tax_lines: CartTotalsTaxLineItem[];
	total_tax: string;
}
⋮----
export interface TotalsTaxesProps {
	className?: string;
	currency: Currency;
	showRateAfterTaxName: boolean;
	values: Values | Record< string, never >;
	showSkeleton?: boolean;
}
⋮----
className=
⋮----
value=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/totals/index.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/totals-wrapper/docs/docs.mdx">
import { Canvas, Meta, ArgTypes, Primary, Source, Controls } from '@storybook/addon-docs/blocks';

import * as TotalsWrapperStories from '../stories/index.stories.tsx';

<Meta name="Docs" of={ TotalsWrapperStories } />

# TotalsWrapper

A wrapper to go around any items displayed in the "Totals" area of the Cart/Checkout blocks. Usually it comes with additional padding so the component rendered inside it doesn't need to add its own padding. If this is being used to wrap a Slot (for use in Slot/Fill patterns) then no padding will be applied.

<Primary />

### Props

<Controls />
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/totals-wrapper/stories/index.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
⋮----
import TotalsWrapper, { TotalsWrapperProps } from '..';
⋮----
const Template: StoryFn< TotalsWrapperProps > = ( args ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/totals-wrapper/index.tsx">
import clsx from 'clsx';
import { Children } from '@wordpress/element';
import type { ReactNode } from 'react';
⋮----
export interface TotalsWrapperProps {
	children: ReactNode;
	slotWrapper?: boolean;
	className?: string;
}
⋮----
const TotalsWrapper = ( {
	children,
	slotWrapper = false,
	className,
}: TotalsWrapperProps ): JSX.Element | null =>
⋮----
className=
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/validation-input-error/stories/index.stories.tsx">
import type { StoryFn, Meta } from '@storybook/react-webpack5';
⋮----
import ValidationInputError, { type ValidationInputErrorProps } from '..';
⋮----
const Template: StoryFn< ValidationInputErrorProps > = ( args ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/validation-input-error/index.tsx">
import { useSelect } from '@wordpress/data';
import { validationStore } from '@woocommerce/block-data';
import { Icon, cautionFilled } from '@wordpress/icons';
⋮----
export interface ValidationInputErrorProps {
	errorMessage?: string;
	propertyName?: string;
	elementId?: string;
}
⋮----
export const ValidationInputError = ( {
	errorMessage = '',
	propertyName = '',
	elementId = '',
}: ValidationInputErrorProps ): JSX.Element | null =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-components/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-registry/block-components/get-registered-block-components.ts">
import deprecated from '@wordpress/deprecated';
import type { RegisteredBlockComponent } from '@woocommerce/types';
⋮----
import { registeredBlockComponents } from './registered-block-components-init';
⋮----
export function getRegisteredBlockComponents(
	context: string
): Record< string, RegisteredBlockComponent >
⋮----
export function getRegisteredInnerBlocks(
	main: string
): Record< string, RegisteredBlockComponent >
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-registry/block-components/index.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-registry/block-components/register-block-component.js">
const assertOption = ( options, optionName, expectedType ) =>
⋮----
const assertBlockComponent = ( options, optionName ) =>
⋮----
export function registerBlockComponent( options )
⋮----
export function registerInnerBlock( options )
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-registry/block-components/registered-block-components-init.ts">
import type { RegisteredBlockComponent } from '@woocommerce/types';
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-registry/payment-methods/assertions.ts">
import { isValidElement } from '@wordpress/element';
import type { ReactNode } from 'react';
import type {
	PaymentMethodConfiguration,
	ExpressPaymentMethodConfiguration,
} from '@woocommerce/types';
⋮----
export const assertValidPaymentMethodComponent = (
	component: () => unknown,
	componentName: string
): void =>
⋮----
export const assertValidElement = (
	element: ReactNode,
	elementName: string
): void =>
⋮----
export const assertValidElementOrString = (
	element: ReactNode,
	elementName: string
): void =>
⋮----
export const assertConfigHasProperties = (
	config: ExpressPaymentMethodConfiguration | PaymentMethodConfiguration,
	expectedProperties: string[] = []
): void =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-registry/payment-methods/express-payment-method-config.ts">
import type { ReactNode } from 'react';
import type {
	ExpressPaymentMethodConfiguration,
	Supports,
	CanMakePaymentCallback,
	ExpressPaymentMethodConfigInstance,
} from '@woocommerce/types';
⋮----
import { getCanMakePayment } from './payment-method-config-helper';
import { assertConfigHasProperties, assertValidElement } from './assertions';
⋮----
export default class ExpressPaymentMethodConfig
implements ExpressPaymentMethodConfigInstance
⋮----
constructor( config: ExpressPaymentMethodConfiguration )
⋮----
get canMakePayment(): CanMakePaymentCallback
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-registry/payment-methods/extensions-config.ts">
import { CanMakePaymentExtensionCallback } from '@woocommerce/types';
⋮----
type CanMakePaymentExtensionCallbacks = Record<
	string,
	CanMakePaymentExtensionCallback
>;
export type NamespacedCanMakePaymentExtensionsCallbacks = Record<
	string,
	CanMakePaymentExtensionCallbacks
>;
export type ExtensionNamespace =
	keyof NamespacedCanMakePaymentExtensionsCallbacks;
export type PaymentMethodName = keyof CanMakePaymentExtensionCallbacks;
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-registry/payment-methods/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-registry/payment-methods/payment-method-config-helper.ts">
import type {
	CanMakePaymentCallback,
	CanMakePaymentExtensionCallback,
} from '@woocommerce/types';
⋮----
import {
	NamespacedCanMakePaymentExtensionsCallbacks,
	PaymentMethodName,
	ExtensionNamespace,
	extensionsConfig,
} from './extensions-config';
⋮----
export const canMakePaymentWithFeaturesCheck =
	(
		canMakePayment: CanMakePaymentCallback,
		features: string[]
): CanMakePaymentCallback
⋮----
export const canMakePaymentWithExtensions =
	(
		canMakePayment: CanMakePaymentCallback,
		extensionsCallbacks: NamespacedCanMakePaymentExtensionsCallbacks,
		paymentMethodName: PaymentMethodName
): CanMakePaymentCallback
⋮----
export const getCanMakePayment = (
	canMakePayment: CanMakePaymentCallback,
	features: string[],
	paymentMethodName: string
): CanMakePaymentCallback =>
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-registry/payment-methods/payment-method-config.tsx">
import deprecated from '@wordpress/deprecated';
import type { ReactNode } from 'react';
import type {
	PaymentMethodConfiguration,
	Supports,
	CanMakePaymentCallback,
	PaymentMethodConfigInstance,
	PaymentMethodIcons,
	CustomPlaceOrderButtonComponent,
} from '@woocommerce/types';
⋮----
import { getCanMakePayment } from './payment-method-config-helper';
import {
	assertConfigHasProperties,
	assertValidElement,
	assertValidElementOrString,
} from './assertions';
⋮----
const NullComponent = () =>
⋮----
export default class PaymentMethodConfig
implements PaymentMethodConfigInstance
⋮----
constructor( config: PaymentMethodConfiguration )
⋮----
get canMakePayment(): CanMakePaymentCallback
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-registry/payment-methods/registry.ts">
import deprecated from '@wordpress/deprecated';
import type {
	PaymentMethodConfiguration,
	ExpressPaymentMethodConfiguration,
	CanMakePaymentExtensionCallback,
	PaymentMethodConfigInstance,
	PaymentMethods,
	ExpressPaymentMethods,
} from '@woocommerce/types';
import { dispatch } from '@wordpress/data';
import {
	ActionCreatorsOf,
	ConfigOf,
	DispatchReturn,
} from '@wordpress/data/build-types/types';
⋮----
import { STORE_KEY as PAYMENT_STORE_KEY } from '../../block-data/payment/constants';
import type { PaymentStoreDescriptor } from '../../block-data/payment';
import { default as PaymentMethodConfig } from './payment-method-config';
import { default as ExpressPaymentMethodConfig } from './express-payment-method-config';
import { canMakePaymentExtensionsCallbacks } from './extensions-config';
⋮----
type LegacyRegisterPaymentMethodFunction = ( config: unknown ) => unknown;
type LegacyRegisterExpressPaymentMethodFunction = (
	config: unknown
) => unknown;
⋮----
export const registerPaymentMethod = (
	options: PaymentMethodConfiguration | LegacyRegisterPaymentMethodFunction
): void =>
... (24 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-registry/product-collection/register-product-collection.tsx">
import { BlockVariation } from '@wordpress/blocks';
import { addFilter } from '@wordpress/hooks';
import { EditorBlock } from '@woocommerce/types';
import type { ElementType } from '@wordpress/element';
import type { BlockEditProps, BlockAttributes } from '@wordpress/blocks';
import {
	SetPreviewState,
	PreviewState,
	ProductCollectionAttributes,
	CoreFilterNames,
} from '@woocommerce/blocks/product-collection/types';
import {
	DEFAULT_ATTRIBUTES,
	INNER_BLOCKS_TEMPLATE,
	PRODUCT_COLLECTION_BLOCK_NAME as BLOCK_NAME,
	DEFAULT_QUERY,
} from '@woocommerce/blocks/product-collection/constants';
⋮----
export interface ProductCollectionConfig extends BlockVariation {
	preview?: {
		setPreviewState?: SetPreviewState;
		initialPreviewState?: PreviewState;
	};
	usesReference?: string[];
}
⋮----
const isValidCollectionConfig = ( config: ProductCollectionConfig ) =>
⋮----
export const __experimentalRegisterProductCollection = (
	config: ProductCollectionConfig
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/blocks-registry/index.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/entity-registration/deprecated-exports.ts">
import deprecated from '@wordpress/deprecated';
⋮----
import {
	isExternalProduct as isExternalProductInternal,
	isProductResponseItem as isProductResponseItemInternal,
	useProduct as useProductInternal,
} from '../../internal/entities';
⋮----
const showDeprecationNotice = ( functionName: string ) =>
⋮----
export const useProduct: typeof useProductInternal = ( postId ) =>
⋮----
export const isExternalProduct: typeof isExternalProductInternal = (
	product
) =>
⋮----
export const isProductResponseItem: typeof isProductResponseItemInternal = (
	product
) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/entity-registration/index.ts">
import { isExperimentalWcRestApiV4Enabled } from '../../../assets/js/settings/blocks/feature-flags';
import {
	registerProductEntity,
	registerSettingsEntity,
} from './register-entities';
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/entity-registration/README.md">
# Entity registration compatibility entry

This directory contains the source entry for the `wc-entities` script. Entity
registration is an internal runtime concern, but this entry remains under
`public-api` because the generated script preserves an externally exposed
compatibility surface.

## Why this lives under `public-api`

The `wc-entities` script historically exposed entity helpers through the
`wc.wcEntities` browser global. Extensions may still depend on that global, so
moving the implementation does not make it safe to remove or rename its
exports.

The global and its helper exports are deprecated as of WooCommerce 11.1.0.
They remain available during the deprecation window and emit a warning when
called. Keeping the compatibility entry under `public-api` makes that
backward-compatibility obligation explicit and helps prevent the legacy
surface from being removed accidentally.

This placement does not make `entity-registration` a new supported package for
extensions. New code must not import it or use `wc.wcEntities`.

## Internal responsibilities

The entry also registers WooCommerce entities as a side effect when WordPress
loads the `wc-entities` script. That registration behavior and the pure entity
helpers under [`packages/internal/entities`](../../internal/entities) remain
internal implementation details.

... (3 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/entity-registration/register-entities.ts">
import { store as coreStore } from '@wordpress/core-data';
import { dispatch } from '@wordpress/data';
⋮----
import { PRODUCT_ENTITY } from '../../internal/entities/product/constants';
import { SETTINGS_ENTITY } from '../../internal/entities/settings/constants';
⋮----
export const registerProductEntity = () =>
⋮----
export const registerSettingsEntity = () =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/price-format/utils/currency.ts">
import type { Currency, CurrencyResponse } from '@woocommerce/types';
⋮----
const splitDecimal = (
	numberString: string
):
⋮----
const applyDecimal = (
	afterDecimal: string,
	decimalSeparator: string,
	minorUnit: number
): string =>
⋮----
const applyThousandSeparator = (
	numberString: string,
	thousandSeparator: string
): string =>
⋮----
export const normalizeCurrencyResponse = (
	currencyData: Partial< CurrencyResponse > | undefined,
	defaultCurrency: Currency
): Currency =>
⋮----
const formatNumberAsCurrencyString = (
	priceInt: number,
	currency: Currency
): string =>
⋮----
export const formatPriceWithCurrency = (
	price: number | string,
	defaultCurrency: Currency,
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/price-format/utils/index.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/price-format/utils/price.ts">
import { SITE_CURRENCY } from '@woocommerce/settings';
import type {
	Currency,
	CurrencyResponse,
	CartShippingPackageShippingRate,
} from '@woocommerce/types';
⋮----
import { formatPriceWithCurrency, normalizeCurrencyResponse } from './currency';
⋮----
export const getCurrencyFromPriceResponse = (
	currencyData?:
		| CurrencyResponse
		| Record< string, never >
		| CartShippingPackageShippingRate
): Currency =>
⋮----
export const getCurrency = (
	currencyData: Partial< Currency > = {}
): Currency =>
⋮----
export const formatPrice = (
	price: number | string,
	currencyData?: Currency
): string =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/price-format/index.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/settings/default-constants.ts">
import type { Currency, SymbolPosition } from '@woocommerce/types';
⋮----
import { allSettings } from './settings-init';
import { getCurrencyPrefix, getCurrencySuffix } from './utils';
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/settings/default-fields.ts">
import type { DocumentObject } from '@woocommerce/base-hooks';
import type { JSONSchemaType } from 'ajv';
import type { AllHTMLAttributes, AriaAttributes } from 'react';
import { isFormFields } from '@woocommerce/types';
⋮----
import type { SelectOption } from '@woocommerce/base-components/select';
import { getSettingWithCoercion } from './utils';
⋮----
type CustomFieldAttributes = Pick<
	AllHTMLAttributes< HTMLInputElement >,
	| 'maxLength'
	| 'readOnly'
	| 'pattern'
	| 'title'
	| 'autoCapitalize'
	| 'autoComplete'
> &
	AriaAttributes;
⋮----
export interface Field {
	label: string;
	optionalLabel: string;
	autocomplete: string;
	autocapitalize?: string;
	required: boolean | JSONSchemaType< DocumentObject< 'global' > > | [];
	hidden: boolean | JSONSchemaType< DocumentObject< 'global' > > | [];
	validation: JSONSchemaType< DocumentObject< 'global' > > | [];
	index: number;
	type?: string;
	options?: SelectOption[];
... (67 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/settings/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/settings/settings-init.ts">
import { SymbolPosition, CurrencyCode } from '@woocommerce/types';
⋮----
interface Window {
		wcSettings: Record< string, unknown >;
	}
⋮----
export interface WooCommerceSiteCurrency {
	code: CurrencyCode;
	precision: number;
	symbol: string;
	symbolPosition: SymbolPosition;
	decimalSeparator: string;
	thousandSeparator: string;
	priceFormat: string;
}
⋮----
export interface WooCommerceSiteLocale {
	siteLocale: string;
	userLocale: string;
	weekdaysShort: string[];
}
⋮----
export interface WooCommerceSharedSettings {
	adminUrl: string;
	countries: Record< string, string > | never[];
	countryData: Record<
		string,
		{
			allowBilling: boolean;
			allowShipping: boolean;
... (45 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/settings/utils.ts">
import compareVersions from 'compare-versions';
import type { SymbolPosition } from '@woocommerce/types';
⋮----
import { allSettings } from './settings-init';
⋮----
export const getSetting = < T >(
	name: string,
	fallback: unknown = false,
filter = ( val: unknown, fb: unknown )
⋮----
export const getSettingWithCoercion = < T >(
	name: string,
	fallback: T,
	typeguard: ( val: unknown, fb: unknown ) => val is T
): T =>
⋮----
const compareVersionSettingIgnorePrerelease = (
	setting: string,
	version: string,
	operator: compareVersions.CompareOperator
): boolean =>
⋮----
// Only augment version if missing patch number.
⋮----
/**
 * Compare the current WP version with the provided `version` param using the
 * `operator`.
 *
 * For example `isWpVersion( '5.6', '<=' )` returns true if the site WP version
 * is smaller or equal than `5.6` .
... (31 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/shared-context/custom-data-context.tsx">
import type { Context, PropsWithChildren } from 'react';
import { createContext, useContext } from '@wordpress/element';
⋮----
export interface CustomData< T > {
	isLoading?: boolean;
	data?: T;
}
⋮----
function get< T >( id: string )
⋮----
function create< T >( id: string, defaultValue: CustomData< T > )
⋮----
export function CustomDataProvider< T >( {
	children,
	id,
	...props
}: PropsWithChildren<
⋮----
export function useCustomDataContext< T >( id: string )
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/shared-context/index.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/shared-context/inner-block-layout-context.tsx">
import { createContext, useContext } from '@wordpress/element';
⋮----
export const useInnerBlockLayoutContext = ()
⋮----
interface InnerBlockLayoutContextProviderProps {
	parentName?: string;
	parentClassName?: string;
	isLoading?: boolean;
	children: React.ReactNode;
}
⋮----
export const InnerBlockLayoutContextProvider = ( {
	parentName = '',
	parentClassName = '',
	isLoading = false,
	children,
}: InnerBlockLayoutContextProviderProps ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/shared-context/product-data-context.tsx">
import { ProductEntityResponse } from '@woocommerce/entities';
import { ProductResponseItem } from '@woocommerce/types';
import { createContext, useContext } from '@wordpress/element';
⋮----
type UseProductDataContextProps = {
	isAdmin?: boolean | undefined;
	product?: ProductResponseItem | ProductEntityResponse | undefined;
	isResolving?: boolean | undefined;
};
⋮----
export const useProductDataContext = (
	props: UseProductDataContextProps = {
		isAdmin: false,
	}
) =>
⋮----
interface ProductDataContextProviderProps {
	product: ProductResponseItem | ProductEntityResponse | null;
	children: JSX.Element | JSX.Element[];
	isLoading: boolean;
}
⋮----
export const ProductDataContextProvider = ( {
	product = null,
	children,
	isLoading,
}: ProductDataContextProviderProps ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/shared-hocs/index.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/shared-hocs/with-filtered-attributes.js">
export const withFilteredAttributes =
( blockAttributes ) => ( OriginalComponent ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/shared-hocs/with-product-data-context.js">
const getProductById = ( products, id )
⋮----
const getProductId = ( isDescendentOfQueryLoop, productId, postId ) =>
⋮----
const OriginalComponentWithContext = ( props ) =>
⋮----
export const withProductDataContext = ( OriginalComponent ) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/add-to-cart-form.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/address-autocomplete.ts">
import type { AddressFormType, AddressFormValues } from '@woocommerce/settings';
⋮----
interface Window {
		wc: {
			addressAutocomplete: {
				providers: Record< string, ClientAddressAutocompleteProvider >;
				activeProvider: {
					[ key in AddressFormType ]?: ClientAddressAutocompleteProvider | null;
				};
				registerAddressAutocompleteProvider: (
					provider: ClientAddressAutocompleteProvider
				) => boolean;
			};
		};
	}
⋮----
export interface ServerAddressAutocompleteProvider {
	name: string;
	id: string;
	branding_html: string;
}
⋮----
export interface AddressAutocompleteResult {
	label: string;
	id: string;
	matchedSubstrings: { length: number; offset: number }[];
}
⋮----
export interface ClientAddressAutocompleteProvider {
	id: string;
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/address-fields.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/api-error-response.ts">
import type { CartResponse } from './cart-response';
⋮----
export type ApiErrorResponse = {
	code: string;
	message: string;
	data?: ApiErrorResponseData | undefined;
};
⋮----
export type CouponApiErrorResponse = ApiErrorResponse & {
	data: ApiErrorResponseData & {
		details: Record< 'cart' | 'checkout', string >;
	};
};
⋮----
export type ApiErrorResponseData = {
	status: number;
	params: Record< string, string >;
	details: Record< string, ApiErrorResponseDataDetails >;
	context?: string;
	cart?: CartResponse | undefined;
} | null;
⋮----
export type ApiErrorResponseDataDetails = {
	code: string;
	message: string;
	data: ApiErrorResponseData;
	additional_errors?: ApiErrorResponse[];
};
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/api-response.ts">
export interface ApiResponse< T > {
	body: Record< string, unknown >;
	headers: Headers;
	status: number;
	ok: boolean;
	json: () => Promise< T >;
}
⋮----
export function assertBatchResponseIsValid(
	response: unknown
): asserts response is
⋮----
export function assertResponseIsValid< T >(
	response: unknown
): asserts response is ApiResponse< T >
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/attributes.ts">
import type { VisualAttributeTerm } from '@woocommerce/base-utils/visual-attribute-terms';
⋮----
export interface AttributeSetting {
	attribute_id: string;
	attribute_name: string;
	attribute_label: string;
	attribute_orderby: 'menu_order' | 'name' | 'name_num' | 'id';
	attribute_public: 0 | 1;
	attribute_type: string;
}
⋮----
export interface AttributeObject {
	count: number;
	has_archives: boolean;
	id: number;
	label: string;
	name: string;
	orderby: 'menu_order' | 'name' | 'name_num' | 'id';
	parent: number;
	taxonomy: string;
	type: string;
}
⋮----
export type AttributeObjectForDisplay = Omit<
	AttributeObject,
	'has_archives' | 'count' | 'parent' | 'type'
>;
⋮----
export interface AttributeQuery {
	attribute: string;
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/billing.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/blocks.ts">
import type { BlockEditProps, BlockInstance } from '@wordpress/blocks';
import type { LazyExoticComponent } from 'react';
⋮----
export type EditorBlock< T > = BlockInstance< T > & BlockEditProps< T >;
⋮----
export type RegisteredBlockComponent =
	| LazyExoticComponent< React.ComponentType< unknown > >
	| ( () => JSX.Element | null )
	| null;
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/cart-response.ts">
import type { CurrencyResponse } from './currency';
import type { CartItem, CartShippingRate } from './cart';
import type { ProductResponseItem } from './product-response';
⋮----
export interface CartResponseTotalsItem extends CurrencyResponse {
	total_discount: string;
	total_discount_tax: string;
}
⋮----
export interface CartResponseCouponItem {
	code: string;
	discount_type: string;
	totals: CartResponseTotalsItem;
}
⋮----
export interface CartResponseCouponItemWithLabel
	extends CartResponseCouponItem {
	label: string;
}
⋮----
export type CartResponseCoupons = CartResponseCouponItemWithLabel[];
⋮----
export interface ResponseFirstNameLastName {
	first_name: string;
	last_name: string;
}
⋮----
export interface ResponseBaseAddress {
	address_1: string;
	address_2: string;
... (147 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/cart.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/cart.ts">
import type { CurrencyCode } from '@woocommerce/types';
⋮----
import {
	MetaKeyValue,
	ShippingRateItem,
	ExtensionsData,
} from './cart-response';
import { ApiErrorResponse } from './api-error-response';
import {
	ProductResponseItemData,
	ProductResponseItem,
} from './product-response';
⋮----
export interface CurrencyInfo {
	currency_code: CurrencyCode;
	currency_symbol: string;
	currency_minor_unit: number;
	currency_decimal_separator: string;
	currency_thousand_separator: string;
	currency_prefix: string;
	currency_suffix: string;
}
⋮----
export interface CartTotalsItem extends CurrencyInfo {
	total_discount: string;
	total_discount_tax: string;
}
⋮----
export interface CartCouponItem {
	code: string;
... (199 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/checkout.ts">
import type { ShippingAddress, BillingAddress } from '@woocommerce/settings';
⋮----
import type { ApiErrorResponse } from './api-error-response';
⋮----
export interface CheckoutResponseSuccess {
	billing_address: BillingAddress;
	customer_id: number;
	customer_note: string;
	extensions: Record< string, unknown >;
	order_id: number;
	order_key: string;
	payment_method: string;
	payment_result: {
		payment_details: Record< string, string > | Record< string, never >;
		payment_status: 'success' | 'failure' | 'pending' | 'error';
		redirect_url: string;
	};
	shipping_address: ShippingAddress;
	status: string;
}
⋮----
export type CheckoutResponseError = ApiErrorResponse;
⋮----
export type CheckoutResponse = CheckoutResponseSuccess | CheckoutResponseError;
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/contexts.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/contexts.ts">
export type ValidationContextError = {
	message: string;
	hidden: boolean;
};
⋮----
export type ValidationData = {
	hasValidationErrors: boolean;
	getValidationError: ( validationErrorId: string ) => ValidationContextError;
	clearValidationError: ( validationErrorId: string ) => void;
	hideValidationError: ( validationErrorId: string ) => void;
	setValidationErrors: (
		errors: Record< string, ValidationContextError >
	) => void;
};
⋮----
export enum SHIPPING_ERROR_TYPES {
	NONE = 'none',
	INVALID_ADDRESS = 'invalid_address',
	UNKNOWN = 'unknown_error',
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/countries.ts">
import { FieldLocaleOverrides, FormFields } from '@woocommerce/settings';
⋮----
export type CountryData = {
	allowBilling: boolean;
	allowShipping: boolean;
	states: Record< string, string >;
	locale: Record< keyof FormFields, FieldLocaleOverrides >;
	format?: string;
};
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/currency.ts">
export interface Currency {
	code: CurrencyCode;
	decimalSeparator: string;
	minorUnit: number;
	prefix: string;
	suffix: string;
	symbol: string;
	thousandSeparator: string;
}
⋮----
export interface CurrencyResponse {
	currency_code: CurrencyCode | '';
	currency_symbol: string;
	currency_minor_unit: number;
	currency_decimal_separator: string;
	currency_thousand_separator: string;
	currency_prefix: string;
	currency_suffix: string;
}
⋮----
export type SymbolPosition = 'left' | 'left_space' | 'right' | 'right_space';
⋮----
export type CurrencyCode =
	| 'AED'
	| 'AFN'
	| 'ALL'
	| 'AMD'
	| 'ANG'
	| 'AOA'
	| 'ARS'
... (158 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/events.ts">
export interface AddToCartEventDetail {
	preserveCartData?: boolean;
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/hocs.ts">
import { ErrorObject } from '@woocommerce/editor-components/error-placeholder';
import type {
	ProductResponseItem,
	ProductCategoryResponseItem,
	ProductBrandResponseItem,
} from '@woocommerce/types';
⋮----
export interface WithInjectedProductVariations {
	error: ErrorObject | null;
	expandedProduct: number | null;
	variations: Record< number, ProductResponseItem[] >;
	variationsLoading: boolean;
	onLoadMoreVariations?: () => void;
	totalVariations?: Record< number, number | null >;
}
⋮----
export interface WithInjectedSearchedProducts {
	error: ErrorObject | null;
	isLoading: boolean;
	onSearch: ( ( search: string ) => void ) | null;
	products: ProductResponseItem[];
	selected: number[];
}
⋮----
export interface WithInjectedSearchedCategories {
	error: ErrorObject | null;
	isLoading: boolean;
	categories: ProductCategoryResponseItem[];
	selected: number[];
}
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/hooks.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/hooks.ts">
import type { CurrencyResponse, ProductResponseItem } from '@woocommerce/types';
⋮----
import type {
	CartResponseErrorItem,
	CartResponseCouponItem,
	CartResponseItem,
	CartResponseFeeItem,
	CartResponseTotals,
	CartResponseShippingAddress,
	CartResponseBillingAddress,
	CartResponseShippingRate,
	CartResponse,
	CartResponseCoupons,
} from './cart-response';
import type { ApiErrorResponse } from './api-error-response';
export interface StoreCartItemQuantity {
	isPendingDelete: boolean;
	quantity: number;
	setItemQuantity: React.Dispatch< React.SetStateAction< number > >;
	removeItem: () => Promise< boolean >;
	cartItemQuantityErrors: CartResponseErrorItem[];
}
⋮----
export interface StoreCartCoupon {
	appliedCoupons: CartResponseCouponItem[];
	isLoading: boolean;
	applyCoupon: ( coupon: string ) => Promise< boolean >;
	removeCoupon: ( coupon: string ) => Promise< boolean >;
	isApplyingCoupon: boolean;
	isRemovingCoupon: boolean;
... (66 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/notices.ts">
import type { WPNotice } from '@wordpress/notices/build-types/store/selectors';
⋮----
export type NoticeStatus = 'success' | 'error' | 'info' | 'warning' | 'default';
export interface NoticeType extends Partial< Omit< WPNotice, 'status' > > {
	id: string;
	content: string;
	status: NoticeStatus;
	isDismissible: boolean;
	context?: string | undefined;
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/objects.ts">
export type ObjectType = Record< string, unknown >;
export type EmptyObjectType = Record< string, never >;
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/payment-method-interface.ts">
import type PaymentMethodLabel from '@woocommerce/base-components/cart-checkout/payment-method-label';
import type PaymentMethodIcons from '@woocommerce/base-components/cart-checkout/payment-method-icons';
import type LoadingMask from '@woocommerce/base-components/loading-mask';
import type { Skeleton } from '@woocommerce/base-components/skeleton';
import type { ValidationInputError } from '@woocommerce/blocks-components';
import type { ComponentType } from 'react';
⋮----
import type {
	emitterCallback,
	responseTypes,
	noticeContexts,
} from '@woocommerce/base-context/event-emit';
import type { Currency } from './currency';
import type { CartBillingAddress, CartShippingRate } from './cart';
import type {
	CartResponseShippingAddress,
	CartResponseCouponItem,
	CartResponseItem,
	CartResponseFeeItem,
	ExtensionsData,
} from './cart-response';
import type { SHIPPING_ERROR_TYPES } from './contexts';
⋮----
export interface PreparedCartTotalItem {
	label: string;
	value: number;
}
⋮----
export interface BillingDataProps {
	appliedCoupons: CartResponseCouponItem[];
... (110 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/payments.ts">
import type { ReactNode } from 'react';
import { ApiErrorResponse } from '@woocommerce/types';
⋮----
import type { CartTotals } from './cart';
import type {
	CartResponse,
	CartResponseBillingAddress,
	CartResponseShippingAddress,
} from './cart-response';
import type { EmptyObjectType } from './objects';
import type { CheckoutResponseSuccess } from './checkout';
import type { CustomPlaceOrderButtonComponent } from './payment-method-interface';
⋮----
export interface GlobalPaymentMethod {
	id: string | number;
	title: string;
	description: string;
}
⋮----
export interface SupportsConfiguration {
	showSavedCards?: boolean;
	showSaveOption?: boolean;
	features?: string[];
	savePaymentInfo?: boolean;
	style?: string[];
}
⋮----
export interface Supports extends SupportsConfiguration {
	features: string[];
}
... (151 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/product-category-response.ts">
export interface TaxonomyResponseImageItem {
	id: number;
	src: string;
	thumbnail: string;
	srcset: string;
	sizes: string;
	name: string;
	alt: string;
}
⋮----
export interface TaxonomyResponseItem {
	id: number;
	name: string;
	slug: string;
	description: string;
	parent: number;
	count: number;
	image: TaxonomyResponseImageItem | null;
	review_count: number;
	permalink: string;
}
⋮----
export type ProductCategoryResponseImageItem = TaxonomyResponseImageItem;
export type ProductCategoryResponseItem = TaxonomyResponseItem;
export type ProductBrandResponseImageItem = TaxonomyResponseImageItem;
export type ProductBrandResponseItem = TaxonomyResponseItem;
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/product-response.ts">
import type { CurrencyResponse } from './currency';
⋮----
export interface ProductResponseItemPrices extends CurrencyResponse {
	price: string;
	regular_price: string;
	sale_price: string;
	price_range: null | { min_amount: string; max_amount: string };
}
⋮----
export interface ProductResponseItemBaseData {
	value: string;
	display?: string;
	raw_key?: string;
	hidden?: string;
	className?: string;
}
⋮----
export type ProductResponseItemData = ProductResponseItemBaseData &
	( { key: string; name?: never } | { key?: never; name: string } );
⋮----
export interface ProductResponseImageItem {
	id: number;
	src: string;
	thumbnail: string;
	srcset: string;
	sizes: string;
	name: string;
	alt: string;
}
⋮----
... (80 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/range-input.ts">
import type { HTMLElementEvent } from './utils';
⋮----
export interface RangeInputContext {
	min: number;
	max: number;
	currentMin: number;
	currentMax: number;
	step?: number;
	storeNamespace: string;
	isLoading?: boolean;
}
⋮----
export type RangeInputBlockContext = {
	'woocommerce/rangeInput': RangeInputContext;
};
⋮----
export interface RangeInputParentStore {
	actions: {
		setMin: ( event: HTMLElementEvent< HTMLInputElement > ) => void;
		setMax: ( event: HTMLElementEvent< HTMLInputElement > ) => void;
	};
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/removable-items.ts">
export interface RemovableItem {
	id: string;
	type: string;
	value: string;
	label: string;
}
⋮----
export interface RemovableItemsContext {
	items: RemovableItem[];
	storeNamespace: string;
}
⋮----
export type RemovableItemsBlockContext = {
	'woocommerce/removableItems': RemovableItemsContext;
};
⋮----
export interface RemovableItemsParentStore {
	state: {
		removableItems: readonly RemovableItem[];
	};
	actions: {
		remove: () => void;
		removeAll: () => void;
	};
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/selectable-items.ts">
import type { ReactNode } from 'react';
⋮----
export type SelectableItem< T = unknown > = (
	| { label: string; ariaLabel?: string }
	| { label: ReactNode; ariaLabel: string }
) & {
	id: string;
	value: string;
	selected?: boolean;
	disabled?: boolean;
	hidden?: boolean;
	type?: string;
} & T;
⋮----
export interface SelectableItemsContext< T = unknown > {
	items: SelectableItem< T >[];
	selectionMode: 'single' | 'multiple';
	storeNamespace: string;
	groupLabel?: string;
	isLoading?: boolean;
	filterType?: string;
}
⋮----
export type SelectableItemsBlockContext< T = unknown > = {
	'woocommerce/selectableItems': SelectableItemsContext< T >;
};
⋮----
export interface SelectableItemsParentStore< T = unknown > {
	state: {
		selectableItems: readonly SelectableItem< T >[];
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/settings.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/shipping.js">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/shipping.ts">
import type { ReactElement } from 'react';
⋮----
export interface PackageRateOption {
	label: string;
	value: string;
	description?: string | ReactElement | undefined;
	secondaryLabel?: string | ReactElement | undefined;
	secondaryDescription?: string | ReactElement | undefined;
	id?: string | undefined;
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/stock-status.ts">
export type StockStatus = 'instock' | 'outofstock' | 'onbackorder';
⋮----
export type StockStatusOptions = {
	[ key in StockStatus ]: string;
};
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/taxes.ts">
export type TaxRate = {
	country: string;
	rate: string;
	name: string;
	shipping: boolean;
	priority: number;
};
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/trim-html.d.ts">
interface Opts {
	limit: number;
	moreLink: string;
	moreText: string;
	preserveTags: boolean;
	preserveWhiteSpace: boolean;
	suffix: string;
	wordBreak: boolean;
}
⋮----
interface TrimResult {
	html: string;
	more: boolean;
}
⋮----
export default function trimHtml(
		html: string,
		options: Partial< Opts >
	): TrimResult;
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/utils.ts">
export type Dictionary = Record< string, string >;
⋮----
export type LooselyMustHave< T, K extends keyof T > = Partial< T > &
	Pick< T, K >;
⋮----
export type Require< T, K extends keyof T > = T & {
	[ P in K ]-?: T[ K ];
};
⋮----
export type HTMLElementEvent< T extends HTMLElement > = Event & {
	target: T;
};
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-defs/validation.ts">
export interface FieldValidationStatus {
	message: string;
	hidden: boolean;
}
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/address.ts">
import type { BillingAddress, ShippingAddress } from '@woocommerce/settings';
import { objectHasProp } from '@woocommerce/types';
⋮----
export const isShippingAddress = (
	address: unknown
): address is ShippingAddress =>
export const isBillingAddress = (
	address: unknown
): address is BillingAddress =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/api-error-response.ts">
import { isObject, objectHasProp } from './object';
import type { ApiErrorResponse } from '../type-defs';
⋮----
export const isApiErrorResponse = (
	response: unknown
): response is ApiErrorResponse =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/attributes.ts">
import type { AttributeTerm, AttributeQuery } from '../type-defs';
import { objectHasProp } from './object';
⋮----
export const isAttributeTerm = ( term: unknown ): term is AttributeTerm =>
⋮----
export const isAttributeTermCollection = (
	terms: unknown
): terms is AttributeTerm[] =>
⋮----
export const isAttributeQuery = ( query: unknown ): query is AttributeQuery =>
⋮----
export const isAttributeQueryCollection = (
	queries: unknown
): queries is AttributeQuery[] =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/boolean.ts">
export const isBoolean = ( term: unknown ): term is boolean =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/cart-response-totals.ts">
import type { CartResponseTotals } from '../type-defs';
import { isObject } from './object';
⋮----
type CartResponseTotalsKeys = Record< keyof CartResponseTotals, 0 >;
⋮----
export const isCartResponseTotals = (
	value: unknown
): value is CartResponseTotals =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/empty.ts">
export const isEmpty = ( value: unknown ): boolean =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/error.ts">
export const isError = ( term: unknown ): term is Error =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/form-fields.ts">
import type { FormFields, Field } from '@woocommerce/settings';
⋮----
const isField = ( value: unknown ): value is Field =>
⋮----
export const isFormFields = ( value: unknown ): value is FormFields =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/function.ts">
export const isFunction = < T extends Function, U >(
	term: T | U
): term is T =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/null.ts">
export const isNull = < T >( term: T | null ): term is null =>
⋮----
export function nonNullable< T >( value: T ): value is NonNullable< T >
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/number.ts">
export const isNumber = < U >( term: number | U ): term is number =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/object.ts">
import { isNull } from './null';
⋮----
export const isObject = < T extends Record< string, unknown >, U >(
	term: T | U
): term is NonNullable< T > =>
⋮----
export function objectHasProp< P extends PropertyKey >(
	target: unknown,
	property: P
): target is
⋮----
export const isEmptyObject = < T extends { [ key: string ]: unknown } >(
	object: T
) =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/observers.ts">
import { FieldValidationStatus, isObject, objectHasProp } from '../';
⋮----
export enum responseTypes {
	SUCCESS = 'success',
	FAIL = 'failure',
	ERROR = 'error',
}
⋮----
export interface ObserverResponse extends Record< string, unknown > {
	type: responseTypes;
	errorMessage?: string;
	context?: string;
	meta?: Record< string, unknown >;
	validationErrors?: Record< string, FieldValidationStatus >;
}
⋮----
export const isObserverResponse = (
	response: unknown
): response is ObserverResponse =>
⋮----
export interface ResponseType extends Record< string, unknown > {
	type: responseTypes;
	retry?: boolean;
}
⋮----
const isResponseOf = (
	response: unknown,
	type: string extends responseTypes ? never : responseTypes
): response is ResponseType =>
⋮----
... (20 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/ratings.ts">
type Rating = '1' | '2' | '3' | '4' | '5';
⋮----
export const isRatingQueryCollection = (
	value: unknown
): value is Rating[] =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/stock-status.ts">
import type { StockStatus, StockStatusOptions } from '../type-defs';
import { isObject } from './object';
⋮----
export const isStockStatusQueryCollection = (
	value: unknown
): value is StockStatus[] =>
⋮----
export const isStockStatusOptions = (
	value: unknown
): value is StockStatusOptions =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/string.ts">
export const isString = < U >( term: string | U ): term is string =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/type-guards/validation.ts">
import {
	FieldValidationStatus,
	isBoolean,
	isObject,
	isString,
	objectHasProp,
} from '../';
⋮----
export const isValidFieldValidationStatus = (
	status: unknown
): status is FieldValidationStatus =>
⋮----
export const isValidValidationErrorsObject = (
	errors: unknown
): errors is Record< string, FieldValidationStatus > =>
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/types/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/AGENTS.md">
# Public API package instructions

Files below this directory implement extension-facing JavaScript contracts.

- Preserve stable exports from each `@woocommerce/*` package root.
- Prefer additive changes. Deprecate existing exports before removing or
  renaming them.
- Preserve the package import, WordPress script handle, and `window.wc` global
  mappings.
- Treat `__experimental` and `__unstable` exports as unstable, and retain their
  prefixes until they are intentionally stabilized.
- Treat deep imports and unexported implementation files as internal unless
  public developer documentation says otherwise.
- State the backward-compatibility impact when changing a root export.
- Check extension usage before changing signatures or runtime behavior.

The Blocks workspace is marked `"private": true` to prevent npm publication.
That setting does not change the public status of these browser APIs.
</file>

<file path="plugins/woocommerce/client/blocks/packages/public-api/README.md">
# WooCommerce Blocks public API packages

This directory contains JavaScript package entry points that WooCommerce
extensions may consume. Stable exports from each package root are public
contracts and require backward-compatibility handling.

## API contract

- Import packages through their `@woocommerce/*` package root.
- Treat stable root exports as public API.
- Add new APIs instead of renaming or removing existing APIs.
- Deprecate an existing API before removing it.
- Treat exports prefixed with `__experimental` or `__unstable` as unstable.
- Treat deep imports and files not exported from a package root as internal
  unless they are documented separately.

The `"private": true` field in the Blocks `package.json` only prevents npm
publication. It does not make these browser APIs private.

## Packages

| Package | Script handle | Browser global |
| --- | --- | --- |
| `@woocommerce/block-data` | `wc-blocks-data-store` | `wc.wcBlocksData` |
| `@woocommerce/blocks-checkout` | `wc-blocks-checkout` | `wc.blocksCheckout` |
| `@woocommerce/blocks-checkout-events` | `wc-blocks-checkout-events` | `wc.blocksCheckoutEvents` |
| `@woocommerce/blocks-components` | `wc-blocks-components` | `wc.blocksComponents` |
| `@woocommerce/blocks-registry` | `wc-blocks-registry` | `wc.wcBlocksRegistry` |
| `@woocommerce/price-format` | `wc-price-format` | `wc.priceFormat` |
| `@woocommerce/settings` | `wc-settings` | `wc.wcSettings` |
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/storybook/__mocks__/woocommerce-base-hooks.js">
export const useStoreCart = () => (
⋮----
receiveCart: ()
⋮----
export const useShippingData = () => (
⋮----
selectShippingRate: ()
</file>

<file path="plugins/woocommerce/client/blocks/storybook/__mocks__/woocommerce-block-settings.js">

</file>

<file path="plugins/woocommerce/client/blocks/storybook/custom-controls/currency.ts">
import { Currency, CurrencyResponse } from '@woocommerce/types';
import { snakeCaseKeys } from '@woocommerce/base-utils';
</file>

<file path="plugins/woocommerce/client/blocks/storybook/custom-controls/index.ts">

</file>

<file path="plugins/woocommerce/client/blocks/storybook/main.mjs">
/**
 * External dependencies
 */
⋮----
/** @type {import('@storybook/react-webpack5').StorybookConfig} */
⋮----
// WooCommerce Blocks stuff (anywhere in repo!)
⋮----
// webpackFinal field was added in following PR: https://github.com/woocommerce/woocommerce-blocks/pull/7514
// This fixes "storybook build issue" related to framer-motion library.
// Solution is from this comment: https://github.com/storybookjs/storybook/issues/16690#issuecomment-971579785
webpackFinal: async ( config ) =>
⋮----
// https://github.com/storybookjs/storybook/discussions/22650#discussioncomment-6414161
</file>

<file path="plugins/woocommerce/client/blocks/storybook/preview.js">

</file>

<file path="plugins/woocommerce/client/blocks/storybook/README.md">
# Working with Storybook <!-- omit in toc -->

## Table of Contents <!-- omit in toc -->

- [Adding new stories](#adding-new-stories)
    - [Scaffold tour](#scaffold-tour)
        - [The `default` export](#the-default-export)
        - [Defining controls](#defining-controls)
        - [The Story template](#the-story-template)
        - [Defining Stories](#defining-stories)
    - [Snippets](#snippets)
- [FAQ](#faq)
    - [What should constitute a story?](#what-should-constitute-a-story)
    - [Can I create stories with mixed components?](#can-i-create-stories-with-mixed-components)
- [Tips](#tips)
    - [One file per component](#one-file-per-component)
    - [Custom controls](#custom-controls)
- [Common gotchas and examples](#common-gotchas-and-examples)
    - [Named exports](#named-exports)
    - [Controlled components](#controlled-components)
    - [Simulating interactions](#simulating-interactions)
    - [Context providers](#context-providers)

This document is meant to make contributing to our Storybook a bit easier by giving some tips, pointing out a few gotchas, making the editing experience smoother, and reducing the friction to adding a new story.

## Adding new stories

To easily scaffold a new story for your component you need a few steps, but most things are already configured to reduce friction.

1. Make sure you add a `stories` directory within your component directory.
... (324 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/storybook/webpack.config.js">

</file>

<file path="plugins/woocommerce/client/blocks/typings/monorepo-enhancements.d.ts">

</file>

<file path="plugins/woocommerce/client/blocks/.browserslistrc">
extends @wordpress/browserslist-config
</file>

<file path="plugins/woocommerce/client/blocks/.gitattributes">
# Ignore all hidden files and directories
/.* export-ignore

# Ignore all markdown files
/*.md export-ignore

# Ignore following directories and contents
/node_modules* export-ignore
/tests export-ignore
/bin export-ignore
/docs export-ignore
/storybook export-ignore

# Ignore following configuration files
/CODEOWNERS export-ignore
/renovate.json export-ignore
/webpack.config.js export-ignore
/postcss.config.js export-ignore
/bundlesize.config.json export-ignore
/package.json export-ignore
/package-lock.json export-ignore
/babel.config.js export-ignore
/docker-compose.yml export-ignore
/globals.d.ts export-ignore
/tsconfig.json export-ignore
/tsconfig.base.json export-ignore
/tsconfig.base export-ignore
/webpack.config.js export-ignore
</file>

<file path="plugins/woocommerce/client/blocks/.markdownlint.json">
{
	"default": true,
	"MD003": { "style": "atx" },
	"MD007": { "indent": 4 },
	"MD013": { "line_length": 9999 },
	"MD024": false,
	"MD025": false,
	"MD029": false,
	"MD033": false,
	"MD046": { "style": "fenced" },
	"no-hard-tabs": false,
	"whitespace": false
}
</file>

<file path="plugins/woocommerce/client/blocks/.prettierrc.js">

</file>

<file path="plugins/woocommerce/client/blocks/.stylelintrc.json">
{
	"extends": "@wordpress/stylelint-config/scss",
	"rules": {
		"at-rule-empty-line-before": null,
		"at-rule-no-unknown": null,
		"comment-empty-line-before": null,
		"font-weight-notation": null,
		"no-descending-specificity": null,
		"no-duplicate-selectors": null,
		"rule-empty-line-before": null,
		"selector-class-pattern": null,
		"value-keyword-case": null,
		"length-zero-no-unit": [
			true,
			{ "ignoreFunctions": [ "calc", "var" ] }
		]
	}
}
</file>

<file path="plugins/woocommerce/client/blocks/babel.config.js">

</file>

<file path="plugins/woocommerce/client/blocks/blocks.ini">
woocommerce_blocks_env = production
</file>

<file path="plugins/woocommerce/client/blocks/CLAUDE.md">
# Claude Code Documentation for WooCommerce Blocks

**Scope**: All WooCommerce blocks — storefront, cart, checkout, product displays, filters, mini cart, order confirmation. Covers editor UI (JS/TS), frontend rendering (PHP + Interactivity API), and supporting services (payments, shipping, patterns).
**pnpm filter**: `@woocommerce/block-library` (internal workspace package, not published)

**See also:**

- `../../CLAUDE.md` - Plugin-level docs, PHP workflow, changelog process
- `../../src/Blocks/` - PHP block classes (registration, rendering, services)
- `docs/README.md` - Full handbook (contributors, extensibility, theming)

## Quick Reference Commands

```bash

# All commands use --filter shorthand. Run from monorepo root.

# Test
pnpm --filter=@woocommerce/block-library test:js                      # Jest unit tests
pnpm --filter=@woocommerce/block-library test:js -- path/to/test      # Specific test file
pnpm --filter=@woocommerce/block-library test:watch                   # Jest watch mode
pnpm --filter=@woocommerce/block-library test:update                  # Update snapshots
pnpm --filter=@woocommerce/block-library test:e2e                     # Playwright E2E tests

# Lint (target specific files only)
npx eslint --fix path/to/file.tsx                                      # Fix JS/TS file
pnpm --filter=@woocommerce/block-library lint:css                      # Stylelint for SCSS
pnpm --filter=@woocommerce/block-library ts:check                     # TypeScript type checking

# Environment
... (206 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/composer.json">
{
	"name": "woocommerce/block-library",
	"description": "Dev tooling for WooCommerce Blocks. Only used to run `pnpm build:docs`, which regenerates the hook docs from the PHP sources in plugins/woocommerce/src.",
	"license": "GPL-3.0-or-later",
	"prefer-stable": true,
	"minimum-stability": "dev",
	"require-dev": {
		"wp-hooks/generator": "1.0.2",
		"cweagans/composer-patches": "^1.7"
	},
	"config": {
		"allow-plugins": {
			"cweagans/composer-patches": true
		},
		"platform": {
			"php": "8.3.0"
		},
		"platform-check": false
	},
	"extra": {
		"composer-exit-on-patch-failure": true,
		"patches": {
			"wp-hooks/generator": {
				"Keep @return/@throws tag types, warn instead of fatal on unknown hook doc tags, and emit raw docblock Markdown instead of Parsedown HTML": "bin/hook-docs/wp-hooks-generator.patch"
			}
		},
		"wp-hooks": {
			"ignore-files": [
				"src/Abilities/",
				"src/Admin/",
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/docker-compose.yml">
version: "3.3"
services:
  db:
    image: mariadb:10.5
    restart: on-failure
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
      MYSQL_RANDOM_ROOT_PASSWORD: "yes"
    volumes:
      - db:/var/lib/mysql
  wordpress-unit-tests:
    container_name: wordpress_test
    depends_on:
      - db
    build:
      context: ./tests/bin
      args:
        WOO_INSTALL_VERSION: ${WOO_VERSION}
    ports:
      - 8085:80
    restart: on-failure
    environment:
      - WORDPRESS_DB_HOST
      - WORDPRESS_DB_NAME
      - WORDPRESS_DB_USER
      - WORDPRESS_DB_PASSWORD
      - WORDPRESS_TABLE_PREFIX=wptests_
      - WP_CORE_DIR=/var/www/html
... (48 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/eslint.config.mjs">
/**
 * External dependencies
 */
⋮----
/**
 * Internal dependencies
 */
⋮----
// node_modules is ignored by default.
⋮----
/*
	 * The shared config already registers the jest, @typescript-eslint and
	 * fixupPluginRules-wrapped `import` plugins, and applies the TypeScript
	 * parser globally. The eslintrc this replaces re-registered all three via
	 * `plugins:` and `plugin:jest/recommended` / `plugin:@typescript-eslint/recommended`
	 * / `plugin:import/errors`. Registering second copies is fatal under ESLint
	 * v10 (eslint-plugin-import has no v10 support) and otherwise trips
	 * "Cannot redefine plugin", so those rules are set on the inherited plugins.
	 */
⋮----
/*
		 * This plugin ships only eslintrc-style configs, whose `plugins` is an
		 * array of names rather than a map, so `compatible` cannot be spread as a
		 * flat config. Register the plugin and take its rules instead. Those rules
		 * call no APIs ESLint 10 removed, so unlike `import` and `react` this one
		 * needs no @eslint/compat fixup.
		 */
⋮----
// @todo Move E2E related ESLint configuration into custom config.
//
... (44 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/global.d.ts">

</file>

<file path="plugins/woocommerce/client/blocks/LICENSE">
GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
... (645 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/package.json">
{
	"name": "@woocommerce/block-library",
	"title": "WooCommerce Blocks",
	"private": true,
	"version": "11.8.0-dev",
	"license": "GPL-2.0-or-later",
	"author": "Automattic",
	"description": "WooCommerce blocks for the Gutenberg editor.",
	"homepage": "https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/client/blocks/README.md",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"keywords": [
		"woocommerce",
		"wordpress",
		"blocks"
	],
	"sideEffects": [
		"*.css",
		"*.scss",
		"./assets/js/atomic/blocks/**",
		"./assets/js/filters/**",
		"./assets/js/middleware/**",
		"./packages/public-api/types/**",
		"./assets/js/blocks/checkout/inner-blocks/**/index.tsx",
		"./assets/js/blocks/checkout/inner-blocks/register-components.ts",
		"./assets/js/blocks/cart/inner-blocks/**/index.tsx",
		"./assets/js/blocks/cart/inner-blocks/register-components.ts",
		"./assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/**/index.tsx",
... (308 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/postcss.config.js">
module.exports = (
</file>

<file path="plugins/woocommerce/client/blocks/README.md">
# WooCommerce Blocks <!-- omit in toc -->

This is the client for WooCommerce + Gutenberg. This package serves as a space to iterate and explore new Blocks and updates to existing blocks for WooCommerce, and how WooCommerce might work with the Block Editor.

## Table of Contents <!-- omit in toc -->

-   [Documentation](#documentation)
    -   [Code Documentation](#code-documentation)
-   [Getting started with block development](#getting-started-with-block-development)
-   [Long-term vision](#long-term-vision)

## Documentation

To find out more about the blocks and how to use them, [check out the documentation on WooCommerce.com](https://woocommerce.com/document/woocommerce-blocks/).

If you want to see what we're working on for future versions, or want to help out, read on.

### Code Documentation

-   [Blocks](./assets/js/blocks) - Documentation for specific Blocks.
-   [Editor Components](assets/js/editor-components) - Shared components used in WooCommerce blocks for the editor (Gutenberg) UI.
-   [WooCommerce Blocks Handbook](./docs) - Documentation for designers and developers on how to extend or contribute to blocks, and how internal developers should handle new releases.
-   [WooCommerce Blocks Storybook](https://woocommerce.github.io/woocommerce-blocks/) - Contains a list and demo of components used in the plugin.

## Getting started with block development

Run through the ["Writing Your First Block Type" tutorial](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/writing-your-first-block-type/) for a quick course in block-building.

For deeper dive, try looking at the [core blocks code,](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src) or see what [components are available.](https://github.com/WordPress/gutenberg/tree/trunk/packages/components/src)

... (11 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/readme.txt">
=== WooCommerce Blocks ===
Contributors: automattic, woocommerce, claudiulodro, tiagonoronha, jameskoster, ryelle, levinmedia, aljullu, mikejolley, nerrad, joshuawold, assassinateur, haszari, mppfeiffer, nielslange, opr18, ralucastn, tjcafferkey, danielwrobert, patriciahillebrandt, albarin, dinhtungdu, royho, imanish003, karolmanijak, sunyatasattva, alexandrelara, gigitux, danieldudzic, samueljseay, alexflorisca, opr18, tarunvijwani, pauloarromba, saadtarhi
Tags: gutenberg, woocommerce, woo commerce, products, blocks, woocommerce blocks
Requires at least: 6.4
Tested up to: 6.4
Requires PHP: 7.4
Stable tag: 11.6.2
License: GPLv3
License URI: https://www.gnu.org/licenses/gpl-3.0.html

== Description ==

WooCommerce Blocks are the easiest, most flexible way to display your products on posts and pages!

For more information on what blocks are available, and how to use them, check out <a href="https://woocommerce.com/document/woocommerce-blocks/
">the official documentation</a>.

**Note: Feature plugin for WooCommerce + Gutenberg. This plugin serves as a space to iterate and explore new Blocks and updates to existing blocks for WooCommerce, and how WooCommerce might work with the block editor.**

Use this plugin if you want access to the bleeding edge of available blocks for WooCommerce. However, stable blocks are bundled into WooCommerce, and can be added from the "WooCommerce" section in the block inserter.

- **Active Filters**
- **All Products**
- **All Reviews**
- **Best Selling Products**
- **Cart including Cross-Sells**
- **Checkout**
- **Featured Category**
- **Featured Product**
- **Filter by Attribute**
... (3194 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/tsconfig.base.json">
{
	"exclude": [
		"node_modules"
	],
	"compilerOptions": {
		"outDir": "./build",
		"sourceMap": true,
		"baseUrl": ".",
		"target": "esnext",
		"module": "esnext",
		"emitDeclarationOnly": true,
		"esModuleInterop": true,
		"exactOptionalPropertyTypes": true,
		"resolveJsonModule": true,
		"jsx": "preserve",
		"allowJs": true,
		"moduleResolution": "bundler",
		"lib": [
			"dom",
			"esnext"
		],
		"checkJs": true,
		"skipLibCheck": true,
		"strict": true,
		"strictNullChecks": true,
		"allowSyntheticDefaultImports": true,
		"composite": true,
		"rootDir": ".",
		"typeRoots": [
			"./node_modules/@types"
... (169 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/tsconfig.json">
{
	"extends": "./tsconfig.base.json",
	"include": [
		"./typings/**/*",
		"./assets/js/**/*",
		"./assets/js/**/*.json",
		"./packages/public-api/**/*",
		"./packages/internal/**/*",
		"./assets/js/middleware/**/*",
		"./assets/js/blocks/**/block.json",
		"./assets/js/atomic/blocks/**/block.json",
		"./assets/js/blocks/mini-cart/mini-cart-contents/inner-blocks/**/block.json",
		"./storybook/**/*",
		"./tests/integration/**/*",
		"./tests/js/**/*",
		"./tests/utils/**/*"
	],
	"exclude": [
		"./storybook/build",
		"./storybook/dist",
		"./storybook/webpack.config.js",
		"./storybook/preview.js",
		"./bin"
	],
	"compilerOptions": {
		"composite": true
	},
	"references": [
		{
			"path": "../../../../packages/js/email-editor"
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/client/blocks/webpack.config.js">
const getCacheConfig = ( name, configPaths = [] )
</file>

<file path="plugins/woocommerce/client/blocks/wp-cli.yml">
apache_modules:
    - mod_rewrite
</file>

<file path="plugins/woocommerce/client/legacy/js/accounting/accounting.js">
function isString(obj)
⋮----
/**
	 * Tests whether supplied parameter is a string
	 * from underscore.js, delegates to ECMA5's native Array.isArray
	 */
function isArray(obj)
⋮----
function isObject(obj)
⋮----
function defaults(object, defs)
⋮----
function map(obj, iterator, context)
⋮----
function checkPrecision(val, base)
⋮----
function checkCurrencyFormat(format)
⋮----
.replace(regex, '')         // strip out any cruft
.replace(decimal, '.')      // make sure decimal point is standard
⋮----
// This will fail silently which may cause trouble, let's wait and see:
⋮----
// Format the number:
⋮----
/**
	 * Format a number into currency
	 *
	 * Usage: accounting.formatMoney(number, symbol, precision, thousandsSep, decimalSep, format)
	 * defaults: (0, "$", 2, ",", ".", "%s%v")
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/utils/maybe-modify-decimal.js">
function maybeModifyDecimal( value, config )
⋮----
// Export for different module systems
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/utils/number-validation.js">
function isValidFormattedNumber( value, config )
⋮----
// For non-empty values, require a config object.
⋮----
// If no numbers found, check if it's a shortcode format.
⋮----
// Check if all matches are valid numbers with the correct separators
⋮----
return false; // If the first character is not a digit, it's invalid
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/api-keys.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/backbone-modal.js">
/**
	 * Create the Backbone Modal
	 *
	 * @return {null}
	 */
⋮----
function closeModal()
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/marketplace-suggestions.js">
function getAdminLink( path )
⋮----
// Dismiss the specified suggestion from the UI, and save the dismissal in settings.
function dismissSuggestion( context, product, promoted, url, suggestionSlug )
⋮----
// hide the suggestion in the UI
⋮----
// save dismissal in user settings
⋮----
// Render DOM element for suggestion dismiss button.
function renderDismissButton( context, product, promoted, url, suggestionSlug )
⋮----
function addURLParameters( context, url )
⋮----
function renderLinkout( context, product, promoted, slug, url, iamUrl, text, isButton )
⋮----
function renderSuggestionIcon( iconUrl )
⋮----
function renderSuggestionContent( slug, title, copy )
⋮----
function renderSuggestionCTA( context, product, promoted, slug, url, iamUrl, linkText, linkIsButton, allowDismiss )
⋮----
function renderListItem(
			context,
			product,
			promoted,
			slug,
			iconUrl,
			title,
			copy,
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/meta-boxes-coupon.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/meta-boxes-order.js">
// Taxes
⋮----
/**
			 * Cancel the add products modal response when a quantity is below its
			 * minimum, reporting it on the input so the modal stays open.
			 */
⋮----
// The clear button is rendered with the results summary, so delegate from its container.
⋮----
// Announce the result to screen readers (WCAG 4.1.3).
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/meta-boxes-product-variation.js">
// Set the new total of pages
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/meta-boxes-product.js">
function appendAttributeTermOption( select, term )
⋮----
function change_product_type_tip( content )
⋮----
function get_product_tip_content( product_type )
⋮----
function show_and_hide_controls( context )
⋮----
function show_and_hide_panels()
⋮----
// File inputs.
⋮----
function show_or_hide_stock_management_fields(
		isStockManagementEnabled,
		productType
)
⋮----
function date_picker_select( datepicker )
⋮----
function update_attribute_row_indexes()
⋮----
function get_new_attribute_list_item_html(
		indexInList,
		globalAttributeId
)
⋮----
function block_attributes_tab_container()
⋮----
function unblock_attributes_tab_container()
⋮----
... (34 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/meta-boxes.js">
function runTipTip()
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/network-orders.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/order-attribution-admin.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/product-editor.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/product-ordering.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/quick-edit.js">
function init_sale_datepickers( $row )
⋮----
function sync_date_limits()
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/reports.js">
function showTooltip( x, y, contents )
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/settings-views-html-settings-tax.js">
// Initialize autocomplete for countries.
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/settings.js">
function editPrompt ()
⋮----
// The Settings UI page owns its dirty state and unsaved-changes prompt,
// so the classic tracking must leave its Save button alone.
⋮----
const nodeListContainsFormElements = ( nodes ) =>
⋮----
const changeAgent = () =>
⋮----
function settings_scroll_to_active_tab()
⋮----
function settings_fix_nav_width()
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/system-status.js">
var the_name    = label.trim().replace( /(<([^>]+)>)/ig, '' ); // Remove HTML.
⋮----
// Find value
⋮----
applyRedactions( report )
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/term-ordering.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/users.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/variation-gallery.js">
const announce = ( message ) =>
⋮----
const pickAttachmentDisplayUrl = ( attachmentJson ) =>
⋮----
/**
	 * Pick the thumbnail URL for use in small previews (gallery thumbs and
	 * the legacy inline preview slot). Falls back to the raw URL when no
	 * thumbnail variant is registered for this attachment.
	 *
	 * @param {{ sizes?: Object, url?: string }} attachmentJson
	 * @return {string}
	 */
const pickAttachmentThumbnailUrl = ( attachmentJson ) =>
⋮----
/**
	 * Map an image count to the i18n template key used to label the field.
	 *
	 * @param {number} count
	 * @return {string}
	 */
const getCountTemplateKey = ( count ) =>
⋮----
const clearHeroOverlays = ( $hero ) =>
⋮----
const getOrCreateHeroImage = ( $hero ) =>
⋮----
init()
⋮----
initializeSortables()
⋮----
... (85 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-admin-notices.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-brands-enhanced-select.js">
function getEnhancedSelectFormatString()
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-clipboard.js">
function wcSetClipboard( data, $el )
⋮----
function wcClearClipboard()
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-customer-stock-notifications.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-enhanced-select.js">
function getVisualTermSwatchStyle( visual )
⋮----
function formatVisualTermOption( term )
⋮----
function getTermDataWithVisual( $select, data )
⋮----
function updateVisualAttributeTermChoices( $select )
⋮----
function getEnhancedSelectFormatString()
⋮----
function display_result( self, select2_args )
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-orders.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-product-export.js">
/**
	 * Process the current export step.
	 */
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-product-import.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-recent-reviews-widget-async.js">
function loadRecentReviewsWidget()
⋮----
function showErrorMessage()
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-setup.js">
function blockWizardUI()
⋮----
function submitActivateForm()
⋮----
function waitForJetpackInstall()
⋮----
function addPlugins( bySlug, $el, hover )
⋮----
function updatePluginInfo()
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-shipping-classes.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-shipping-providers.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-shipping-zone-methods.js">
// Avoid triggering a rerender here because we don't want to show the method
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-shipping-zones.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-status-widget-async.js">
function loadStatusWidget()
⋮----
function showErrorMessage()
</file>

<file path="plugins/woocommerce/client/legacy/js/admin/wc-status-widget.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/admin/woocommerce_admin.js">
// Check if newvalue have more than one decimal point.
⋮----
function maybeToggleMarketplaceMenu( e )
⋮----
function isTouchDevice()
</file>

<file path="plugins/woocommerce/client/legacy/js/dompurify/purify.js">
function unapply(func)
⋮----
function unconstruct(func)
⋮----
function addToSet(set, array)
⋮----
function cleanArray(array)
⋮----
function clone(object)
⋮----
function lookupGetter(object, prop)
⋮----
function fallbackValue()
⋮----
createHTML(html)
createScriptURL(scriptUrl)
⋮----
// Policy creation failed (most likely another DOMPurify script has
// already run). Skip creating the policy, as this will only cause errors
// if TT are enforced.
⋮----
function createDOMPurify()
⋮----
const DOMPurify = root
⋮----
/**
     * Expose whether this browser supports running the full DOMPurify.
     */
⋮----
// Uninitialized policy, attempt to initialize the internal dompurify policy.
... (71 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/flexslider/jquery.flexslider.js">
// Store a reference to the slider object
⋮----
// CONTROLSCONTAINER:
⋮----
// MANUAL:
⋮----
// CUSTOM DIRECTION NAV:
⋮----
// RANDOMIZE:
⋮----
// INIT
⋮----
// CONTROLNAV:
⋮----
// DIRECTIONNAV:
⋮----
// KEYBOARD:
⋮----
// public methods
⋮----
// Unbind previous transitionEnd events and re-bind new transitionEnd event
⋮----
controlsContainer: "",          //{UPDATED} jQuery Object/Selector: Declare which container the navigation elements should be appended too. Default container is the FlexSlider element. Example use would be $(".flexslider-container"). Property is ignored if given element is not found.
manualControls: "",             //{UPDATED} jQuery Object/Selector: Declare custom control navigation. Examples would be $(".flex-control-nav li") or "#tabs-nav li img", etc. The number of elements in your controlNav should match the number of slides/tabs.
customDirectionNav: "",         //{NEW} jQuery Object/Selector: Custom prev / next button. Must be two jQuery elements. In order to make the events work they have to have the classes "prev" and "next" (plus namespace)
sync: "",                       //{NEW} Selector: Mirror the actions performed on this slider with another slider. Use with care.
asNavFor: "",                   //{NEW} Selector: Internal property exposed for turning the slider into a thumbnail navigation for another slider
⋮----
// Carousel Options
itemWidth: 0,                   //{NEW} Integer: Box-model width of individual carousel items, including horizontal borders and padding.
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/utils/address-autocomplete-common.js">
function registerAddressAutocompleteProvider( provider )
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/utils/custom-place-order-button.js">
function getForm()
⋮----
function getGatewaysWithCustomButton()
⋮----
function gatewayHasCustomPlaceOrderButton( gatewayId )
⋮----
function getOrCreateCustomButtonContainer()
⋮----
function removeCustomButtonContainer()
⋮----
function cleanupCurrentCustomButton()
⋮----
function maybeShowCustomPlaceOrderButton( gatewayId, api )
⋮----
function maybeHideDefaultButtonOnInit( gatewayId )
⋮----
function registerCustomPlaceOrderButton( gatewayId, config )
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/a8c-address-autocomplete-service.js">
function generateSessionId()
⋮----
function debounce( func, wait, options )
⋮----
function invokeFunc( time )
⋮----
function leadingEdge( time )
⋮----
function remainingWait( time )
⋮----
function shouldInvoke( time )
⋮----
function timerExpired()
⋮----
function trailingEdge( time )
⋮----
function cancel()
⋮----
function flush()
⋮----
function debounced()
⋮----
class LRUCache
⋮----
get( key )
⋮----
set( key, value )
⋮----
clear()
⋮----
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/account-i18n.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/add-payment-method.js">
function createAddPaymentMethodApi()
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/add-to-cart-variation.js">
/**
	 * When the product image is reset.
	 */
⋮----
/**
	 * Looks for matching variations for current selected attributes.
	 */
⋮----
// Decode HTML entities.
⋮----
/**
	 * Updates attributes in the DOM to show valid values.
	 */
⋮----
// Loop through selects and disable/enable options based on selections.
⋮----
// Reference options set at first.
⋮----
// Legacy data attribute.
⋮----
// The attribute of this select field should not be taken into account when calculating its matching variations:
// The constraints of this attribute are shaped by the values of the other attributes.
⋮----
// Loop through variations.
⋮----
// Decode entities.
⋮----
// Attach to matching options by value. This is done to compare
// TEXT values rather than any HTML entities.
⋮----
... (70 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/add-to-cart.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/address-autocomplete.js">
function setActiveProvider( country, type )
⋮----
function cacheAddressFields( type )
⋮----
function disableBrowserAutofill( input )
⋮----
function enableBrowserAutofill( input, shouldFocus = true )
⋮----
function getHighlightedLabel( label, matches )
⋮----
function sanitizeForDisplay( html )
⋮----
/**
			 * Handle searching and displaying autocomplete results below the address input if the value meets the criteria
			 * of 3 or more characters. No suggestion is initially highlighted.
			 * @param inputValue {string} The value entered into the address input.
			 * @param country {string} The country code to pass to the provider's search method.
			 * @param type {string} The address type ('billing' or 'shipping').
			 * @return {Promise<void>}
			 */
async function displaySuggestions( inputValue, country, type )
⋮----
li.textContent = ''; // Clear existing content.
⋮----
// Check if branding element already exists.
⋮----
function hideSuggestions( type )
⋮----
// Hide branding element but keep it in DOM (will be removed on country change).
⋮----
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/address-i18n.js">
function field_is_required( field, is_required )
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/back-in-stock-form.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/cart-fragments.js">
function set_cart_creation_timestamp()
⋮----
function set_cart_hash( cart_hash )
⋮----
function refresh_cart_fragment()
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/cart.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/checkout.js">
function encodeApostrophes( data )
⋮----
function createCheckoutPlaceOrderApi()
⋮----
// Check if window.wc.addressAutocomplete exists and has an active provider
⋮----
/**
		 * Check if an address_1 field has an active autocomplete provider and should trigger checkout updates on blur
		 * @param {Event} e - The event object
		 * @return {boolean} true if updates should be triggered, false otherwise
		 */
⋮----
// Check if window.wc.addressAutocomplete exists and has an active provider
⋮----
// Check if we're in an address_1 field with an active provider
⋮----
// Check if window.wc.addressAutocomplete exists and has an active provider
⋮----
// Provider is available - don't queue updates while typing
⋮----
// Detach the unload handler that prevents a reload / redirect
⋮----
// Reload page
⋮----
// Trigger update in case we need a fresh nonce
⋮----
// Add new errors
⋮----
// The error notice template (plugins/woocommerce/templates/notices/error.php)
// adds the role="alert" to a list HTML element. This becomes a problem in this context
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/country-select.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/credit-card-form.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/geolocation.js">
function get_geo_hash()
⋮----
function needs_refresh()
⋮----
function update_forms()
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/lost-password.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/order-attribution.js">
const propertyAccessor = ( obj, path )
const returnNull = ()
const stringifyFalsyInputValue = ( value )
⋮----
// Hardcode Checkout store key (`wc.wcBlocksData.CHECKOUT_STORE_KEY`), as we no longer have `wc-blocks-checkout` as a dependency.
⋮----
function removeDuplicateInputGroups()
⋮----
function updateFormValues( values )
⋮----
function updateCheckoutBlockData( values )
⋮----
function isSbjsAvailable()
⋮----
function removeTrackingCookies()
⋮----
function eventuallyInitializeCheckoutBlock()
⋮----
connectedCallback()
⋮----
/**
		 * Update form values.
		 */
set values( values )
get values()
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/order-review.js">
function initGroup( container )
⋮----
function syncCaption()
⋮----
function focusInput( input )
⋮----
function currentRating( row )
⋮----
function currentText( row )
⋮----
/**
	 * Whether a row has been edited since page load.
	 *
	 * @param {HTMLElement} row `.woocommerce-review-order__item`
	 * @return {boolean}
	 */
function isRowDirty( row )
⋮----
/**
	 * Enable / disable the review-order submit button based on whether at
	 * least one row has been edited since page load.
	 *
	 * @param {HTMLFormElement} form `.woocommerce-review-order__form`
	 */
function initSubmitGate( form )
⋮----
function syncSubmit()
⋮----
function setRowRatingError( row, visible )
⋮----
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/password-strength-meter.js">
// Reset.
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/price-slider.js">
function init_price_filter()
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/single-product.js">
timeToIdle: 0, // Ensure the gallery controls are always visible to avoid keyboard navigation issues.
⋮----
// Initializes and opens PhotoSwipe.
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/tokenization-form.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/woocommerce.js">
function store_notice_keydown_handler( event )
⋮----
function store_notice_click_handler( event )
⋮----
function on_keydown_remove_from_cart( event )
⋮----
function focus_populate_live_region()
⋮----
function refresh_sorted_by_live_region()
⋮----
function on_document_ready()
</file>

<file path="plugins/woocommerce/client/legacy/js/frontend/wp-consent-api-integration.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/gateways/paypal.js">
function renderButtons()
⋮----
// If PayPal is not loaded, don't try to render the buttons.
⋮----
const manageCartForProductPageOrder = async () =>
⋮----
// Clearing the cart and re-adding the item causes the current WooCommerce draft order to be lost.
// If the user is re-opening the payment modal and has not changed anything, do nothing;
// we want to resume the existing draft order if the cart has not changed.
⋮----
// Empty the cart before adding the product.
⋮----
async createOrder( data )
⋮----
// eslint-disable-next-line no-console
⋮----
onApprove()
⋮----
async onCancel( data )
⋮----
// eslint-disable-next-line no-console
⋮----
function applyStyles()
</file>

<file path="plugins/woocommerce/client/legacy/js/jquery-blockui/jquery.blockUI.js">
function setup($)
⋮----
function install(el, opts)
⋮----
function remove(el, opts)
⋮----
function reset(els,data,opts,el)
⋮----
function bind(b, el, opts)
⋮----
function handler(e)
⋮----
function focus(back)
⋮----
function center(el, x, y)
⋮----
function sz(el, p)
</file>

<file path="plugins/woocommerce/client/legacy/js/jquery-cookie/jquery.cookie.js">
function encode(s)
⋮----
function decode(s)
⋮----
function stringifyCookieValue(value)
⋮----
function parseCookieValue(s)
⋮----
// Replace server-side written pluses with spaces.
// If we can't decode the cookie, ignore it, it's unusable.
⋮----
function read(s, converter)
⋮----
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
⋮----
// Read
⋮----
// To prevent the for loop in the first place assign an empty array
// in case there are no cookies at all. Also prevents odd result when
// calling $.cookie().
⋮----
// If second argument (value) is a function it's a converter...
</file>

<file path="plugins/woocommerce/client/legacy/js/jquery-flot/jquery.flot.js">
(function(B)
⋮----
// the actual Flot code
⋮----
// Cache the prototype hasOwnProperty for faster access
⋮----
///////////////////////////////////////////////////////////////////////////
// The Canvas object is a wrapper around an HTML5 <canvas> tag.
//
// @constructor
// @param {string} cls List of classes to apply to the canvas.
// @param {element} container Element onto which to append the canvas.
//
// Requiring a container is a little iffy, but unfortunately canvas
// operations don't work unless the canvas is attached to the DOM.
⋮----
function Canvas(cls, container)
⋮----
// If the font is a font-spec object, generate a CSS font definition
⋮----
function Plot(placeholder, data_, options_, plugins)
⋮----
function executeHooks(hook, args)
⋮----
function initPlugins()
⋮----
function parseOptions(opts)
⋮----
function setData(d)
⋮----
... (109 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/jquery-flot/jquery.flot.pie.js">
function init(plot)
⋮----
function processDatapoints(plot, series, datapoints)
⋮----
function combine(data)
⋮----
function draw(plot, newCtx)
⋮----
function clear()
⋮----
function drawShadow()
⋮----
function drawPie()
⋮----
function drawSlice(angle, color, fill)
⋮----
function drawLabels()
⋮----
function drawLabel(slice, startAngle, index)
⋮----
function drawDonutHole(layer)
⋮----
function isPointInPoly(poly, pt)
⋮----
function findNearbySlice(mouseX, mouseY)
⋮----
function onMouseMove(e)
⋮----
function onClick(e)
⋮----
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/jquery-flot/jquery.flot.resize.js">
(function($,h,c)
⋮----
function init(plot)
⋮----
function onResize()
⋮----
function bindEvents(plot, eventHolder)
⋮----
function shutdown(plot, eventHolder)
</file>

<file path="plugins/woocommerce/client/legacy/js/jquery-flot/jquery.flot.stack.js">
function init(plot)
⋮----
function findMatchingSeries(s, allseries)
⋮----
function stackData(plot, s, datapoints)
</file>

<file path="plugins/woocommerce/client/legacy/js/jquery-flot/jquery.flot.time.js">
function floorInBase(n, base)
⋮----
function formatDate(d, fmt, monthNames, dayNames)
⋮----
case 'h':	// For back-compat with 0.7; remove in 1.0
⋮----
// quarters not in Open Group's strftime specification
⋮----
// To have a consistent view of time-based data independent of which time
// zone the client happens to be in we need a date-like object independent
// of time zones.  This is done through a wrapper that only calls the UTC
// versions of the accessor methods.
⋮----
function makeUtcWrapper(d)
⋮----
function addProxyMethod(sourceObj, sourceMethod, targetObj, targetMethod)
⋮----
// support strftime, if found
⋮----
function dateGenerator(ts, opts)
⋮----
function init(plot)
</file>

<file path="plugins/woocommerce/client/legacy/js/jquery-payment/jquery.payment.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/jquery-qrcode/jquery.qrcode.js">
function QR8bitByte(data)
⋮----
function QRCode(typeNumber, errorCorrectLevel)
⋮----
function QRPolynomial(num, shift)
⋮----
function QRRSBlock(totalCount, dataCount)
⋮----
function QRBitBuffer()
</file>

<file path="plugins/woocommerce/client/legacy/js/jquery-serializejson/jquery.serializejson.js">
// Return computed options (opts to be used in the rest of the script)
⋮----
keys = $.map(keys, function (key) { return key.replace(/\]/g, ''); }); // remove closing brackets
if (keys[0] === '') { keys.shift(); } // ensure no opening bracket ("[foo][inn]" should be same as "foo[inn]")
⋮----
// Set a value in an object or array, using multiple keys to set in a nested object or array:
//
// deepSet(obj, ['foo'], v)
⋮----
o.push(value); // '' is used to push values into the array (assume o is an array)
⋮----
o[key] = value; // other keys can be used as object keys or array indexes
⋮----
// With more keys is a deepSet. Apply recursively.
⋮----
// '' is used to push values into the array,
// with nextKey, set the value into the same object, in object[nextKey].
// Covers the case of ['', 'foo'] and ['', 'var'] to push the object {foo, var}, and the case of nested arrays.
⋮----
lastIdx = o.length - 1; // asume o is array
⋮----
if (f.isObject(lastVal) && (f.isUndefined(lastVal[nextKey]) || keys.length > 2)) { // if nextKey is not present in the last object element, or there are more keys to deep set
key = lastIdx; // then set the new value in the same object element
⋮----
key = lastIdx + 1; // otherwise, point to set the next index in the array
⋮----
// '' is used to push values into the array "array[]"
</file>

<file path="plugins/woocommerce/client/legacy/js/jquery-tiptip/jquery.tipTip.js">
org_elem.removeAttr(opts.attribute); //remove original Attribute
⋮----
function active_tiptip()
⋮----
function deactive_tiptip()
</file>

<file path="plugins/woocommerce/client/legacy/js/jquery-ui-touch-punch/jquery-ui-touch-punch.js">
function simulateMouseEvent (event, simulatedType)
</file>

<file path="plugins/woocommerce/client/legacy/js/js-cookie/js.cookie.js">
function assign (target)
⋮----
function init (converter, defaultAttributes)
⋮----
function set (name, value, attributes)
⋮----
// Considers RFC 6265 section 5.2:
// ...
// 3.  If the remaining unparsed-attributes contains a %x3B (";")
//     character:
// Consume the characters of the unparsed-attributes up to,
// not including, the first %x3B (";") character.
// ...
⋮----
function get (name)
</file>

<file path="plugins/woocommerce/client/legacy/js/photoswipe/photoswipe-ui-default.js">
getPageURLForShare: function( /* shareButtonData */ ) {
⋮----
getTextForShare: function( /* shareButtonData */ ) {
⋮----
// reset idle timer
</file>

<file path="plugins/woocommerce/client/legacy/js/photoswipe/photoswipe.js">
/*
			elastic: {
				out: function ( k ) {
					var s, a = 0.1, p = 0.4;
					if ( k === 0 ) return 0;
					if ( k === 1 ) return 1;
					if ( !a || a < 1 ) { a = 1; s = p / 4; }
					else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI );
					return ( a * Math.pow( 2, - 10 * k) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) + 1 );
				},
			},
			back: {
				out: function ( k ) {
					var s = 1.70158;
					return --k * k * ( ( s + 1 ) * k + s ) + 1;
				}
			}
		*/
⋮----
/**
	 *
	 * @return {object}
	 *
	 * {
	 *  raf : request animation frame function
	 *  caf : cancel animation frame function
	 *  transfrom : transform property key (with vendor), or null if not supported
	 *  oldIE : IE8 or below
	 * }
	 *
... (34 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/prettyPhoto/jquery.prettyPhoto.init.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/prettyPhoto/jquery.prettyPhoto.js">
social_tools: '<div class="twitter"><a href="//twitter.com/share" class="twitter-share-button" data-count="none">Tweet</a><script type="text/javascript" src="//platform.twitter.com/widgets.js"></script></div><div class="facebook"><iframe src="//www.facebook.com/plugins/like.php?locale=en_US&href={location_href}&amp;layout=button_count&amp;show_faces=true&amp;width=500&amp;action=like&amp;font&amp;colorscheme=light&amp;height=23" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:500px; height:23px;" allowTransparency="true"></iframe></div>' /* html or false to disable */
⋮----
// Global variables accessible only by prettyPhoto
⋮----
// prettyPhoto container specific
⋮----
// Window size
⋮----
// Global elements
⋮----
// Window/Keyboard events
⋮----
set_position = jQuery.inArray($(this).attr('href'), pp_images); // Define where in the array the clicked item is positionned
⋮----
_build_overlay(this); // Build the overlay {this} being the caller
⋮----
/**
		* Opens the prettyPhoto modal box.
		* @param image {String,Array} Full path to the image to be open, can also be an array containing full images paths.
		* @param title {String,Array} The title to be displayed with the picture, can also be an array containing all the titles.
		* @param description {String,Array} The description to be displayed with the picture, can also be an array containing all the descriptions.
		*/
⋮----
_build_overlay(event.target); // Build the overlay {this} being the caller
⋮----
if(settings.hideflash) $('object,embed,iframe[src*=youtube],iframe[src*=vimeo]').css('visibility','hidden'); // Hide the flash
⋮----
_checkPosition($(pp_images).length); // Hide the next/previous links if on first or last images.
⋮----
// Rebuild Facebook Like Button with updated href
... (61 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/round/round.js">
function round (value, precision, mode)
</file>

<file path="plugins/woocommerce/client/legacy/js/select2/select2.full.js">
function hasProp(obj, prop)
⋮----
function normalize(name, baseName)
⋮----
//Lop off the last part of baseParts, so that . matches the
//"directory" and not name of the baseName's module. For instance,
⋮----
function makeRequire(relName, forceSync)
⋮----
function makeNormalize(relName)
⋮----
function makeLoad(depName)
⋮----
function callDep(name)
⋮----
function splitPrefix(name)
⋮----
function makeConfig(name)
⋮----
//Use name if no relName
⋮----
//Call the callback to define the module, if necessary.
⋮----
function BaseConstructor ()
⋮----
function getMethods (theClass)
⋮----
function DecoratedClass ()
⋮----
function ctr ()
... (153 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/select2/select2.js">
function hasProp(obj, prop)
⋮----
function normalize(name, baseName)
⋮----
//Lop off the last part of baseParts, so that . matches the
//"directory" and not name of the baseName's module. For instance,
⋮----
function makeRequire(relName, forceSync)
⋮----
function makeNormalize(relName)
⋮----
function makeLoad(depName)
⋮----
function callDep(name)
⋮----
function splitPrefix(name)
⋮----
function makeConfig(name)
⋮----
//Use name if no relName
⋮----
//Call the callback to define the module, if necessary.
⋮----
function BaseConstructor ()
⋮----
function getMethods (theClass)
⋮----
function DecoratedClass ()
⋮----
function ctr ()
... (104 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/selectWoo/selectWoo.full.js">
function hasProp(obj, prop)
⋮----
function normalize(name, baseName)
⋮----
// Starts with a '.' so need the baseName
⋮----
//Convert baseName to array, and lop off the last part,
//so that . matches that 'directory' and not name of the baseName's
⋮----
function makeRequire(relName, forceSync)
⋮----
function makeNormalize(relName)
⋮----
function makeLoad(depName)
⋮----
function callDep(name)
⋮----
function splitPrefix(name)
⋮----
function makeRelParts(relName)
⋮----
function makeConfig(name)
⋮----
//Use name if no relName
⋮----
//Call the callback to define the module, if necessary.
⋮----
function BaseConstructor ()
⋮----
function getMethods (theClass)
... (152 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/selectWoo/selectWoo.js">
function hasProp(obj, prop)
⋮----
function normalize(name, baseName)
⋮----
// Starts with a '.' so need the baseName
⋮----
//Convert baseName to array, and lop off the last part,
//so that . matches that 'directory' and not name of the baseName's
⋮----
function makeRequire(relName, forceSync)
⋮----
function makeNormalize(relName)
⋮----
function makeLoad(depName)
⋮----
function callDep(name)
⋮----
function splitPrefix(name)
⋮----
function makeRelParts(relName)
⋮----
function makeConfig(name)
⋮----
//Use name if no relName
⋮----
//Call the callback to define the module, if necessary.
⋮----
function BaseConstructor ()
⋮----
function getMethods (theClass)
... (103 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/js/stupidtable/stupidtable.js">

</file>

<file path="plugins/woocommerce/client/legacy/js/zoom/jquery.zoom.js">
function start(e)
⋮----
function stop()
</file>

<file path="plugins/woocommerce/client/legacy/.browserslistrc">
extends @wordpress/browserslist-config
</file>

<file path="plugins/woocommerce/client/legacy/.stylelintrc">
# Legacy SCSS lives here, so this config deliberately diverges from the sibling
# configs in client/blocks and packages/js/email-editor. Read the notes before
# "aligning" any of these with the preset.
{
	"extends": "@wordpress/stylelint-config/scss",

	# Vendored upstream file; 159 violations we do not own. This is the single
	# authoritative exclusion, so a direct `stylelint` run skips it too.
	"ignoreFiles": [ "css/select2.scss" ],

	"rules": {
		# The icon fonts have no generic fallback by design.
		"font-family-no-missing-generic-family-keyword": [
			true,
			{
				"ignoreFontFamilies": [ "WooCommerce", "Dashicons", "dashicons" ]
			}
		],

		# The preset says "never". Several backgrounds here are base64/SVG data
		# URIs containing spaces, quotes and "<", which cannot legally be
		# unquoted. The rule is report-only (no "fixable" in its stylelint 14
		# meta), so "never" would not rewrite them, it would just report 41
		# violations we would then have to blanket-disable. "always" states the
		# safe policy once instead.
		"function-url-quotes": "always",

		# The preset allows only px for line-height. This code uses px, em, rem
		# and %, so any list that passes today would have to allow all of them,
		# which is what null already does. Changing the values is a behavior
... (40 lines truncated)
</file>

<file path="plugins/woocommerce/client/legacy/babel-transformer.js">

</file>

<file path="plugins/woocommerce/client/legacy/eslint.config.mjs">
/**
 * External dependencies
 */
⋮----
/*
			 * These are classic scripts, not modules. eslintrc defaulted to
			 * `script`; flat config defaults `.js` to `module`, which would
			 * parse them in strict mode.
			 */
</file>

<file path="plugins/woocommerce/client/legacy/Gruntfile.js">
const runQueued = ( tasks ) =>
</file>

<file path="plugins/woocommerce/client/legacy/jest.config.json">
{
	"rootDir": "./js",
	"collectCoverageFrom": [
		"js/**/*.js",
		"!**/node_modules/**"
	],
	"moduleDirectories": [ "node_modules" ],
	"preset": "@wordpress/jest-preset-default",
	"testPathIgnorePatterns": [
		"<rootDir>/build/",
		"<rootDir>/node_modules/",
		"<rootDir>/tests/"
	],
	"roots": [ "<rootDir>" ],
	"transform": {
		"^.+\\.(js|ts|tsx)$": "<rootDir>/../babel-transformer.js"
	},
	"verbose": true,
	"cacheDirectory": "<rootDir>/../../node_modules/.cache/jest",
	"testEnvironment": "jest-fixed-jsdom"
}
</file>

<file path="plugins/woocommerce/client/legacy/package.json">
{
	"name": "@woocommerce/classic-assets",
	"private": true,
	"version": "1.0.0",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"main": "Gruntfile.js",
	"scripts": {
		"build": "pnpm build:project",
		"build:project": "pnpm --stream '/^build:project:.*$/'",
		"build:project:js": "grunt js",
		"build:project:css": "grunt css",
		"lint": "pnpm --if-present '/^lint:lang:.*$/'",
		"lint:fix": "pnpm --if-present '/^lint:fix:lang:.*$/'",
		"lint:lang:js": "eslint 'js/admin/*.js' 'js/frontend/*.js'",
		"lint:lang:css": "grunt stylelint",
		"lint:fix:lang:js": "eslint 'js/admin/*.js' 'js/frontend/*.js' --fix",
		"lint:fix:lang:css": "grunt stylelint --fix",
		"watch:build": "pnpm watch:build:project",
		"watch:build:project": "pnpm --stream '/^watch:build:project:.*$/'",
		"watch:build:project:assets": "grunt watch",
		"test:js": "wp-scripts test-unit-js --config jest.config.json"
	},
	"devDependencies": {
		"@types/node": "^24.1.0",
		"@wordpress/scripts": "32.6.0",
		"@wordpress/stylelint-config": "^21.36.0",
		"chokidar": "^3.6.0",
		"eslint": "^10.0.0",
		"globals": "^16.5.0",
... (49 lines truncated)
</file>

<file path="plugins/woocommerce/i18n/languages/README.md">
# WARNING! DO NOT PUT CUSTOM TRANSLATIONS HERE!

WooCommerce will delete all custom translations placed in this directory.

## Translating WooCommerce
Put your custom WooCommerce translations in your WordPress language directory, located at: WP_LANG_DIR . "/woocommerce/{$textdomain}-{$locale}.mo";

## Contributing your translating to WooCommerce
If you want to help translate WooCommerce, please visit our [translation page](https://translate.wordpress.org/projects/wp-plugins/woocommerce).
</file>

<file path="plugins/woocommerce/i18n/continents.php">

</file>

<file path="plugins/woocommerce/i18n/countries.php">

</file>

<file path="plugins/woocommerce/i18n/currencies.php">

</file>

<file path="plugins/woocommerce/i18n/currency-info.php">

</file>

<file path="plugins/woocommerce/i18n/locale-info.php">

</file>

<file path="plugins/woocommerce/i18n/phone.php">

</file>

<file path="plugins/woocommerce/i18n/postcode-validation-rules.json">
{
	"generatedFrom": {
		"package": "postcode-validator",
		"version": "3.10.22"
	},
	"rules": {
		"AT": {
			"pattern": "[0-9]{4}"
		},
		"BA": {
			"pattern": "[7-8][0-9]{4}"
		},
		"BE": {
			"pattern": "\\d{4}"
		},
		"BR": {
			"pattern": "\\d{5}[\\-]?\\d{3}"
		},
		"CA": {
			"pattern": "[ABCEGHJKLMNPRSTVXY][0-9][ABCEGHJKLMNPRSTVWXYZ] ?[0-9][ABCEGHJKLMNPRSTVWXYZ][0-9]",
			"flags": "i"
		},
		"CH": {
			"pattern": "\\d{4}"
		},
		"CZ": {
			"pattern": "(?:CZ-)?[0-9]{3}[ ]?[0-9]{2}"
		},
		"DE": {
			"pattern": "(?:0[1-9]|[1-9][0-9])[0-9]{3}"
... (88 lines truncated)
</file>

<file path="plugins/woocommerce/i18n/README.md">
# Countries and Subdivisions

If you are interested in making changes to the list of countries or subdivisions, please first read the guidance in our [developer documentation](../../../docs/contribution/contributing/string-localisation-guidelines.md#countries-and-subdivisions). WooCommerce tries to follow the [Unicode CLDR](https://cldr.unicode.org/) standard for these codes and names.
</file>

<file path="plugins/woocommerce/i18n/states.php">

</file>

<file path="plugins/woocommerce/i18n/units.php">

</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-address-provider.php">
abstract class WC_Address_Provider {
⋮----
public $id;
⋮----
public $name;
⋮----
public $branding_html = '';
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-data.php">
abstract class WC_Data {
⋮----
protected $id = 0;
⋮----
protected $data = array();
⋮----
protected $changes = array();
⋮----
protected $object_read = false;
⋮----
protected $object_type = 'data';
⋮----
protected $extra_data = array();
⋮----
protected $default_data = array();
⋮----
protected $data_store;
⋮----
protected $cache_group = '';
⋮----
/**
	 * Stores additional meta data.
	 *
	 * @since 3.0.0
	 * @var WC_Meta_Data[]|null
	 */
protected $meta_data = null;
⋮----
/**
	 * Clone mode for controlling meta ID handling during clone operations.
... (196 lines truncated)
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-deprecated-hooks.php">
use Automattic\Jetpack\Constants;
⋮----
abstract class WC_Deprecated_Hooks {
⋮----
protected $deprecated_hooks = array();
⋮----
protected $deprecated_version = array();
⋮----
public function __construct() {
⋮----
abstract public function hook_in( $hook_name );
⋮----
public function get_old_hooks( $new_hook ) {
⋮----
public function maybe_handle_deprecated_hook() {
⋮----
$old_hooks         = $this->get_old_hooks( $new_hook );
⋮----
$return_value = $this->handle_deprecated_hook( $new_hook, $old_hook, $new_callback_args, $return_value );
⋮----
abstract public function handle_deprecated_hook( $new_hook, $old_hook, $new_callback_args, $return_value );
⋮----
protected function get_deprecated_version( $old_hook ) {
return ! empty( $this->deprecated_version[ $old_hook ] ) ? $this->deprecated_version[ $old_hook ] : Constants::get_constant( 'WC_VERSION' );
⋮----
protected function display_notice( $old_hook, $new_hook ) {
wc_deprecated_hook( esc_html( $old_hook ), esc_html( $this->get_deprecated_version( $old_hook ) ), esc_html( $new_hook ) );
⋮----
abstract protected function trigger_hook( $old_hook, $new_callback_args );
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-integration.php">
abstract class WC_Integration extends WC_Settings_API {
⋮----
public $enabled = 'yes';
⋮----
public $method_title = '';
⋮----
/**
	 * Integration description.
	 *
	 * @var string
	 */
public $method_description = '';
⋮----
/**
	 * Return the title for admin screens.
	 *
	 * @return string
	 */
public function get_method_title() {
⋮----
public function get_method_description() {
⋮----
public function admin_options() {
echo '<h2>' . esc_html( $this->get_method_title() ) . '</h2>';
echo wp_kses_post( wpautop( $this->get_method_description() ) );
⋮----
parent::admin_options();
⋮----
public function init_settings() {
parent::init_settings();
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-log-handler.php">
abstract class WC_Log_Handler implements WC_Log_Handler_Interface {
⋮----
protected static function format_time( $timestamp ) {
⋮----
protected static function format_entry( $timestamp, $level, $message, $context ) {
$time_string  = self::format_time( $timestamp );
⋮----
protected static function get_backtrace() {
⋮----
$reflector = new \ReflectionClass( $class );
return $reflector->getFileName();
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-object-query.php">
abstract class WC_Object_Query {
⋮----
protected $query_vars = array();
⋮----
public function __construct( $args = array() ) {
$this->query_vars = wp_parse_args( $args, $this->get_default_query_vars() );
⋮----
public function get_query_vars() {
⋮----
public function get( $query_var, $default = '' ) {
⋮----
/**
	 * Set a query variable.
	 *
	 * @param string $query_var Query variable to set.
	 * @param mixed  $value Value to set for query variable.
	 */
public function set( $query_var, $value ) {
⋮----
/**
	 * Get the default allowed query vars.
	 *
	 * @return array
	 */
protected function get_default_query_vars() {
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-order.php">
use Automattic\WooCommerce\Caches\OrderCache;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\TaxBasedOn;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
use Automattic\WooCommerce\Internal\Customers\SearchService as CustomersSearchService;
use Automattic\WooCommerce\Internal\Orders\PaymentInfo;
use Automattic\WooCommerce\Internal\Tax\TaxRateDataStore;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\ArrayUtil;
use Automattic\WooCommerce\Utilities\NumberUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
⋮----
protected $data = array(
⋮----
protected $legacy_datastore_props = array(
⋮----
protected $items = array();
⋮----
protected $items_to_delete = array();
⋮----
protected $temp_item_id_counter = 0;
⋮----
private $data_store_supports_deferred_item_deletion = null;
⋮----
protected $item_types_to_bulk_delete = array();
... (984 lines truncated)
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-payment-gateway.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Enums\PaymentGatewayFeature;
use Automattic\WooCommerce\Internal\Admin\Settings\Utils as SettingsUtils;
use Automattic\WooCommerce\Internal\Utilities\HtmlSanitizer;
⋮----
abstract class WC_Payment_Gateway extends WC_Settings_API {
⋮----
public $order_button_text;
⋮----
public $has_custom_place_order_button = false;
⋮----
public $enabled = 'yes';
⋮----
public $title;
⋮----
public $description;
⋮----
public $chosen;
⋮----
public $method_title = '';
⋮----
/**
	 * Gateway description.
	 *
	 * @var string
	 */
public $method_description = '';
⋮----
/**
	 * True if the gateway shows fields on the checkout.
... (229 lines truncated)
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-payment-token.php">
abstract class WC_Payment_Token extends WC_Legacy_Payment_Token {
⋮----
protected $data = array(
⋮----
/**
	 * Token Type (CC, eCheck, or a custom type added by an extension).
	 * Set by child classes.
	 *
	 * @var string
	 */
protected $type = '';
⋮----
/**
	 * Initialize a payment token.
	 *
	 * These fields are accepted by all payment tokens:
	 * is_default   - boolean Optional - Indicates this is the default payment token for a user
	 * token        - string  Required - The actual token to store
	 * gateway_id   - string  Required - Identifier for the gateway this token is associated with
	 * user_id      - int     Optional - ID for the user this token is associated with. 0 if this token is not associated with a user
	 *
	 * @since 2.6.0
	 * @param mixed $token Token.
	 */
public function __construct( $token = '' ) {
parent::__construct( $token );
⋮----
$this->set_id( $token );
⋮----
$token_id = $token->get_id();
... (59 lines truncated)
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-privacy.php">
abstract class WC_Abstract_Privacy {
⋮----
public $name;
⋮----
protected $exporters = array();
⋮----
protected $erasers = array();
⋮----
protected $export_priority;
⋮----
protected $erase_priority;
⋮----
public function __construct( $name = '', $export_priority = 5, $erase_priority = 10 ) {
⋮----
$this->init();
⋮----
/**
	 * Hook in events.
	 */
protected function init() {
⋮----
public function add_privacy_message() {
⋮----
$content = $this->get_privacy_message();
⋮----
wp_add_privacy_policy_content( $this->name, $this->get_privacy_message() );
⋮----
public function get_privacy_message() {
⋮----
/**
... (28 lines truncated)
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-product.php">
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\CatalogVisibility;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore as ProductAttributesLookupDataStore;
⋮----
class WC_Product extends WC_Abstract_Legacy_Product {
⋮----
protected $object_type = 'product';
⋮----
protected $post_type = 'product';
⋮----
protected $cache_group = 'products';
⋮----
protected $data = array(
⋮----
protected $supports = array();
⋮----
public function __construct( $product = 0 ) {
parent::__construct( $product );
⋮----
$this->set_id( $product );
⋮----
$this->set_id( absint( $product->get_id() ) );
⋮----
$this->set_id( absint( $product->ID ) );
⋮----
$this->set_object_read( true );
... (758 lines truncated)
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-session.php">
abstract class WC_Session {
⋮----
protected $_customer_id;
⋮----
protected $_data = array();
⋮----
protected $_dirty = false;
⋮----
public function init() {}
⋮----
public function cleanup_sessions() {}
⋮----
public function __get( $key ) {
return $this->get( $key );
⋮----
public function __set( $key, $value ) {
$this->set( $key, $value );
⋮----
public function __isset( $key ) {
⋮----
public function __unset( $key ) {
⋮----
public function get( $key, $default_value = null ) {
⋮----
public function set( $key, $value ) {
⋮----
$this->__unset( $key );
⋮----
public function get_customer_id() {
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-settings-api.php">
use Automattic\WooCommerce\Internal\Utilities\HtmlSanitizer;
⋮----
abstract class WC_Settings_API {
⋮----
public $plugin_id = 'woocommerce_';
⋮----
public $id = '';
⋮----
/**
	 * Validation errors.
	 *
	 * @var array of strings
	 */
public $errors = array();
⋮----
/**
	 * Setting values.
	 *
	 * @var array
	 */
public $settings = array();
⋮----
/**
	 * Form option fields.
	 *
	 * @var array
	 */
public $form_fields = array();
⋮----
/**
... (257 lines truncated)
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-shipping-method.php">
use Automattic\WooCommerce\Enums\ProductTaxStatus;
⋮----
abstract class WC_Shipping_Method extends WC_Settings_API {
⋮----
public $supports = array( 'settings' );
⋮----
public $id = '';
⋮----
/**
	 * Method title.
	 *
	 * @var string
	 */
public $method_title = '';
⋮----
/**
	 * Method description.
	 *
	 * @var string
	 */
public $method_description = '';
⋮----
/**
	 * Yes or no based on whether the method is enabled.
	 *
	 * @var string
	 */
public $enabled = 'yes';
⋮----
public $title;
... (173 lines truncated)
</file>

<file path="plugins/woocommerce/includes/abstracts/abstract-wc-widget.php">
use Automattic\Jetpack\Constants;
⋮----
abstract class WC_Widget extends WP_Widget {
⋮----
public $widget_cssclass;
⋮----
public $widget_description;
⋮----
public $widget_id;
⋮----
public $widget_name;
⋮----
public $settings;
⋮----
public function __construct() {
⋮----
parent::__construct( $this->widget_id, $this->widget_name, $widget_ops );
⋮----
public function get_cached_widget( $args ) {
⋮----
$cache = wp_cache_get( $this->get_widget_id_for_cache( $this->widget_id ), 'widget' );
⋮----
if ( isset( $cache[ $this->get_widget_id_for_cache( $args['widget_id'] ) ] ) ) {
echo $cache[ $this->get_widget_id_for_cache( $args['widget_id'] ) ];
⋮----
public function cache_widget( $args, $content ) {
⋮----
$cache[ $this->get_widget_id_for_cache( $args['widget_id'] ) ] = $content;
⋮----
wp_cache_set( $this->get_widget_id_for_cache( $this->widget_id ), $cache, 'widget' );
... (43 lines truncated)
</file>

<file path="plugins/woocommerce/includes/abstracts/class-wc-background-process.php">
abstract class WC_Background_Process extends WP_Background_Process {
⋮----
protected function is_queue_empty() {
⋮----
$key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
⋮----
$count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table} WHERE {$column} LIKE %s", $key ) );
⋮----
protected function get_batch() {
⋮----
$query = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table} WHERE {$column} LIKE %s ORDER BY {$key_column} ASC LIMIT 1", $key ) );
⋮----
protected function batch_limit_exceeded() {
return $this->time_exceeded() || $this->memory_exceeded();
⋮----
protected function handle() {
$this->lock_process();
⋮----
$batch = $this->get_batch();
⋮----
$task = $this->task( $value );
⋮----
if ( $this->batch_limit_exceeded() ) {
⋮----
$this->update( $batch->key, $batch->data );
⋮----
$this->delete( $batch->key );
⋮----
} while ( ! $this->batch_limit_exceeded() && ! $this->is_queue_empty() );
⋮----
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/helper/views/html-helper-compat.php">

</file>

<file path="plugins/woocommerce/includes/admin/helper/views/html-main.php">
<?php require WC_Helper::get_view_filename( 'html-section-nav.php' ); ?>
⋮----
<?php require WC_Helper::get_view_filename( 'html-section-notices.php' ); ?>
⋮----
<?php require WC_Helper::get_view_filename( 'html-section-account.php' ); ?>
⋮----
$filters        = array_keys( WC_Helper::get_filters() );
⋮----
$current_filter = WC_Helper::get_current_filter();
$counts         = WC_Helper::get_filters_counts();
⋮----
foreach ( WC_Helper::get_filters() as $key => $label ) :
⋮----
<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
⋮----
<a href="<?php echo esc_url( WC_Helper::add_utm_params_to_url_for_subscription_link( $subscription['product_url'], 'product-name' ) ); ?>" target="_blank">
⋮----
<a href="<?php echo esc_url( WC_Helper::add_utm_params_to_url_for_subscription_link( $data['_product_url'], 'product-name' ) ); ?>" target="_blank">
</file>

<file path="plugins/woocommerce/includes/admin/helper/views/html-notice-woo-updater-not-activated.php">

</file>

<file path="plugins/woocommerce/includes/admin/helper/views/html-notice-woo-updater-not-installed.php">
esc_url( WC_Woo_Update_Manager_Plugin::generate_install_url() ),
</file>

<file path="plugins/woocommerce/includes/admin/helper/views/html-oauth-start.php">
<?php require WC_Helper::get_view_filename( 'html-section-nav.php' ); ?>
⋮----
<?php require WC_Helper::get_view_filename( 'html-section-notices.php' ); ?>
⋮----
<img src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/woo-logo.svg' ); ?>" alt="
</file>

<file path="plugins/woocommerce/includes/admin/helper/views/html-section-account.php">

</file>

<file path="plugins/woocommerce/includes/admin/helper/views/html-section-nav.php">
$count_html = WC_Helper_Updater::get_updates_count_html();
</file>

<file path="plugins/woocommerce/includes/admin/helper/views/html-section-notices.php">

</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-helper-admin.php">
use Automattic\WooCommerce\Internal\Admin\Marketplace;
use Automattic\WooCommerce\Admin\PluginsHelper;
⋮----
class WC_Helper_Admin {
⋮----
public static function load() {
⋮----
public static function add_marketplace_settings( $settings ) {
if ( ! WC_Helper::is_site_connected() && isset( $_GET['connect'] ) ) {
wp_safe_redirect( self::get_connection_url() );
⋮----
$auth_user_data  = WC_Helper_Options::get( 'auth_user_data', array() );
⋮----
// Get the all installed themes and plugins. Knowing this will help us decide to show Add to Store button on product cards.
$installed_products = array_merge( WC_Helper::get_local_plugins(), WC_Helper::get_local_themes() );
⋮----
'isConnected'                => WC_Helper::is_site_connected(),
'connectURL'                 => self::get_connection_url(),
'reConnectURL'               => self::get_connection_url( true ),
⋮----
'inAppPurchaseURLParams'     => WC_Admin_Addons::get_in_app_purchase_url_params(),
⋮----
'mySubscriptionsTabLoaded'   => WC_Helper_Options::get( 'my_subscriptions_tab_loaded' ),
'wooUpdateManagerInstalled'  => WC_Woo_Update_Manager_Plugin::is_plugin_installed(),
'wooUpdateManagerActive'     => WC_Woo_Update_Manager_Plugin::is_plugin_active(),
'wooUpdateManagerInstallUrl' => WC_Woo_Update_Manager_Plugin::generate_install_url(),
⋮----
$settings['wccomHelper']['wooUpdateCount']          = WC_Helper_Updater::get_updates_count_based_on_site_status();
$settings['wccomHelper']['connected_notice']        = PluginsHelper::get_wccom_connected_notice( $auth_user_email );
$settings['wccomHelper']['woocomConnectNoticeType'] = WC_Helper_Updater::get_woo_connect_notice_type();
... (48 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-helper-api-backoff.php">
class WC_Helper_API_Backoff {
⋮----
private static function get_all_bounds(): array {
⋮----
private static function get_bounds( string $request_type ): array {
⋮----
return self::get_all_bounds()[ $request_type ] ?? $fallback;
⋮----
private static function get_transient_key( string $request_type ): string {
⋮----
public static function is_refresh_request(): bool {
$request_uri = wp_unslash( $_SERVER['REQUEST_URI'] ?? '' ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
⋮----
public static function is_rate_limited( string $request_type ): bool {
if ( self::is_refresh_request() ) {
self::clear( $request_type );
⋮----
$retry_after = get_transient( self::get_transient_key( $request_type ) );
⋮----
public static function record_from_response( string $request_type, array $response ): void {
⋮----
$bounds = self::get_bounds( $request_type );
⋮----
$retry_after = self::get_retry_after_from_headers( $response );
⋮----
set_transient( self::get_transient_key( $request_type ), $now + $retry_after, $retry_after );
⋮----
private static function get_retry_after_from_headers( array $response ): ?int {
⋮----
public static function get_retry_after( string $request_type ): ?int {
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-helper-api.php">
class WC_Helper_API {
⋮----
public static $api_base;
⋮----
public static function load() {
⋮----
public static function request( $endpoint, $args = array() ) {
⋮----
$url = self::url( $endpoint, $args['query_string'] );
⋮----
if ( ! self::_authenticate( $url, $args ) ) {
⋮----
private static function create_request_signature( string $access_token_secret, string $url, string $method, $body = null ): string {
⋮----
public static function add_auth_parameters( string $url ): string {
$auth = WC_Helper_Options::get( 'auth' );
⋮----
$signature = self::create_request_signature( (string) $auth['access_token_secret'], $url, 'GET' );
⋮----
private static function _authenticate( &$url, &$args ) {
⋮----
$signature = self::create_request_signature(
⋮----
public static function get( $endpoint, $args = array() ) {
⋮----
return self::request( $endpoint, $args );
⋮----
public static function post( $endpoint, $args = array() ) {
⋮----
public static function put( $endpoint, $args = array() ) {
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-helper-compat.php">
class WC_Helper_Compat {
⋮----
public static function load() {
⋮----
public static function helper_loaded() {
⋮----
self::remove_actions();
self::migrate_connection();
self::deactivate_plugin();
⋮----
public static function remove_actions() {
⋮----
public static function migrate_connection() {
⋮----
if ( WC_Helper_Options::get( 'did-migrate' ) ) {
⋮----
$auth = WC_Helper_Options::get( 'auth' );
⋮----
WC_Helper::log( 'Attempting oauth/migrate' );
WC_Helper_Options::update( 'did-migrate', true );
⋮----
WC_Helper::log( 'Master key not found, aborting' );
⋮----
$request = WC_Helper_API::post(
⋮----
WC_Helper::log( 'Call to oauth/migrate returned a non-200 response code' );
⋮----
WC_Helper::log( 'Call to oauth/migrate returned an empty token' );
⋮----
WC_Helper::log( 'Call to oauth/access_token returned a non-200 response code' );
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-helper-options.php">
class WC_Helper_Options {
⋮----
private static $option_name = 'woocommerce_helper_data';
⋮----
public static function update( $key, $value ) {
⋮----
public static function get( $key, $default = false ) {
</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-helper-orders-api.php">
class WC_Helper_Orders_API {
⋮----
public static function load() {
⋮----
public static function register_rest_routes() {
⋮----
public static function get_permission() {
return WC_Helper_Subscriptions_API::get_permission();
⋮----
public static function create_order( $request ) {
⋮----
return new \WP_REST_Response(
⋮----
$response = WC_Helper_API::post(
⋮----
'message' => __( 'Could not start the installation process. Reason: ', 'woocommerce' ) . $e->getMessage(),
⋮----
WC_Helper_Orders_API::load();
</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-helper-sanitization.php">
class WC_Helper_Sanitization {
⋮----
public static function sanitize_css( $css ) {
⋮----
// Remove potentially harmful constructs.
⋮----
// Block all data URIs.
⋮----
// Only allow URLs from specific trusted domains and their subdomains.
⋮----
// Block other potentially dangerous protocols.
⋮----
public static function sanitize_html( $html ) {
⋮----
$svg_tags     = self::wc_kses_safe_svg_tags();
⋮----
return wp_kses( self::wc_pre_sanitize_svg( $html ), $allowed_html );
⋮----
public static function wc_pre_sanitize_svg( $content ) {
⋮----
// Remove foreignObject elements (can contain arbitrary HTML).
⋮----
/**
	 * Add limited SVG support to wp_kses_post with XSS protection.
	 *
	 * @return array Array of allowed SVG tags and their attributes.
	 */
public static function wc_kses_safe_svg_tags() {
// SVG elements and attributes - security focused.
</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-helper-subscriptions-api.php">
class WC_Helper_Subscriptions_API {
⋮----
public static function load() {
⋮----
public static function register_rest_routes() {
⋮----
public static function get_permission() {
⋮----
public static function get_subscriptions() {
⋮----
if ( WC_Helper::is_site_connected() === true && empty( WC_Helper_Options::get( 'my_subscriptions_tab_loaded' ) ) ) {
WC_Helper_Options::update( 'my_subscriptions_tab_loaded', date( 'Y-m-d H:i:s' ) );
⋮----
$subscriptions = WC_Helper::get_subscription_list_data();
⋮----
public static function refresh() {
⋮----
WC_Helper::refresh_helper_subscriptions();
WC_Helper::get_subscriptions();
WC_Helper::get_product_usage_notice_rules();
WC_Helper::fetch_helper_connection_info();
⋮----
$api_error = WC_Helper::get_api_error();
⋮----
self::get_subscriptions();
⋮----
'message' => $e->getMessage(),
⋮----
public static function connect( $request ) {
$product_key = $request->get_param( 'product_key' );
... (34 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-helper-updater.php">
use Automattic\WooCommerce\Admin\PluginsHelper;
⋮----
class WC_Helper_Updater {
⋮----
public static function load() {
⋮----
public static function add_hook_for_modifying_update_notices() {
if ( ! WC_Woo_Update_Manager_Plugin::is_plugin_active() || ! WC_Helper::is_site_connected() ) {
⋮----
if ( WC_Helper::is_site_connected() ) {
⋮----
public static function setup_message_for_expired_and_expiring_subscriptions() {
foreach ( WC_Helper::get_local_woo_plugins() as $plugin ) {
⋮----
public static function setup_message_for_plugins_without_subscription() {
⋮----
public static function transient_update_plugins( $transient ) {
$update_data = self::get_update_data();
⋮----
if ( self::is_autoupdate_forced( $data, $item ) ) {
⋮----
$translations            = self::get_translations_update_data();
⋮----
public static function transient_update_themes( $transient ) {
⋮----
foreach ( WC_Helper::get_local_woo_themes() as $theme ) {
⋮----
/**
			 * Filters the Woo plugin data before saving it in transient used for updates.
			 *
... (106 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-helper.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Admin\Notes\Note;
⋮----
class WC_Helper {
⋮----
public static $log;
⋮----
private static $local_woo_plugins_cache = null;
⋮----
private static $local_woo_themes_cache = null;
⋮----
public static function get_view_filename( $view ) {
⋮----
public static function load() {
self::includes();
⋮----
protected static function remove_api_error_notice() {
⋮----
$data_store = \WC_Data_Store::load( 'admin-note' );
⋮----
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
⋮----
if ( $note->get_id() ) {
$data_store->delete( $note );
⋮----
private static function record_api_error( int $code, string $message ): void {
⋮----
self::log( 'Could not reach the WooCommerce.com API: ' . $message, 'error' );
⋮----
... (501 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-plugin-api-updater.php">
class WC_Plugin_Api_Updater {
⋮----
public static function load() {
⋮----
public static function plugins_api( $response, $action, $args ) {
⋮----
return self::override_products_api_response( $response, $action, $args );
⋮----
public static function themes_api( $response, $action, $args ) {
⋮----
public static function override_products_api_response( $response, $action, $args ) {
⋮----
// Look through update data by slug.
$update_data = WC_Helper_Updater::get_update_data();
⋮----
$is_site_connected = WC_Helper::is_site_connected();
⋮----
$request = WC_Helper_API::get(
⋮----
$request = WC_Helper_API::get( $endpoint );
⋮----
WC_Plugin_Api_Updater::load();
</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-product-usage-notice.php">
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
⋮----
class WC_Product_Usage_Notice {
⋮----
private static $product_usage_notice_rules = array();
⋮----
private static $current_notice_rule = array();
⋮----
public static function load() {
⋮----
public static function maybe_show_product_usage_notice( $screen ) {
⋮----
if ( ! WC_Helper::is_site_connected() ) {
⋮----
self::$product_usage_notice_rules = WC_Helper::get_product_usage_notice_rules();
⋮----
self::$current_notice_rule = self::get_current_notice_rule( $screen );
⋮----
if ( self::is_notice_throttled( $user_id, $product_id ) ) {
⋮----
private static function is_remind_later_clicked_recently( int $user_id, int $product_id ): bool {
⋮----
private static function has_reached_max_dismissals( int $user_id, int $product_id ): bool {
⋮----
private static function is_any_notices_dismissed_recently( int $user_id ): bool {
⋮----
private static function is_product_notice_dismissed_recently( int $user_id, int $product_id ): bool {
⋮----
private static function is_notice_throttled( int $user_id, int $product_id ): bool {
return self::is_remind_later_clicked_recently( $user_id, $product_id ) ||
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-woo-helper-connection.php">
class WC_Woo_Helper_Connection {
⋮----
public static function get_connection_url_notice(): string {
$connection_data = WC_Helper::get_cached_connection_data();
⋮----
$auth     = WC_Helper_Options::get( 'auth' );
⋮----
/* translators: 1: WooCommerce.com connection URL, 2: home URL */
⋮----
public static function get_deleted_connection_notice(): string {
⋮----
/* translators: 1: home URL */
⋮----
public static function has_host_plan_orders(): bool {
$subscriptions = WC_Helper::get_subscriptions();
</file>

<file path="plugins/woocommerce/includes/admin/helper/class-wc-woo-update-manager-plugin.php">
use Automattic\WooCommerce\Admin\PageController;
⋮----
class WC_Woo_Update_Manager_Plugin {
⋮----
public static function load(): void {
⋮----
public static function is_plugin_active(): bool {
⋮----
public static function is_plugin_installed(): bool {
⋮----
public static function generate_install_url(): string {
$install_url = WC_Helper::get_install_base_url() . self::WOO_UPDATE_MANAGER_SLUG . '/';
⋮----
return WC_Helper_API::add_auth_parameters( $install_url );
⋮----
public static function get_plugin_slug(): string {
⋮----
public static function show_woo_update_manager_install_notice(): void {
⋮----
if ( ! WC_Helper::is_site_connected() ) {
⋮----
if ( ! PageController::is_admin_or_embed_page() ) {
⋮----
if ( self::is_plugin_installed() && self::is_plugin_active() ) {
⋮----
if ( ! self::is_plugin_installed() ) {
⋮----
if ( self::install_admin_notice_dismissed() ) {
⋮----
if ( self::activate_admin_notice_dismissed() ) {
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/importers/mappings/default.php">
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
⋮----
function wc_importer_current_locale() {
⋮----
function wc_importer_default_english_mappings( $mappings ) {
⋮----
if ( wc_get_container()->get( CostOfGoodsSoldController::class )->feature_is_enabled() ) {
⋮----
function wc_importer_default_special_english_mappings( $mappings ) {
</file>

<file path="plugins/woocommerce/includes/admin/importers/mappings/generic.php">
function wc_importer_generic_mappings( $mappings ) {
</file>

<file path="plugins/woocommerce/includes/admin/importers/mappings/mappings.php">

</file>

<file path="plugins/woocommerce/includes/admin/importers/mappings/shopify.php">
function wc_importer_shopify_mappings( $mappings, $raw_headers ) {
⋮----
function wc_importer_shopify_special_mappings( $mappings, $raw_headers ) {
⋮----
function wc_importer_shopify_expand_data( $data ) {
</file>

<file path="plugins/woocommerce/includes/admin/importers/mappings/wordpress.php">
function wc_importer_wordpress_mappings( $mappings ) {
</file>

<file path="plugins/woocommerce/includes/admin/importers/views/html-csv-import-done.php">
$error_data = $error->get_error_data();
⋮----
<td><?php echo wp_kses_post( $error->get_error_message() ); ?></td>
</file>

<file path="plugins/woocommerce/includes/admin/importers/views/html-csv-import-footer.php">

</file>

<file path="plugins/woocommerce/includes/admin/importers/views/html-csv-import-header.php">

</file>

<file path="plugins/woocommerce/includes/admin/importers/views/html-csv-import-mapping.php">
<form class="wc-progress-form-content woocommerce-importer" method="post" action="<?php echo esc_url( $this->get_next_step_link() ); ?>">
⋮----
<?php foreach ( $this->get_mapping_options( $mapped_value ) as $key => $value ) : ?>
</file>

<file path="plugins/woocommerce/includes/admin/importers/views/html-csv-import-progress.php">

</file>

<file path="plugins/woocommerce/includes/admin/importers/views/html-csv-import-steps.php">

</file>

<file path="plugins/woocommerce/includes/admin/importers/views/html-product-csv-import-form.php">

</file>

<file path="plugins/woocommerce/includes/admin/importers/class-wc-product-csv-importer-controller.php">
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
use Automattic\WooCommerce\Internal\Utilities\URL;
use Automattic\WooCommerce\Utilities\I18nUtil;
⋮----
class WC_Product_CSV_Importer_Controller {
⋮----
protected $file = '';
⋮----
/**
	 * The current import step.
	 *
	 * @var string
	 */
protected $step = '';
⋮----
/**
	 * Progress steps.
	 *
	 * @var array
	 */
protected $steps = array();
⋮----
/**
	 * Errors.
	 *
	 * @var array
	 */
protected $errors = array();
⋮----
... (188 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/importers/class-wc-tax-rate-importer.php">
class WC_Tax_Rate_Importer extends WP_Importer {
⋮----
public $id;
⋮----
public $file_url;
⋮----
public $import_page;
⋮----
public $delimiter;
⋮----
public $import_error_message;
⋮----
public function __construct() {
⋮----
public function dispatch() {
⋮----
$this->header();
⋮----
$this->greet();
⋮----
if ( $this->handle_upload() ) {
⋮----
$this->import( $file );
⋮----
$this->import_error( $this->import_error_message );
⋮----
$this->footer();
⋮----
private function import_start() {
⋮----
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/list-tables/abstract-class-wc-admin-list-table.php">
abstract class WC_Admin_List_Table {
⋮----
protected $list_table_type = '';
⋮----
/**
	 * Object being shown on the row.
	 *
	 * @var object|null
	 */
protected $object = null;
⋮----
/**
	 * Constructor.
	 */
public function __construct() {
⋮----
public function maybe_render_blank_state( $which ) {
⋮----
$this->render_blank_state();
⋮----
protected function render_blank_state() {}
⋮----
public function disable_view_mode( $post_types ) {
⋮----
public function restrict_manage_posts() {
⋮----
$this->render_filters();
⋮----
public function request_query( $query_vars ) {
⋮----
... (71 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/list-tables/class-wc-admin-list-table-coupons.php">
class WC_Admin_List_Table_Coupons extends WC_Admin_List_Table {
⋮----
protected $list_table_type = 'shop_coupon';
⋮----
public function __construct() {
parent::__construct();
⋮----
protected function render_blank_state() {
⋮----
protected function get_primary_column() {
⋮----
protected function get_row_actions( $actions, $post ) {
⋮----
public function define_columns( $columns ) {
⋮----
protected function prepare_row_data( $post_id ) {
⋮----
if ( empty( $this->object ) || $this->object->get_id() !== $post_id ) {
⋮----
protected function render_coupon_code_column() {
⋮----
$edit_link = get_edit_post_link( $this->object->get_id() );
$title     = $this->object->get_code();
⋮----
protected function render_type_column() {
echo esc_html( wc_get_coupon_type( $this->object->get_discount_type() ) );
⋮----
protected function render_amount_column() {
echo esc_html( wc_format_localized_price( $this->object->get_amount() ) );
⋮----
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/list-tables/class-wc-admin-list-table-orders.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\Admin\Orders\ListTable;
use Automattic\WooCommerce\Internal\Utilities\OrderItemMetaUtil;
⋮----
class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
⋮----
protected $list_table_type = 'shop_order';
⋮----
private $orders_list_table;
⋮----
public function __construct() {
parent::__construct();
$this->orders_list_table = wc_get_container()->get( ListTable::class );
⋮----
protected function render_blank_state() {
$this->orders_list_table->render_blank_state();
⋮----
protected function get_primary_column() {
⋮----
protected function get_row_actions( $actions, $post ) {
⋮----
protected function define_hidden_columns() {
⋮----
public function define_sortable_columns( $columns ) {
⋮----
public function define_columns( $columns ) {
⋮----
public function define_bulk_actions( $actions ) {
⋮----
protected function prepare_row_data( $post_id ) {
... (147 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/list-tables/class-wc-admin-list-table-products.php">
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
⋮----
class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
⋮----
protected $list_table_type = 'product';
⋮----
private bool $cogs_is_enabled;
⋮----
private bool $use_cogs_lookup_column;
⋮----
public function __construct() {
parent::__construct();
⋮----
$cogs_controller              = wc_get_container()->get( CostOfGoodsSoldController::class );
$this->cogs_is_enabled        = $cogs_controller->feature_is_enabled();
$this->use_cogs_lookup_column = $this->cogs_is_enabled && $cogs_controller->product_meta_lookup_table_cogs_value_columns_exist();
⋮----
public function prime_status_counts_cache(): void {
⋮----
wc_get_container()->get( ProductUtil::class )->get_counts_for_type( 'product' )
⋮----
public function prime_thumbnail_caches( $posts, $query ) {
if ( $query instanceof \WP_Query && 'product' === $query->get( 'post_type' ) ) {
⋮----
protected function render_blank_state() {
⋮----
protected function get_primary_column() {
... (222 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/marketplace-suggestions/templates/html-product-data-extensions.php">
WC_Marketplace_Suggestions::render_suggestions_container( 'product-edit-meta-tab-header' );
WC_Marketplace_Suggestions::render_suggestions_container( 'product-edit-meta-tab-body' );
WC_Marketplace_Suggestions::render_suggestions_container( 'product-edit-meta-tab-footer' );
</file>

<file path="plugins/woocommerce/includes/admin/marketplace-suggestions/views/container.php">

</file>

<file path="plugins/woocommerce/includes/admin/marketplace-suggestions/class-wc-marketplace-suggestions.php">
class WC_Marketplace_Suggestions {
⋮----
public static function init() {
if ( ! self::allow_suggestions() ) {
⋮----
public static function product_data_tabs( $tabs ) {
⋮----
public static function product_data_panels() {
⋮----
public static function get_dismissed_suggestions() {
⋮----
public static function post_add_dismissed_suggestion_handler() {
⋮----
$dismissed_suggestions = self::get_dismissed_suggestions();
⋮----
public static function render_orders_list_empty_state() {
self::render_suggestions_container( 'orders-list-empty-header' );
self::render_suggestions_container( 'orders-list-empty-body' );
self::render_suggestions_container( 'orders-list-empty-footer' );
⋮----
public static function render_suggestions_container( $context ) {
⋮----
public static function show_suggestions_for_screen( $screen_id ) {
⋮----
return self::allow_suggestions();
⋮----
public static function maybe_trigger_suggestions_fetch() {
⋮----
if ( 'woocommerce_page_wc-admin' === $screen_id && self::allow_suggestions() ) {
self::get_suggestions_api_data();
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/marketplace-suggestions/class-wc-marketplace-updater.php">
class WC_Marketplace_Updater {
⋮----
public static function load() {
⋮----
public static function init() {
⋮----
public static function update_marketplace_suggestions() {
⋮----
if ( class_exists( 'WC_Marketplace_Suggestions' ) && WC_Marketplace_Suggestions::allow_suggestions() && $allow_tracking ) {
$request_data = self::add_personalization_data( $request_data );
⋮----
self::retry();
⋮----
public static function retry() {
WC()->queue()->cancel_all( 'woocommerce_update_marketplace_suggestions' );
WC()->queue()->schedule_single( time() + DAY_IN_SECONDS, 'woocommerce_update_marketplace_suggestions' );
⋮----
public static function add_personalization_data( $request_params ) {
⋮----
WC_Marketplace_Updater::load();
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-order-download-permission.php">
<button type="button" data-permission_id="<?php echo esc_attr( $download->get_id() ); ?>" rel="<?php echo esc_attr( $download->get_product_id() ) . ',' . esc_attr( $download->get_download_id() ); ?>" class="revoke_access button"><?php esc_html_e( 'Revoke access', 'woocommerce' ); ?></button>
⋮----
esc_html( $product->get_id() ),
esc_html( apply_filters( 'woocommerce_admin_download_permissions_title', $product->get_name(), $download->get_product_id(), $download->get_order_id(), $download->get_order_key(), $download->get_download_id() ) ),
⋮----
esc_html( wc_get_filename_from_url( $product->get_file_download_path( $download->get_download_id() ) ) )
⋮----
printf( _n( 'Downloaded %s time', 'Downloaded %s times', $download->get_download_count(), 'woocommerce' ), esc_html( $download->get_download_count() ) )
⋮----
<input type="hidden" name="permission_id[<?php echo esc_attr( $loop ); ?>]" value="<?php echo esc_attr( $download->get_id() ); ?>" />
<input type="number" step="1" min="0" class="short" name="downloads_remaining[<?php echo esc_attr( $loop ); ?>]" value="<?php echo esc_attr( $download->get_downloads_remaining() ); ?>" placeholder="<?php esc_attr_e( 'Unlimited', 'woocommerce' ); ?>" />
⋮----
<input type="text" class="short date-picker" name="access_expires[<?php echo esc_attr( $loop ); ?>]" value="<?php echo ! is_null( $download->get_access_expires() ) ? esc_attr( date_i18n( 'Y-m-d', $download->get_access_expires()->getTimestamp() ) ) : ''; ?>" maxlength="10" placeholder="<?php esc_attr_e( 'Never', 'woocommerce' ); ?>" pattern="<?php echo esc_attr( apply_filters( 'woocommerce_date_input_html_pattern', '[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])' ) ); ?>" />
⋮----
'download_file' => $download->get_product_id(),
'order'         => $download->get_order_key(),
'email'         => urlencode( $download->get_user_email() ),
'key'           => $download->get_download_id(),
⋮----
rawurlencode( $download->get_id() ),
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-order-fee.php">
<?php echo esc_html( $item->get_name() ? $item->get_name() : __( 'Fee', 'woocommerce' ) ); ?>
⋮----
<input type="text" placeholder="<?php esc_attr_e( 'Fee name', 'woocommerce' ); ?>" name="order_item_name[<?php echo absint( $item_id ); ?>]" value="<?php echo ( $item->get_name() ) ? esc_attr( $item->get_name() ) : ''; ?>" />
⋮----
<input type="hidden" name="order_item_tax_class[<?php echo absint( $item_id ); ?>]" value="<?php echo esc_attr( $item->get_tax_class() ); ?>" />
⋮----
echo wc_price( $item->get_total(), array( 'currency' => $order->get_currency() ) );
⋮----
if ( $refunded = -1 * $order->get_total_refunded_for_item( $item_id, 'fee' ) ) {
echo '<small class="refunded">' . wc_price( $refunded, array( 'currency' => $order->get_currency() ) ) . '</small>';
⋮----
<input type="text" name="line_total[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo esc_attr( wc_format_localized_price( 0 ) ); ?>" value="<?php echo esc_attr( wc_format_localized_price( $item->get_total() ) ); ?>" class="line_total wc_input_price" />
⋮----
if ( ( $tax_data = $item->get_taxes() ) && wc_tax_enabled() ) {
⋮----
$tax_item_id    = $tax_item->get_rate_id();
⋮----
echo ( '' !== $tax_item_total ) ? wc_price( wc_round_tax_total( $tax_item_total ), array( 'currency' => $order->get_currency() ) ) : '&ndash;';
⋮----
if ( $refunded = -1 * $order->get_tax_refunded_for_item( $item_id, $tax_item_id, 'fee' ) ) {
⋮----
<?php if ( $order->is_editable() ) : ?>
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-order-item-meta.php">
$hidden_order_itemmeta = \Automattic\WooCommerce\Internal\Utilities\OrderItemMetaUtil::get_hidden_keys();
⋮----
$meta_data = $item->get_all_formatted_meta_data( '' );
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-order-item.php">
use Automattic\WooCommerce\Internal\Admin\Orders\ItemQuantityLimits;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
⋮----
$product      = $item->get_product();
$product_link = $product ? admin_url( 'post.php?post=' . $item->get_product_id() . '&action=edit' ) : '';
$thumbnail    = $product ? apply_filters( 'woocommerce_admin_order_item_thumbnail', $product->get_image( 'thumbnail', array( 'title' => '' ), false ), $item_id, $item ) : '';
⋮----
$wc_price_arg = array( 'currency' => $order->get_currency() );
$is_visible   = $product && $product->is_visible();
⋮----
$item_name = apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, $is_visible );
⋮----
if ( $product && $product->get_sku() ) {
echo '<div class="wc-order-item-sku"><strong>' . esc_html__( 'SKU:', 'woocommerce' ) . '</strong> ' . esc_html( $product->get_sku() ) . '</div>';
⋮----
if ( $item->get_variation_id() ) {
⋮----
if ( 'product_variation' === get_post_type( $item->get_variation_id() ) ) {
echo esc_html( $item->get_variation_id() );
⋮----
printf( esc_html__( '%s (No longer exists)', 'woocommerce' ), esc_html( $item->get_variation_id() ) );
⋮----
<input type="hidden" name="order_item_tax_class[<?php echo absint( $item_id ); ?>]" value="<?php echo esc_attr( $item->get_tax_class() ); ?>" />
⋮----
<?php if ( wc_get_container()->get( CostOfGoodsSoldController::class )->feature_is_enabled() ) : ?>
<td class="item_cost_of_goods" width="1%" data-sort-value="<?php echo esc_attr( $item->get_cogs_value() ); ?>">
<?php $tooltip_text = $item->get_cogs_value_per_unit_tooltip_text(); ?>
⋮----
echo wp_kses_post( $item->get_cogs_value_html() );
⋮----
... (45 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-order-items.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
⋮----
$render_refunds = (bool) apply_filters( 'woocommerce_admin_order_should_render_refunds', 0 < $order->get_total() - $order->get_total_refunded() || 0 < absint( $order->get_item_count() - $order->get_item_count_refunded() ), $order->get_id(), $order );
⋮----
$line_items          = $order->get_items( apply_filters( 'woocommerce_admin_order_item_types', 'line_item' ) );
$discounts           = $order->get_items( 'discount' );
$line_items_fee      = $order->get_items( 'fee' );
$line_items_shipping = $order->get_items( 'shipping' );
$cogs_is_enabled     = wc_get_container()->get( CostOfGoodsSoldController::class )->feature_is_enabled();
⋮----
$order_taxes      = $order->get_taxes();
$tax_classes      = WC_Tax::get_tax_classes();
⋮----
<?php if ( $order->is_editable() ) : ?>
⋮----
do_action( 'woocommerce_before_order_item_' . $item->get_type() . '_html', $item_id, $item, $order );
⋮----
do_action( 'woocommerce_order_item_' . $item->get_type() . '_html', $item_id, $item, $order );
⋮----
do_action( 'woocommerce_admin_order_items_after_line_items', $order->get_id() );
⋮----
do_action( 'woocommerce_admin_order_items_after_fees', $order->get_id() );
⋮----
$shipping_methods = WC()->shipping() ? WC()->shipping()->load_shipping_methods() : array();
⋮----
do_action( 'woocommerce_admin_order_items_after_shipping', $order->get_id() );
⋮----
$refunds = $order->get_refunds();
⋮----
... (76 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-order-notes.php">
<abbr class="exact-date" title="<?php echo esc_attr( $note->date_created->date( 'Y-m-d H:i:s' ) ); ?>">
⋮----
echo esc_html( sprintf( __( '%1$s at %2$s', 'woocommerce' ), $note->date_created->date_i18n( wc_date_format() ), $note->date_created->date_i18n( wc_time_format() ) ) );
⋮----
$note_date_label   = $note->date_created->date_i18n( wc_date_format() );
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-order-refund.php">
$refunded_by  = $refund->get_refunded_by();
⋮----
if ( $who_refunded->exists() ) {
⋮----
<tr class="refund <?php echo ( ! empty( $class ) ) ? esc_attr( $class ) : ''; ?>" data-order_refund_id="<?php echo esc_attr( $refund->get_id() ); ?>">
⋮----
/* translators: 1: refund id 2: refund date 3: username, or "System" when no user issued the refund */
⋮----
esc_html( $refund->get_id() ),
esc_html( wc_format_datetime( $refund->get_date_created(), get_option( 'date_format' ) . ', ' . get_option( 'time_format' ) ) )
⋮----
<?php if ( $refund->get_reason() ) : ?>
<p class="description"><?php echo esc_html( $refund->get_reason() ); ?></p>
⋮----
<input type="hidden" class="order_refund_id" name="order_refund_id[]" value="<?php echo esc_attr( $refund->get_id() ); ?>" />
⋮----
<?php do_action( 'woocommerce_admin_order_item_values', null, $refund, $refund->get_id() ); ?>
⋮----
wc_price( '-' . $refund->get_amount(), array( 'currency' => $refund->get_currency() ) )
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-order-shipping.php">
<?php echo esc_html( $item->get_name() ? $item->get_name() : __( 'Shipping', 'woocommerce' ) ); ?>
⋮----
value="<?php echo esc_attr( $item->get_name() ); ?>"
⋮----
$is_active = $item->get_method_id() === $method->id;
⋮----
echo '<option value="' . esc_attr( $method->id ) . '" ' . selected( true, $is_active, false ) . '>' . esc_html( $method->get_method_title() ) . '</option>';
⋮----
if ( ! $found_method && $item->get_method_id() ) {
echo '<option value="' . esc_attr( $item->get_method_id() ) . '" selected="selected">' . esc_html__( 'Other', 'woocommerce' ) . '</option>';
⋮----
echo wp_kses_post( wc_price( $item->get_total(), array( 'currency' => $order->get_currency() ) ) );
$refunded = -1 * $order->get_total_refunded_for_item( $item_id, 'shipping' );
⋮----
echo wp_kses_post( '<small class="refunded">' . wc_price( $refunded, array( 'currency' => $order->get_currency() ) ) . '</small>' );
⋮----
<input type="text" name="shipping_cost[<?php echo esc_attr( $item_id ); ?>]" placeholder="<?php echo esc_attr( wc_format_localized_price( 0 ) ); ?>" value="<?php echo esc_attr( wc_format_localized_price( $item->get_total() ) ); ?>" class="line_total wc_input_price" />
⋮----
$tax_data = $item->get_taxes();
⋮----
$tax_item_id    = $tax_item->get_rate_id();
⋮----
echo wp_kses_post( ( '' !== $tax_item_total ) ? wc_price( $tax_item_total, array( 'currency' => $order->get_currency() ) ) : '&ndash;' );
$refunded = -1 * $order->get_tax_refunded_for_item( $item_id, $tax_item_id, 'shipping' );
⋮----
<?php if ( $order->is_editable() ) : ?>
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-product-attribute-inner.php">
use Automattic\WooCommerce\Internal\ProductAttributes\VisualAttributeTermMeta;
⋮----
<?php if ( $attribute->is_taxonomy() ) : ?>
<strong><?php echo esc_html( wc_attribute_label( $attribute->get_name() ) ); ?></strong>
<input type="hidden" name="attribute_names[<?php echo esc_attr( $i ); ?>]" value="<?php echo esc_attr( $attribute->get_name() ); ?>" />
⋮----
<input type="text" class="attribute_name" name="attribute_names[<?php echo esc_attr( $i ); ?>]" value="<?php echo esc_attr( $attribute->get_name() ); ?>" placeholder="<?php esc_attr_e( 'e.g. length or weight', 'woocommerce' ); ?>" />
⋮----
<input type="hidden" name="attribute_position[<?php echo esc_attr( $i ); ?>]" class="attribute_position" value="<?php echo esc_attr( $attribute->get_position() ); ?>" />
⋮----
if ( $attribute->is_taxonomy() && $attribute->get_taxonomy_object() ) {
$attribute_taxonomy = $attribute->get_taxonomy_object();
⋮----
data-taxonomy="<?php echo esc_attr( $attribute->get_taxonomy() ); ?>"
⋮----
$selected_terms = $attribute->get_terms();
⋮----
$term_visuals = VisualAttributeTermMeta::get_term_visuals( wp_list_pluck( $selected_terms, 'term_id' ) );
⋮----
$term_visuals[ $selected_term->term_id ] ?? VisualAttributeTermMeta::get_empty_visual()
⋮----
/**
								 * Filter the selected attribute term name.
								 *
								 * @since 3.4.0
								 * @param string  $name Name of selected term.
								 * @param array   $term The selected term object.
								 */
⋮----
<textarea name="attribute_values[<?php echo esc_attr( $i ); ?>]" cols="5" rows="5"><?php echo esc_textarea( wc_implode_text_attributes( $attribute->get_options() ) ); ?></textarea>
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-product-attribute.php">
<div data-taxonomy="<?php echo esc_attr( $attribute->get_taxonomy() ); ?>" class="woocommerce_attribute wc-metabox postbox closed <?php echo esc_attr( implode( ' ', $metabox_class ) ); ?>" rel="<?php echo esc_attr( $attribute->get_position() ); ?>">
⋮----
<strong class="attribute_name<?php echo esc_attr( $attribute->get_name() === '' ? ' placeholder' : '' ); ?>"><?php echo esc_html( $attribute->get_name() !== '' ? wc_attribute_label( $attribute->get_name() ) : __( 'New attribute', 'woocommerce' ) ); ?></strong>
<?php if ( $attribute->is_taxonomy() ) : ?>
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-product-data-advanced.php">
use Automattic\WooCommerce\Internal\ProductFeed\Integrations\POSCatalog\POSProductVisibilitySync;
⋮----
'value'       => $product_object->get_purchase_note( 'edit' ),
⋮----
'value'             => $product_object->get_menu_order( 'edit' ),
⋮----
'value'   => $product_object->get_reviews_allowed( 'edit' ) ? 'open' : 'closed',
⋮----
<?php $is_pos_supported = wc_get_container()->get( POSProductVisibilitySync::class )->is_product_supported( $product_object ); ?>
⋮----
$visible_in_pos = ! has_term( 'pos-hidden', 'pos_product_visibility', $product_object->get_id() );
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-product-data-attributes.php">
use Automattic\WooCommerce\Internal\ProductAttributes\VisualAttributeTermAdmin;
⋮----
$product_attributes = $product_object->get_attributes( 'edit' );
⋮----
if ( $attribute->is_taxonomy() ) {
⋮----
$metabox_class[] = $attribute->get_name();
⋮----
<?php VisualAttributeTermAdmin::render_add_attribute_term_modal_fields(); ?>
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-product-data-general.php">
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
⋮----
use Automattic\WooCommerce\Enums\ProductTaxStatus;
⋮----
'value'       => is_callable( array( $product_object, 'get_product_url' ) ) ? $product_object->get_product_url( 'edit' ) : '',
⋮----
'value'       => is_callable( array( $product_object, 'get_button_text' ) ) ? $product_object->get_button_text( 'edit' ) : '',
⋮----
$cogs_controller = wc_get_container()->get( CostOfGoodsSoldController::class );
$cogs_is_enabled = $cogs_controller->feature_is_enabled();
⋮----
'value'     => $product_object->get_regular_price( 'edit' ),
⋮----
'value'       => $product_object->get_sale_price( 'edit' ),
⋮----
$sale_price_dates_from_timestamp = $product_object->get_date_on_sale_from( 'edit' ) ? $product_object->get_date_on_sale_from( 'edit' )->getOffsetTimestamp() : false;
$sale_price_dates_to_timestamp   = $product_object->get_date_on_sale_to( 'edit' ) ? $product_object->get_date_on_sale_to( 'edit' )->getOffsetTimestamp() : false;
⋮----
// phpcs:disable WooCommerce.Commenting.CommentHooks.MissingSinceComment
⋮----
/**
			 * Hook to customize the regular expression that validates dates entered in the WooCommerce admin editors.
			 *
			 * @param string $pattern Default pattern to use.
			 */
⋮----
'value'       => $product_object->get_cogs_value() ?? '',
⋮----
'description' => $cogs_controller->get_general_cost_edit_field_tooltip( $is_variable ),
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-product-data-inventory.php">
'value'       => $product_object->get_sku( 'edit' ),
⋮----
'value'       => $product_object->get_global_unique_id( 'edit' ),
⋮----
'value'         => $product_object->get_manage_stock( 'edit' ) ? 'yes' : 'no',
⋮----
'value'             => wc_stock_amount( $product_object->get_stock_quantity( 'edit' ) ?? $default_stock_amount ),
⋮----
echo '<input type="hidden" name="_original_stock" value="' . esc_attr( wc_stock_amount( $product_object->get_stock_quantity( 'edit' ) ) ) . '" />';
⋮----
'value'   => $product_object->get_backorders( 'edit' ),
⋮----
'value'             => $product_object->get_low_stock_amount( 'edit' ),
⋮----
'value'         => $product_object->get_stock_status( 'edit' ),
⋮----
'value'         => $product_object->get_sold_individually( 'edit' ) ? 'yes' : 'no',
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-product-data-linked-products.php">
use Automattic\WooCommerce\Enums\ProductType;
⋮----
$product_ids = $product_object->is_type( ProductType::GROUPED ) ? $product_object->get_children( 'edit' ) : array();
⋮----
echo '<option value="' . esc_attr( $product_id ) . '"' . selected( true, true, false ) . '>' . esc_html( wp_strip_all_tags( $product->get_formatted_name() ) ) . '</option>';
⋮----
$product_ids = $product_object->get_upsell_ids( 'edit' );
⋮----
$product_ids = $product_object->get_cross_sell_ids( 'edit' );
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-product-data-panel.php">
<option value="<?php echo esc_attr( $value ); ?>" <?php echo selected( $product_object->get_type(), $value, false ); ?>><?php echo esc_html( $label ); ?></option>
⋮----
foreach ( self::get_product_type_options() as $key => $option ) :
⋮----
<?php foreach ( self::get_product_data_tabs() as $key => $tab ) : ?>
⋮----
self::output_tabs();
self::output_variations();
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-product-data-shipping.php">
use Automattic\WooCommerce\Utilities\I18nUtil;
⋮----
'value'       => $product_object->get_weight( 'edit' ),
⋮----
I18nUtil::get_weight_unit_label( get_option( 'woocommerce_weight_unit', 'kg' ) )
⋮----
esc_html( I18nUtil::get_dimensions_unit_label( get_option( 'woocommerce_dimension_unit' ) ) )
⋮----
<input id="product_length" placeholder="<?php esc_attr_e( 'Length', 'woocommerce' ); ?>" class="input-text wc_input_decimal" size="6" type="text" name="_length" value="<?php echo esc_attr( wc_format_localized_decimal( $product_object->get_length( 'edit' ) ) ); ?>" />
<input id="product_width" placeholder="<?php esc_attr_e( 'Width', 'woocommerce' ); ?>" class="input-text wc_input_decimal" size="6" type="text" name="_width" value="<?php echo esc_attr( wc_format_localized_decimal( $product_object->get_width( 'edit' ) ) ); ?>" />
<input id="product_height" placeholder="<?php esc_attr_e( 'Height', 'woocommerce' ); ?>" class="input-text wc_input_decimal last" size="6" type="text" name="_height" value="<?php echo esc_attr( wc_format_localized_decimal( $product_object->get_height( 'edit' ) ) ); ?>" />
⋮----
'selected'         => $product_object->get_shipping_class_id( 'edit' ),
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-product-data-variations.php">
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
⋮----
$selected_value = isset( $default_attributes[ sanitize_title( $attribute->get_name() ) ] ) ? $default_attributes[ sanitize_title( $attribute->get_name() ) ] : '';
⋮----
<select name="default_attribute_<?php echo esc_attr( sanitize_title( $attribute->get_name() ) ); ?>" data-current="<?php echo esc_attr( $selected_value ); ?>">
<?php /* translators: WooCommerce attribute label */ ?>
<option value=""><?php echo esc_html( sprintf( __( 'No default %s&hellip;', 'woocommerce' ), wc_attribute_label( $attribute->get_name() ) ) ); ?></option>
<?php if ( $attribute->is_taxonomy() ) : ?>
<?php foreach ( (array) $attribute->get_terms() as $option ) : ?>
⋮----
<option <?php selected( $selected_value, $option->slug ); ?> value="<?php echo esc_attr( $option->slug ); ?>"><?php echo esc_html( apply_filters( 'woocommerce_variation_option_name', $option->name, $option, $attribute->get_name(), $product_object ) ); ?></option>
⋮----
<?php foreach ( $attribute->get_options() as $option ) : ?>
⋮----
<option <?php selected( $selected_value, $option ); ?> value="<?php echo esc_attr( $option ); ?>"><?php echo esc_html( apply_filters( 'woocommerce_variation_option_name', $option, null, $attribute->get_name(), $product_object ) ); ?></option>
⋮----
<?php if ( wc_get_container()->get( CostOfGoodsSoldController::class )->feature_is_enabled() ) : ?>
⋮----
<option value="<?php echo $i; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $i is a bounded integer pagination index. ?>"><?php echo $i; ?></option>
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-product-download.php">

</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-product-variation-download.php">

</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/views/html-variation-admin.php">
use Automattic\WooCommerce\Utilities\I18nUtil;
⋮----
$attribute_values = $variation_object->get_attributes( 'edit' );
⋮----
foreach ( $product_object->get_attributes( 'edit' ) as $attribute ) {
if ( ! $attribute->get_variation() ) {
⋮----
$selected_value = isset( $attribute_values[ sanitize_title( $attribute->get_name() ) ] ) ? $attribute_values[ sanitize_title( $attribute->get_name() ) ] : '';
⋮----
<select name="attribute_<?php echo esc_attr( sanitize_title( $attribute->get_name() ) . "[{$loop}]" ); ?>">
⋮----
/* translators: %s: attribute label */
printf( esc_html__( 'Any %s&hellip;', 'woocommerce' ), wc_attribute_label( $attribute->get_name() ) );
⋮----
<?php if ( $attribute->is_taxonomy() ) : ?>
<?php foreach ( (array) $attribute->get_terms() as $option ) : ?>
⋮----
<option <?php selected( $selected_value, $option->slug ); ?> value="<?php echo esc_attr( $option->slug ); ?>"><?php echo esc_html( apply_filters( 'woocommerce_variation_option_name', $option->name, $option, $attribute->get_name(), $product_object ) ); ?></option>
⋮----
<?php foreach ( $attribute->get_options() as $option ) : ?>
⋮----
<option <?php selected( $selected_value, $option ); ?> value="<?php echo esc_attr( $option ); ?>"><?php echo esc_html( apply_filters( 'woocommerce_variation_option_name', $option, null, $attribute->get_name(), $product_object ) ); ?></option>
⋮----
<input type="hidden" class="variation_menu_order" name="variation_menu_order[<?php echo esc_attr( $loop ); ?>]" value="<?php echo esc_attr( $variation_object->get_menu_order( 'edit' ) ); ?>" />
⋮----
<a href="#" class="upload_image_button tips <?php echo $variation_object->get_image_id( 'edit' ) ? 'remove' : ''; ?>" data-tip="<?php echo $variation_object->get_image_id( 'edit' ) ? esc_attr__( 'Remove this image', 'woocommerce' ) : esc_attr__( 'Upload an image', 'woocommerce' ); ?>" rel="<?php echo esc_attr( $variation_id ); ?>">
<img src="<?php echo $variation_object->get_image_id( 'edit' ) ? esc_url( wp_get_attachment_thumb_url( (int) $variation_object->get_image_id( 'edit' ) ) ) : esc_url( wc_placeholder_img_src() ); ?>" /><input type="hidden" name="upload_image_id[<?php echo esc_attr( $loop ); ?>]" class="upload_image_id" value="<?php echo esc_attr( $variation_object->get_image_id( 'edit' ) ); ?>" />
⋮----
'value'         => $variation_object->get_sku( 'edit' ),
'placeholder'   => $variation_object->get_sku(),
... (66 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-coupon-data.php">
class WC_Meta_Box_Coupon_Data {
⋮----
public static function output( $post ) {
⋮----
'value'   => $coupon->get_discount_type( 'edit' ),
⋮----
'data_type'   => 'percent' === $coupon->get_discount_type( 'edit' ) ? 'decimal' : 'price',
⋮----
'value'       => $coupon->get_amount( 'edit' ),
⋮----
'value'       => wc_bool_to_string( $coupon->get_free_shipping( 'edit' ) ),
⋮----
$expiry_date = $coupon->get_date_expires( 'edit' ) ? $coupon->get_date_expires( 'edit' )->date( 'Y-m-d' ) : '';
⋮----
do_action( 'woocommerce_coupon_options', $coupon->get_id(), $coupon );
⋮----
'value'       => $coupon->get_minimum_amount( 'edit' ),
⋮----
'value'       => $coupon->get_maximum_amount( 'edit' ),
⋮----
'value'       => wc_bool_to_string( $coupon->get_individual_use( 'edit' ) ),
⋮----
'value'       => wc_bool_to_string( $coupon->get_exclude_sale_items( 'edit' ) ),
⋮----
$product_ids = $coupon->get_product_ids( 'edit' );
⋮----
echo '<option value="' . esc_attr( $product_id ) . '"' . selected( true, true, false ) . '>' . esc_html( wp_strip_all_tags( $product->get_formatted_name() ) ) . '</option>';
⋮----
$product_ids = $coupon->get_excluded_product_ids( 'edit' );
⋮----
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-order-actions.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\Admin\Orders\PageController;
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class WC_Meta_Box_Order_Actions {
⋮----
public static function output( $post ) {
⋮----
OrderUtil::init_theorder_object( $post );
⋮----
$order_id      = $order->get_id();
$order_actions = self::get_available_order_actions_for_order( $order );
⋮----
<a class="submitdelete deletion" href="<?php echo esc_url( self::get_trash_or_delete_order_link( $order_id ) ); ?>"><?php echo esc_html( $delete_text ); ?></a>
⋮----
<button type="submit" class="button save_order button-primary" name="save" value="<?php echo OrderStatus::AUTO_DRAFT === $order->get_status() ? esc_attr__( 'Create', 'woocommerce' ) : esc_attr__( 'Update', 'woocommerce' ); ?>"><?php echo OrderStatus::AUTO_DRAFT === $order->get_status() ? esc_html__( 'Create', 'woocommerce' ) : esc_html__( 'Update', 'woocommerce' ); ?></button>
⋮----
private static function get_trash_or_delete_order_link( int $order_id ): string {
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
$order_type      = wc_get_order( $order_id )->get_type();
$order_list_url  = wc_get_container()->get( PageController::class )->get_base_page_url( $order_type );
⋮----
public static function save( $post_id, $post ) {
⋮----
WC()->payment_gateways();
WC()->shipping();
WC()->mailer()->customer_invoice( $order );
⋮----
$order->add_order_note( __( 'Order details manually sent to customer.', 'woocommerce' ), false, true, array( 'note_group' => OrderNoteGroup::EMAIL_NOTIFICATION ) );
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-order-data.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\Utilities\Users;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class WC_Meta_Box_Order_Data {
⋮----
protected static $billing_fields = array();
⋮----
protected static $shipping_fields = array();
⋮----
protected static function get_billing_fields( $order = false, $context = 'edit' ) {
⋮----
'options' => array( '' => __( 'Select a country / region&hellip;', 'woocommerce' ) ) + WC()->countries->get_countries(),
⋮----
protected static function get_shipping_fields( $order = false, $context = 'edit' ) {
⋮----
public static function init_address_fields() {
self::$billing_fields  = self::get_billing_fields();
self::$shipping_fields = self::get_shipping_fields();
⋮----
private static function order_has_no_shipping( $order ) {
return 0 === count( $order->get_shipping_methods() );
⋮----
private static function order_has_only_virtual_products( $order ) {
$items = $order->get_items();
⋮----
$product = $item->get_product();
⋮----
if ( ! $product instanceof WC_Product || $product->needs_shipping() ) {
⋮----
... (118 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-order-downloads.php">
class WC_Meta_Box_Order_Downloads {
⋮----
public static function output( $post ) {
⋮----
$order_id = $post->get_id();
⋮----
$data_store           = WC_Data_Store::load( 'customer-download' );
⋮----
$download_permissions = $data_store->get_downloads(
⋮----
if ( ! $product || $product->get_id() !== $download->get_product_id() ) {
$product      = wc_get_product( $download->get_product_id() );
⋮----
if ( ! $product || ! $product->exists() || ! $product->has_file( $download->get_download_id() ) ) {
⋮----
$file       = $product->get_file( $download->get_download_id() );
⋮----
public static function save( $post_id, $post ) {
⋮----
$download->set_downloads_remaining( wc_clean( $downloads_remaining[ $i ] ) );
$download->set_access_expires( array_key_exists( $i, $access_expires ) && '' !== $access_expires[ $i ] ? strtotime( $access_expires[ $i ] ) : '' );
$download->save();
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-order-items.php">
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class WC_Meta_Box_Order_Items {
⋮----
public static function output( $post ) {
⋮----
OrderUtil::init_theorder_object( $post );
⋮----
public static function save( $post_id ) {
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-order-notes.php">
class WC_Meta_Box_Order_Notes {
⋮----
public static function output( $post ) {
⋮----
$order_id = $post->get_id();
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-product-categories.php">
class WC_Meta_Box_Product_Categories {
⋮----
public static function output( $post, $box ) {
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-product-data.php">
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
use Automattic\WooCommerce\Internal\ProductFeed\Integrations\POSCatalog\POSProductVisibilitySync;
⋮----
class WC_Meta_Box_Product_Data {
⋮----
public static function output( $post ) {
⋮----
private static function output_tabs() {
⋮----
private static function get_product_type_options() {
⋮----
private static function get_product_data_tabs() {
⋮----
private static function product_data_tabs_sort( $a, $b ) {
⋮----
private static function filter_variation_attributes( $attribute ) {
return true === $attribute->get_variation();
⋮----
private static function filter_non_variation_attributes( $attribute ) {
return false === $attribute->get_variation();
⋮----
public static function output_variations() {
⋮----
$variation_attributes   = array_filter( $product_object->get_attributes(), array( __CLASS__, 'filter_variation_attributes' ) );
$default_attributes     = $product_object->get_default_attributes();
$variations_count       = absint( apply_filters( 'woocommerce_admin_meta_boxes_variations_count', $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(ID) FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'product_variation' AND post_status IN ('publish', 'private')", $post->ID ) ), $post->ID ) );
⋮----
... (121 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-product-images.php">
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\ProductGallery\ProductMediaGallery;
⋮----
class WC_Meta_Box_Product_Images {
⋮----
public static function output( $post ) {
⋮----
$product_gallery_videos_enabled = ProductMediaGallery::is_feature_enabled();
⋮----
? ProductMediaGallery::get_product_media_gallery_items(
⋮----
: ProductMediaGallery::get_product_image_media_items( $product_object, false, 'edit' );
⋮----
ProductMediaGallery::prime_attachment_caches( $product_media_gallery, true );
⋮----
? self::get_video_preview_html( $attachment_id )
⋮----
value="<?php echo esc_attr( self::get_media_gallery_json( $updated_media_gallery ) ); ?>"
⋮----
public static function save( $post_id, $post ) {
$product_type = empty( $_POST['product-type'] ) ? WC_Product_Factory::get_product_type( $post_id ) : sanitize_title( wp_unslash( $_POST['product-type'] ) );
$classname    = WC_Product_Factory::get_product_classname( $post_id, $product_type ? $product_type : ProductType::SIMPLE );
$product      = new $classname( $post_id );
⋮----
$videos_enabled = ProductMediaGallery::is_feature_enabled();
⋮----
$product->set_gallery_image_ids( $attachment_ids );
$product->save();
⋮----
$media_gallery        = ProductMediaGallery::normalize_media_gallery_items(
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-product-reviews.php">
class WC_Meta_Box_Product_Reviews {
⋮----
public static function output( $comment ) {
⋮----
public static function save( $data ) {
</file>

<file path="plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-product-short-description.php">
class WC_Meta_Box_Product_Short_Description {
⋮----
public static function output( $post ) {
</file>

<file path="plugins/woocommerce/includes/admin/notes/class-wc-notes-refund-returns.php">
use Automattic\WooCommerce\Admin\Notes\Note;
⋮----
class WC_Notes_Refund_Returns {
⋮----
public static function init() {
⋮----
public static function on_newly_installed() {
⋮----
self::possibly_add_note( $page_id );
⋮----
public static function possibly_add_note( $page_id ) {
if ( ! WC()->is_wc_admin_active() ) {
⋮----
$data_store = \WC_Data_Store::load( 'admin-note' );
⋮----
$note_id = $data_store->get_notes_with_name( self::NOTE_NAME );
⋮----
if ( false !== $note || $note::E_WC_ADMIN_NOTE_ACTIONED === $note->get_status() ) {
⋮----
$note = self::get_note( $page_id );
$note->save();
⋮----
public static function get_note( $page_id ) {
⋮----
$note->set_title( __( 'Setup a Refund and Returns Policy page to boost your store\'s credibility.', 'woocommerce' ) );
$note->set_content( __( 'We have created a sample draft Refund and Returns Policy page for you. Please have a look and update it to fit your store.', 'woocommerce' ) );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_content_data( (object) array() );
$note->set_source( 'woocommerce-core' );
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/notes/class-wc-notes-run-db-update.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Admin\Notes\Note;
⋮----
class WC_Notes_Run_Db_Update {
⋮----
public static function maybe_update_notice( $note ) {
if ( ! $note instanceof Note || $note->get_name() !== self::NOTE_NAME ) {
⋮----
if ( ! in_array( 'update', \WC_Admin_Notices::get_notices(), true ) ) {
$note->set_status( Note::E_WC_ADMIN_NOTE_ACTIONED );
$note->save();
⋮----
$needs_db_update = \WC_Install::needs_db_update();
⋮----
if ( Note::E_WC_ADMIN_NOTE_ACTIONED !== $note->get_status() ) {
self::update_done_notice( $note );
⋮----
$next_scheduled_date = WC()->queue()->get_next( 'woocommerce_run_update_callback', null, 'woocommerce-db-updates' );
⋮----
self::update_in_progress_notice( $note );
⋮----
self::update_needed_notice( $note );
⋮----
private static function get_current_notice() {
⋮----
$data_store = \WC_Data_Store::load( 'admin-note' );
⋮----
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
⋮----
$data_store->delete( $note );
... (57 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/plugin-updates/views/html-notice-untested-extensions-inline.php">

</file>

<file path="plugins/woocommerce/includes/admin/plugin-updates/views/html-notice-untested-extensions-modal.php">

</file>

<file path="plugins/woocommerce/includes/admin/plugin-updates/class-wc-plugin-updates.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Plugin_Updates {
⋮----
protected $new_version = '';
⋮----
/**
	 * Array of plugins lacking testing with the major version.
	 *
	 * @var array
	 */
protected $major_untested_plugins = array();
⋮----
/**
	 * Common JS for initializing and managing thickbox-based modals.
	 */
protected function generic_modal_js() {
⋮----
protected function get_extensions_inline_warning_major() {
⋮----
protected function get_extensions_modal_warning() {
⋮----
public function get_untested_plugins( $new_version, $release ) {
⋮----
$extensions        = array_merge( $this->get_plugins_with_header( self::VERSION_TESTED_HEADER ), $this->get_plugins_for_woocommerce() );
⋮----
protected function get_plugins_with_header( $header ) {
⋮----
protected function get_plugins_for_woocommerce() {
</file>

<file path="plugins/woocommerce/includes/admin/plugin-updates/class-wc-plugins-screen-updates.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Plugins_Screen_Updates extends WC_Plugin_Updates {
⋮----
protected $upgrade_notice = '';
⋮----
/**
	 * Constructor.
	 */
public function __construct() {
⋮----
public function in_plugin_update_message( $args, $response ) {
$version_type = Constants::get_constant( 'WC_SSR_PLUGIN_UPDATE_RELEASE_VERSION_TYPE' );
⋮----
$this->upgrade_notice         = $this->get_upgrade_notice( $response->new_version );
$this->major_untested_plugins = $this->get_untested_plugins( $response->new_version, $version_type );
⋮----
$current_version_parts = explode( '.', Constants::get_constant( 'WC_VERSION' ) );
⋮----
$this->upgrade_notice .= $this->get_extensions_inline_warning_major();
⋮----
$this->upgrade_notice .= $this->get_extensions_modal_warning();
⋮----
echo apply_filters( 'woocommerce_in_plugin_update_message', $this->upgrade_notice ? '</p>' . wp_kses_post( $this->upgrade_notice ) . '<p class="dummy">' : '' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- The base value is run through wp_kses_post() and the filter returns extension-controlled markup by design.
⋮----
/**
	 * Get the upgrade notice from WordPress.org.
	 *
	 * @param  string $version WooCommerce new version.
	 * @return string
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/plugin-updates/class-wc-updates-screen-updates.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Updates_Screen_Updates extends WC_Plugin_Updates {
⋮----
public function __construct() {
⋮----
public function update_screen_modal() {
⋮----
$version_type = Constants::get_constant( 'WC_SSR_PLUGIN_UPDATE_RELEASE_VERSION_TYPE' );
⋮----
$this->major_untested_plugins = $this->get_untested_plugins( $this->new_version, $version_type );
⋮----
echo $this->get_extensions_modal_warning();
$this->update_screen_modal_js();
⋮----
protected function update_screen_modal_js() {
⋮----
$this->generic_modal_js();
</file>

<file path="plugins/woocommerce/includes/admin/settings/views/class-wc-settings-rest-api.php">

</file>

<file path="plugins/woocommerce/includes/admin/settings/views/html-admin-page-shipping-classes.php">

</file>

<file path="plugins/woocommerce/includes/admin/settings/views/html-admin-page-shipping-providers.php">

</file>

<file path="plugins/woocommerce/includes/admin/settings/views/html-admin-page-shipping-zone-methods.php">
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Blocks\Shipping\ShippingController;
use Automattic\WooCommerce\StoreApi\Utilities\LocalPickupUtils;
⋮----
<?php wc_back_header( $zone->get_zone_name() ? $zone->get_zone_name() : __( 'Add zone', 'woocommerce' ), __( 'Return to shipping', 'woocommerce' ), admin_url( 'admin.php?page=wc-settings&tab=shipping' ) ); ?>
⋮----
<?php if ( 0 !== $zone->get_id() ) : ?>
⋮----
<input type="text" data-attribute="zone_name" name="zone_name" id="zone_name" value="<?php echo esc_attr( $zone->get_zone_name( 'edit' ) ); ?>" placeholder="<?php esc_attr_e( 'Zone name', 'woocommerce' ); ?>">
⋮----
<article class="wc-modal-shipping-method-settings" data-id="{{{ data.instance_id }}}" data-status="{{{ data.status }}}"  data-shipping-classes-count="<?php echo count( WC()->shipping()->get_shipping_classes() ); ?>">
⋮----
$methods = WC()->shipping()->load_shipping_methods();
⋮----
if ( CartCheckoutUtils::is_checkout_block_default() && ! ShippingController::is_legacy_local_pickup_active() && 'local_pickup' === $method->id ) {
⋮----
if ( ! $method->supports( 'shipping-zones' ) ) {
⋮----
echo '<div class="wc-shipping-zone-method-input"><input type="radio" value="' . esc_attr( $method->id ) . '" id="' . esc_attr( $method->id ) . '" name="add_method_id"/><label for="' . esc_attr( $method->id ) . '">' . esc_html( $method->get_method_title() ) . '<span class="dashicons dashicons-yes"></span></label></div>';
⋮----
echo '<div id=' . esc_attr( $method->id ) . '-description class="wc-shipping-zone-method-input-help-text"><span>' . wp_kses_post( wpautop( $method->get_method_description() ) ) . '</span></div>';
⋮----
if ( CartCheckoutUtils::is_checkout_block_default() ) {
⋮----
if ( ShippingController::is_legacy_local_pickup_active() ) {
⋮----
if ( LocalPickupUtils::is_local_pickup_enabled() ) {
</file>

<file path="plugins/woocommerce/includes/admin/settings/views/html-admin-page-shipping-zones-instance.php">
<a href="<?php echo admin_url( 'admin.php?page=wc-settings&tab=shipping&zone_id=' . absint( $zone->get_id() ) ); ?>"><?php echo esc_html( $zone->get_zone_name() ); ?></a> &gt;
<?php echo esc_html( $shipping_method->get_method_title() ); ?>
⋮----
<?php $shipping_method->admin_options(); ?>
</file>

<file path="plugins/woocommerce/includes/admin/settings/views/html-admin-page-shipping-zones.php">
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
⋮----
if ( CartCheckoutUtils::is_checkout_block_default() ) {
⋮----
$methods   = $worldwide->get_shipping_methods();
⋮----
echo '<li class="wc-shipping-zone-method ' . esc_attr( $class_name ) . '" data-id="' . esc_attr( $method->instance_id ) . '">' . esc_html( $method->get_title() ) . '</li>';
⋮----
foreach ( WC()->shipping()->load_shipping_methods() as $method ) {
if ( ! $method->supports( 'shipping-zones' ) ) {
⋮----
echo '<option data-description="' . esc_attr( wp_kses_post( wpautop( $method->get_method_description() ) ) ) . '" value="' . esc_attr( $method->id ) . '">' . esc_html( $method->get_method_title() ) . '</li>';
</file>

<file path="plugins/woocommerce/includes/admin/settings/views/html-keys-edit.php">

</file>

<file path="plugins/woocommerce/includes/admin/settings/views/html-settings-tax.php">

</file>

<file path="plugins/woocommerce/includes/admin/settings/views/html-webhooks-edit.php">
<input type="hidden" name="webhook_id" value="<?php echo esc_attr( $webhook->get_id() ); ?>" />
⋮----
echo wc_help_tip( sprintf( __( 'Friendly name for identifying this webhook, defaults to Webhook created on %s.', 'woocommerce' ), (new DateTime('now'))->format( _x( 'M d, Y @ h:i A', 'Webhook created on date parsed by DateTime::format', 'woocommerce' ) ) ) );
⋮----
<input name="webhook_name" id="webhook_name" type="text" class="input-text regular-input" value="<?php echo esc_attr( $webhook->get_name() ); ?>" />
⋮----
$current_status = $webhook->get_status();
⋮----
$topic_data = WC_Admin_Webhooks::get_topic_data( $webhook );
⋮----
<input name="webhook_delivery_url" id="webhook_delivery_url" type="text" class="input-text regular-input" value="<?php echo esc_attr( $webhook->get_delivery_url() ); ?>" />
⋮----
<input name="webhook_secret" id="webhook_secret" type="text" class="input-text regular-input" value="<?php echo esc_attr( $webhook->get_secret() ); ?>" />
⋮----
<option value="<?php echo esc_attr( $version ); ?>" <?php selected( $version, $webhook->get_api_version(), true ); ?>>
⋮----
<?php if ( WC()->legacy_rest_api_is_available() ) : ?>
<option value="legacy_v3" <?php selected( 'legacy_v3', $webhook->get_api_version(), true ); ?>>
⋮----
<?php elseif ( ! in_array( $webhook->get_api_version(), wc_get_webhook_rest_api_versions(), true ) ) : ?>
<option value="<?php echo esc_attr( $webhook->get_api_version() ); ?>" selected="selected">
⋮----
echo esc_html( sprintf( __( '%s (unsupported)', 'woocommerce' ), $webhook->get_api_version() ) );
⋮----
<?php if ( $webhook->get_date_created() && '0000-00-00 00:00:00' !== $webhook->get_date_created()->date( 'Y-m-d H:i:s' ) ) : ?>
<?php if ( is_null( $webhook->get_date_modified() ) ) : ?>
⋮----
<?php echo esc_html( date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $webhook->get_date_created()->date( 'Y-m-d H:i:s' ) ) ) ); ?>
⋮----
<?php echo esc_html( date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $webhook->get_date_modified()->date( 'Y-m-d H:i:s' ) ) ) ); ?>
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/settings/views/settings-tax.php">
use Automattic\WooCommerce\Enums\TaxBasedOn;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
⋮----
'value'     => implode( "\n", WC_Tax::get_tax_classes() ),
</file>

<file path="plugins/woocommerce/includes/admin/settings/class-wc-settings-accounts.php">
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Admin\Features\Features;
⋮----
class WC_Settings_Accounts extends WC_Settings_Page {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public $icon = 'people';
⋮----
protected function get_settings_for_default_section() {
⋮----
if ( CartCheckoutUtils::is_checkout_block_default() ) {
⋮----
public function output() {
parent::output();
</file>

<file path="plugins/woocommerce/includes/admin/settings/class-wc-settings-advanced.php">
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Settings_Advanced extends WC_Settings_Page {
⋮----
public function __construct() {
⋮----
parent::__construct();
$this->notices();
⋮----
public $icon = 'more';
⋮----
protected function get_own_sections() {
⋮----
$features_controller = wc_get_container()->get( FeaturesController::class );
if ( $features_controller->feature_is_enabled( 'rest_api_caching' ) ) {
⋮----
if ( FeaturesUtil::feature_is_enabled( 'blueprint' ) ) {
⋮----
protected function get_settings_for_default_section() {
⋮----
protected function get_settings_for_woocommerce_com_section() {
⋮----
protected function get_settings_for_legacy_api_section() {
⋮----
protected function get_settings_for_rest_api_caching_section() {
⋮----
protected function get_settings_for_blueprint_section() {
⋮----
public function form_method( $method ) {
... (26 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/settings/class-wc-settings-checkout.php">

</file>

<file path="plugins/woocommerce/includes/admin/settings/class-wc-settings-emails.php">
use Automattic\WooCommerce\Internal\Admin\EmailPreview\EmailPreview;
use Automattic\WooCommerce\Internal\Email\EmailColors;
use Automattic\WooCommerce\Internal\Email\EmailFont;
use Automattic\WooCommerce\Internal\Email\EmailStyleSync;
use Automattic\WooCommerce\Internal\EmailEditor\EmailTemplates\WooEmailTemplate;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsManager;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmails;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateDivergenceDetector;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateSyncRegistry;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Settings_Emails extends WC_Settings_Page {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public $icon = 'atSymbol';
⋮----
protected function get_own_sections() {
⋮----
protected function get_settings_for_default_section() {
⋮----
$block_email_editor_enabled = FeaturesUtil::feature_is_enabled( 'block_email_editor' );
$email_improvements_enabled = $this->get_email_improvements_enabled();
⋮----
$default_colors = EmailColors::get_default_colors( $email_improvements_enabled );
⋮----
public function get_custom_fonts() {
... (125 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/settings/class-wc-settings-general.php">
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Enums\DefaultCustomerAddress;
use Automattic\WooCommerce\Internal\AddressProvider\AddressProviderController;
⋮----
class WC_Settings_General extends WC_Settings_Page {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public $icon = 'cog';
⋮----
protected function get_settings_for_default_section() {
⋮----
$address_provider_class         = wc_get_container()->get( AddressProviderController::class );
$address_autocomplete_providers = $address_provider_class->get_providers();
⋮----
wc_get_logger()->log( 'error', 'Error getting address provider class: ' . $e->getMessage() );
⋮----
public function color_picker( $name, $id, $value, $desc = '' ) {
⋮----
/**
	 * Output settings with additional JS to hide preferred provider if autocomplete is disabled.
	 *
	 * @return void
	 */
public function output() {
parent::output();
</file>

<file path="plugins/woocommerce/includes/admin/settings/class-wc-settings-integrations.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Settings_Integrations extends WC_Settings_Page {
⋮----
public function __construct() {
⋮----
if ( isset( WC()->integrations ) && WC()->integrations->get_integrations() ) {
parent::__construct();
⋮----
public $icon = 'plugins';
⋮----
protected function get_own_sections() {
⋮----
if ( ! $this->wc_is_installing() ) {
$integrations = $this->get_integrations();
⋮----
protected function wc_is_installing() {
return Constants::is_defined( 'WC_INSTALLING' );
⋮----
protected function get_integrations() {
return WC()->integrations->get_integrations();
⋮----
public function output() {
⋮----
$integrations[ $current_section ]->admin_options();
</file>

<file path="plugins/woocommerce/includes/admin/settings/class-wc-settings-page.php">
use Automattic\WooCommerce\Admin\Settings\SettingsSectionRegistry;
use Automattic\WooCommerce\Admin\Settings\SettingsUIPageInterface;
use Automattic\WooCommerce\Internal\Admin\Settings\SettingsUIRequestContext;
⋮----
abstract class WC_Settings_Page {
⋮----
protected $id = '';
⋮----
/**
		 * Setting page icon.
		 *
		 * @var string
		 */
public $icon = 'settings';
⋮----
protected $label = '';
⋮----
/**
		 * Constructor.
		 */
public function __construct() {
⋮----
public function get_id() {
⋮----
public function get_label() {
⋮----
public function get_settings_ui_page(): ?SettingsUIPageInterface {
⋮----
public function add_settings_ui_body_class( $classes ) {
⋮----
... (110 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/settings/class-wc-settings-payment-gateways.php">
use Automattic\WooCommerce\Admin\Settings\SettingsSectionRegistry;
use Automattic\WooCommerce\Internal\Admin\Loader;
⋮----
class WC_Settings_Payment_Gateways extends WC_Settings_Page {
⋮----
public $icon = 'payment';
⋮----
private ?array $reactified_sections_memo = null;
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function should_render_react_section( $section ): bool {
return in_array( $this->standardize_section_name( $section ), $this->get_reactified_sections(), true );
⋮----
public function add_body_classes( $classes ) {
⋮----
if ( ! $this->should_render_react_section( $current_section ) ) {
⋮----
$classes .= ' woocommerce_page_wc-settings-checkout-section-' . esc_attr( $this->standardize_section_name( $current_section ) ) . '_legacy';
⋮----
public function output() {
⋮----
if ( is_string( $current_section ) && $this->is_registered_settings_section( $current_section ) ) {
parent::output();
⋮----
if ( is_string( $current_section ) && $this->should_render_react_section( $current_section ) ) {
$this->render_react_section( $this->standardize_section_name( $current_section ) );
⋮----
... (80 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/settings/class-wc-settings-point-of-sale.php">
use Automattic\WooCommerce\Internal\Settings\PointOfSaleDefaultSettings;
⋮----
class WC_Settings_Point_Of_Sale extends WC_Settings_Page {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public $icon = 'store';
⋮----
protected function get_settings_for_default_section() {
⋮----
'default'           => PointOfSaleDefaultSettings::get_default_store_name(),
⋮----
'default'  => PointOfSaleDefaultSettings::get_default_store_address(),
⋮----
'default' => PointOfSaleDefaultSettings::get_default_store_email(),
</file>

<file path="plugins/woocommerce/includes/admin/settings/class-wc-settings-products.php">
use Automattic\WooCommerce\Admin\Settings\SettingsUIPageInterface;
use Automattic\WooCommerce\Internal\Admin\Settings\SettingsUIPages\ProductsSettingsPageAdapter;
use Automattic\WooCommerce\Utilities\I18nUtil;
⋮----
class WC_Settings_Products extends WC_Settings_Page {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public $icon = 'box';
⋮----
public function get_settings_ui_page(): ?SettingsUIPageInterface {
⋮----
protected function get_own_sections() {
⋮----
protected function get_settings_for_default_section() {
$locale_info            = include WC()->plugin_path() . '/i18n/locale-info.php';
⋮----
'kg'  => I18nUtil::get_weight_unit_label( 'kg' ),
'g'   => I18nUtil::get_weight_unit_label( 'g' ),
'lbs' => I18nUtil::get_weight_unit_label( 'lbs' ),
'oz'  => I18nUtil::get_weight_unit_label( 'oz' ),
⋮----
'm'  => I18nUtil::get_dimensions_unit_label( 'm' ),
'cm' => I18nUtil::get_dimensions_unit_label( 'cm' ),
'mm' => I18nUtil::get_dimensions_unit_label( 'mm' ),
'in' => I18nUtil::get_dimensions_unit_label( 'in' ),
'yd' => I18nUtil::get_dimensions_unit_label( 'yd' ),
⋮----
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/settings/class-wc-settings-shipping.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Settings_Shipping extends WC_Settings_Page {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public $icon = 'shipping';
⋮----
public function add_settings_page( $pages ) {
return wc_shipping_enabled() ? parent::add_settings_page( $pages ) : $pages;
⋮----
protected function get_own_sections() {
⋮----
if ( FeaturesUtil::feature_is_enabled( 'fulfillments' ) ) {
⋮----
if ( ! $this->wc_is_installing() ) {
⋮----
$shipping_methods = $this->get_shipping_methods();
⋮----
if ( ! $method->has_settings() ) {
⋮----
protected function wc_is_installing() {
return Constants::is_defined( 'WC_INSTALLING' );
⋮----
protected function get_shipping_methods() {
return WC()->shipping()->get_shipping_methods();
... (79 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/settings/class-wc-settings-site-visibility.php">
class WC_Settings_Site_Visibility extends WC_Settings_Page {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
protected function get_settings_for_default_section() {
</file>

<file path="plugins/woocommerce/includes/admin/settings/class-wc-settings-tax.php">
class WC_Settings_Tax extends WC_Settings_Page {
⋮----
public function __construct() {
⋮----
public $icon = 'percent';
⋮----
public function conflict_error() {
⋮----
public function add_settings_page( $pages ) {
⋮----
return parent::add_settings_page( $pages );
⋮----
protected function get_own_sections() {
⋮----
$tax_classes = WC_Tax::get_tax_classes();
⋮----
public function get_settings_for_default_section() {
⋮----
public function output() {
⋮----
$tax_classes = WC_Tax::get_tax_class_slugs();
⋮----
$this->output_tax_rates();
⋮----
parent::output();
⋮----
public function save() {
⋮----
$this->save_settings_for_current_section();
⋮----
... (73 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/views/html-admin-dashboard-setup.php">

</file>

<file path="plugins/woocommerce/includes/admin/views/html-admin-page-addons-category-nav.php">

</file>

<file path="plugins/woocommerce/includes/admin/views/html-admin-page-product-export.php">
foreach ( $exporter->get_default_column_names() as $column_id => $column_name ) {
⋮----
foreach ( WC_Admin_Exporters::get_product_types() as $value => $label ) {
</file>

<file path="plugins/woocommerce/includes/admin/views/html-admin-page-reports.php">
<?php if ( WC()->is_wc_admin_active() ) { ?>
</file>

<file path="plugins/woocommerce/includes/admin/views/html-admin-page-status-logs-db.php">
<?php $log_table_list->search_box( __( 'Search logs', 'woocommerce' ), 'log' ); ?>
<?php $log_table_list->display(); ?>
</file>

<file path="plugins/woocommerce/includes/admin/views/html-admin-page-status-logs.php">
use Automattic\WooCommerce\Utilities\LoggingUtil;
⋮----
$log_directory = LoggingUtil::get_log_directory();
</file>

<file path="plugins/woocommerce/includes/admin/views/html-admin-page-status-report.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Utilities\RestApiUtil;
⋮----
$report             = wc_get_container()->get( RestApiUtil::class )->get_endpoint_data( '/wc/v3/system_status' );
⋮----
$untested_plugins   = $plugin_updates->get_untested_plugins( WC()->version, Constants::get_constant( 'WC_SSR_PLUGIN_UPDATE_RELEASE_VERSION_TYPE' ) );
⋮----
// Check if the plugin file exists before trying to access it.
⋮----
$wc_version  = $plugin_data['Version'] ?? ''; // Use null coalescing operator to handle undefined index.
⋮----
$version = ActionScheduler_Versions::instance()->latest_version();
$path    = ActionScheduler::plugin_path( '' ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
⋮----
self::output_tables_info();
⋮----
<?php self::output_plugins_info( $active_plugins, $untested_plugins ); ?>
⋮----
<?php self::output_plugins_info( $inactive_plugins, $untested_plugins ); ?>
⋮----
if ( CartCheckoutUtils::is_overridden_by_custom_template_content( $_page['block'] ) ) {
</file>

<file path="plugins/woocommerce/includes/admin/views/html-admin-page-status-tools.php">
use Automattic\WooCommerce\Utilities\ArrayUtil;
⋮----
if ( ArrayUtil::is_truthy( $tool, 'requires_refresh' ) ) {
⋮----
if ( ! is_null( ArrayUtil::get_value_or_default( $tool, 'selector' ) ) ) {
⋮----
<input <?php disabled( ArrayUtil::is_truthy( $tool, 'disabled' ) ); ?> type="submit" form="<?php echo esc_attr( 'form_' . $action_name ); ?>" class="button button-large" value="<?php echo esc_attr( $tool['button'] ); ?>" />
</file>

<file path="plugins/woocommerce/includes/admin/views/html-admin-page-status.php">
WC_Admin_Status::status_tools();
⋮----
WC_Admin_Status::status_logs();
⋮----
WC_Admin_Status::status_report();
</file>

<file path="plugins/woocommerce/includes/admin/views/html-admin-settings.php">
use Automattic\WooCommerce\Internal\Admin\Settings\SettingsUIRequestContext;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$settings_ui_context = SettingsUIRequestContext::get_current();
⋮----
$settings_ui_settings_page           = $settings_ui_context->get_settings_page();
$is_rendering_settings_ui_drill_down = $settings_ui_context->is_rendering_enabled()
&& $settings_ui_context->is_drill_down()
&& ! $settings_ui_context->has_schema_failed()
&& ! $settings_ui_context->has_script_handle_loading_failed();
⋮----
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Used only to select non-mutating view output.
⋮----
/**
				 * Hook for adding additional settings tabs.
				 *
				 * @since 1.0.0
				 */
⋮----
WC_Admin_Settings::show_messages();
⋮----
$icon_url      = WC()->plugin_url() . '/assets/images/icons/external-link.svg';
</file>

<file path="plugins/woocommerce/includes/admin/views/html-bulk-edit-product.php">
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
use Automattic\WooCommerce\Enums\CatalogVisibility;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Utilities\I18nUtil;
⋮----
<?php if ( wc_get_container()->get( CostOfGoodsSoldController::class )->feature_is_enabled() ) : ?>
⋮----
<?php /* phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped */ ?>
⋮----
$tax_classes = WC_Tax::get_tax_classes();
⋮----
I18nUtil::get_weight_unit_label( get_option( 'woocommerce_weight_unit', 'kg' ) )
⋮----
$dimension_unit_label = I18nUtil::get_dimensions_unit_label( get_option( 'woocommerce_dimension_unit', 'cm' ) );
</file>

<file path="plugins/woocommerce/includes/admin/views/html-email-template-preview.php">

</file>

<file path="plugins/woocommerce/includes/admin/views/html-notice-custom.php">

</file>

<file path="plugins/woocommerce/includes/admin/views/html-notice-update.php">

</file>

<file path="plugins/woocommerce/includes/admin/views/html-notice-updated.php">

</file>

<file path="plugins/woocommerce/includes/admin/views/html-notice-updating.php">
use Automattic\Jetpack\Constants;
⋮----
$cron_disabled       = Constants::is_true( 'DISABLE_WP_CRON' );
</file>

<file path="plugins/woocommerce/includes/admin/views/html-quick-edit-product.php">
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
use Automattic\WooCommerce\Enums\CatalogVisibility;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
⋮----
<?php if ( wc_get_container()->get( CostOfGoodsSoldController::class )->feature_is_enabled() ) : ?>
⋮----
$tax_classes = WC_Tax::get_tax_classes();
</file>

<file path="plugins/woocommerce/includes/admin/views/html-report-by-date.php">
<?php $this->get_export_button(); ?>
⋮----
<?php if ( $legends = $this->get_chart_legend() ) : ?>
⋮----
<?php foreach ( $this->get_chart_widgets() as $widget ) : ?>
⋮----
<?php $this->get_main_chart(); ?>
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-addons.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Admin\RemoteInboxNotifications as PromotionRuleEngine;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
⋮----
class WC_Admin_Addons {
⋮----
public static function fetch_featured() {
⋮----
$featured = self::get_locale_data_from_transient( $transient_name, $locale );
⋮----
$raw_featured  = self::fetch( $url, $fetch_options );
⋮----
$featured = self::process_api_response( $raw_featured, 'featured' );
⋮----
self::set_locale_data_in_transient( $transient_name, $featured, $locale, DAY_IN_SECONDS );
⋮----
public static function fetch_product_preview( int $product_id ) {
⋮----
$raw_preview = self::fetch( $url, $fetch_options );
⋮----
return self::process_api_response( $raw_preview, 'product preview', true );
⋮----
public static function is_ssl_error( $error_message ) {
⋮----
public static function get_sections() {
⋮----
$addon_sections = self::get_locale_data_from_transient( 'wc_addons_sections', $locale );
⋮----
self::set_locale_data_in_transient( 'wc_addons_sections', $addon_sections, $locale, WEEK_IN_SECONDS );
⋮----
... (57 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-api-keys-table-list.php">
class WC_Admin_API_Keys_Table_List extends WP_List_Table {
⋮----
public function __construct() {
parent::__construct(
⋮----
public function no_items() {
⋮----
public function get_columns() {
⋮----
public function column_cb( $key ) {
⋮----
public function column_title( $key ) {
⋮----
public function column_truncated_key( $key ) {
⋮----
public function column_user( $key ) {
⋮----
public function column_permissions( $key ) {
⋮----
/**
	 * Return last access column.
	 *
	 * @param  array $key Key data.
	 * @return string
	 */
public function column_last_access( $key ) {
⋮----
protected function get_bulk_actions() {
⋮----
public function search_box( $text, $input_id ) {
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-api-keys.php">
class WC_Admin_API_Keys {
⋮----
public function __construct() {
⋮----
public function allow_save_settings( $allow ) {
⋮----
private function is_api_keys_settings_page() {
⋮----
public static function page_output() {
⋮----
$key_data = self::get_key_data( $key_id );
⋮----
self::table_list_output();
⋮----
public function screen_option() {
⋮----
if ( ! isset( $_GET['create-key'] ) && ! isset( $_GET['edit-key'] ) && $this->is_api_keys_settings_page() ) {
⋮----
private static function table_list_output() {
⋮----
$count = $wpdb->get_var( "SELECT COUNT(key_id) FROM {$wpdb->prefix}woocommerce_api_keys WHERE 1 = 1;" );
⋮----
$keys_table_list->prepare_items();
⋮----
$keys_table_list->views();
$keys_table_list->search_box( __( 'Search key', 'woocommerce' ), 'key' );
$keys_table_list->display();
⋮----
private static function get_key_data( $key_id ) {
⋮----
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-assets.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\Admin\Analytics;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
⋮----
class WC_Admin_Assets {
⋮----
public function __construct() {
⋮----
private function should_show_lost_connection_notice() {
⋮----
&& \Automattic\WooCommerce\Admin\PageController::is_admin_page();
⋮----
public function render_lost_connection_notice() {
if ( ! $this->should_show_lost_connection_notice() ) {
⋮----
public function admin_styles() {
$version   = Constants::get_constant( 'WC_VERSION' );
⋮----
// Register admin styles.
wp_register_style( 'woocommerce_admin_menu_styles', WC()->plugin_url() . '/assets/css/menu.css', array(), $version );
wp_register_style( 'woocommerce_admin_styles', WC()->plugin_url() . '/assets/css/admin.css', array(), $version );
wp_register_style( 'jquery-ui-style', WC()->plugin_url() . '/assets/css/jquery-ui/jquery-ui.min.css', array(), $version );
wp_register_style( 'woocommerce_admin_dashboard_styles', WC()->plugin_url() . '/assets/css/dashboard.css', array(), $version );
wp_register_style( 'woocommerce_admin_print_reports_styles', WC()->plugin_url() . '/assets/css/reports-print.css', array(), $version, 'print' );
wp_register_style( 'woocommerce_admin_marketplace_styles', WC()->plugin_url() . '/assets/css/marketplace-suggestions.css', array(), $version );
wp_register_style( 'woocommerce_admin_privacy_styles', WC()->plugin_url() . '/assets/css/privacy.css', array(), $version );
... (102 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-attributes.php">
use Automattic\WooCommerce\Internal\ProductAttributes\AttributeSlugLength;
use Automattic\WooCommerce\Internal\ProductAttributes\VisualAttributeTermAdmin;
⋮----
class WC_Admin_Attributes {
⋮----
private static $edited_attribute_id;
⋮----
public static function output() {
⋮----
// Action to perform: add, edit, delete or none.
⋮----
$result = self::process_add_attribute();
⋮----
$result = self::process_edit_attribute();
⋮----
$result = self::process_delete_attribute();
⋮----
echo '<div id="woocommerce_errors" class="error"><p>' . wp_kses_post( $result->get_error_message() ) . '</p></div>';
⋮----
self::edit_attribute();
⋮----
self::add_attribute();
⋮----
private static function get_posted_attribute() {
⋮----
'attribute_label'   => isset( $_POST['attribute_label'] ) ? wc_clean( wp_unslash( $_POST['attribute_label'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Action helpers verify nonces; fields are normalized before CRUD.
'attribute_name'    => isset( $_POST['attribute_name'] ) ? wc_sanitize_taxonomy_name( wp_unslash( $_POST['attribute_name'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Action helpers verify nonces; fields are normalized before CRUD.
⋮----
'attribute_orderby' => isset( $_POST['attribute_orderby'] ) ? wc_clean( wp_unslash( $_POST['attribute_orderby'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Action helpers verify nonces; fields are normalized before CRUD.
⋮----
... (27 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-brands.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Brands_Admin {
⋮----
public $settings_tabs;
⋮----
private $settings;
⋮----
public $fields = array();
⋮----
public function __construct() {
⋮----
$this->init_form_fields();
⋮----
public function add_settings_section( $settings, $current_section ) {
⋮----
public function add_settings_tab( $sections ) {
⋮----
public function add_coupon_brands_fields() {
⋮----
public function save_coupon_brands( $post_id ) {
⋮----
public function init_form_fields() {
⋮----
public function scripts() {
⋮----
$version = Constants::get_constant( 'WC_VERSION' );
$suffix  = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min';
⋮----
WC()->plugin_url() . '/assets/js/admin/wc-brands-enhanced-select' . $suffix . '.js',
... (136 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-customize.php">
class WC_Admin_Customize {
⋮----
public function __construct() {
⋮----
public function register_customize_nav_menu_item_types( $item_types ) {
⋮----
public function register_customize_nav_menu_items( $items = array(), $type = '', $object = '', $page = 0 ) {
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-dashboard-setup.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskLists;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
⋮----
class WC_Admin_Dashboard_Setup {
⋮----
private bool $initialized = false;
⋮----
private $task_list = null;
⋮----
private $tasks = null;
⋮----
private $completed_tasks_count = 0;
⋮----
public function __construct() {
if ( $this->should_display_widget() ) {
⋮----
public function render() {
$version = Constants::get_constant( 'WC_VERSION' );
wp_enqueue_style( 'wc-dashboard-setup', WC()->plugin_url() . '/assets/css/dashboard-setup.css', array(), $version );
⋮----
$task = $this->get_next_task();
⋮----
$button_link            = $this->get_button_link( $task );
$task_header            = $this->get_task_header( $task );
$task_is_in_progress    = $task->is_in_progress();
$task_in_progress_label = $task_is_in_progress ? $task->in_progress_label() : '';
$completed_tasks_count  = $this->get_completed_tasks_count();
⋮----
... (51 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-dashboard.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\OrderInternalStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class WC_Admin_Dashboard {
⋮----
public function __construct() {
⋮----
if ( $this->should_display_widget() ) {
⋮----
public function init() {
⋮----
$this->register_network_order_widget();
⋮----
public function register_network_order_widget() {
⋮----
private function should_display_widget() {
if ( ! WC()->is_wc_admin_active() ) {
⋮----
private function get_top_seller() {
⋮----
$hpos_enabled         = OrderUtil::custom_orders_table_usage_is_enabled();
$orders_table         = OrderUtil::get_table_for_orders();
⋮----
return $wpdb->get_row( $sql );
⋮----
... (74 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-duplicate-product.php">
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\ProductGallery\ProductMediaGallery;
⋮----
class WC_Admin_Duplicate_Product {
⋮----
public function __construct() {
⋮----
public function dupe_link( $actions, $post ) {
⋮----
if ( empty( $the_product ) || $the_product->get_id() !== $post->ID ) {
⋮----
if ( $the_product && ProductStatus::PUBLISH === $the_product->get_status() && 0 < $the_product->get_total_sales() ) {
⋮----
get_delete_post_link( $the_product->get_id(), '', false ),
/* translators: %s: post title */
⋮----
public function duplicate_product_action() {
⋮----
$duplicate = $this->product_duplicate( $product );
⋮----
wc_do_deprecated_action( 'woocommerce_duplicate_product', array( $duplicate->get_id(), $this->get_product_to_duplicate( $product_id ) ), '3.0', 'Use woocommerce_product_duplicate action instead.' );
⋮----
wp_redirect( admin_url( 'post.php?action=edit&post=' . $duplicate->get_id() ) );
⋮----
public function product_duplicate( $product ) {
⋮----
$product->get_meta_data()
⋮----
$duplicate->set_id( 0 );
... (114 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-exporters.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class WC_Admin_Exporters {
⋮----
protected $exporters = array();
⋮----
public function __construct() {
if ( ! $this->export_allowed() ) {
⋮----
protected function export_allowed() {
⋮----
public function add_to_menus() {
⋮----
public function hide_from_menus() {
⋮----
public function menu_highlight_for_product_export() {
⋮----
public function admin_scripts() {
$suffix  = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min';
$version = Constants::get_constant( 'WC_VERSION' );
wp_register_script( 'wc-product-export', WC()->plugin_url() . '/assets/js/admin/wc-product-export' . $suffix . '.js', array( 'jquery' ), $version );
⋮----
public function product_exporter() {
⋮----
public function download_export_file() {
⋮----
$exporter->set_filename( wp_unslash( $_GET['filename'] ) );
⋮----
$exporter->export();
... (29 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-help.php">
class WC_Admin_Help {
⋮----
public function __construct() {
⋮----
public function add_tabs() {
⋮----
$screen->add_help_tab(
⋮----
$screen->set_help_sidebar(
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-importers.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Integrations\WPPostsImporter;
⋮----
class WC_Admin_Importers {
⋮----
protected $importers = array();
⋮----
public function __construct() {
if ( ! $this->import_allowed() ) {
⋮----
$wp_posts_importer = wc_get_container()->get( WPPostsImporter::class );
$wp_posts_importer->register();
⋮----
protected function import_allowed() {
⋮----
public function add_to_menus() {
⋮----
public function hide_from_menus() {
⋮----
public function menu_highlight_for_product_import() {
⋮----
public function admin_scripts() {
$suffix  = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min';
$version = Constants::get_constant( 'WC_VERSION' );
wp_register_script( 'wc-product-import', WC()->plugin_url() . '/assets/js/admin/wc-product-import' . $suffix . '.js', array( 'jquery' ), $version, true );
⋮----
public function product_importer() {
if ( Constants::is_defined( 'WP_LOAD_IMPORTERS' ) ) {
⋮----
$importer->dispatch();
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-log-table-list.php">
class WC_Admin_Log_Table_List extends WP_List_Table {
⋮----
public function __construct() {
parent::__construct(
⋮----
public function level_dropdown() {
$labels = WC_Log_Levels::get_all_level_labels();
⋮----
public function display_rows() {
⋮----
$this->single_row( $log );
⋮----
$this->context_row( $log );
⋮----
protected function context_row( $log ) {
⋮----
<td colspan="<?php echo esc_attr( $this->get_column_count() ); ?>">
⋮----
public function get_columns() {
⋮----
public function column_cb( $log ) {
⋮----
public function column_timestamp( $log ) {
⋮----
public function column_level( $log ) {
$level_key = WC_Log_Levels::get_severity_level( $log['level'] );
$levels    = WC_Log_Levels::get_all_level_labels();
⋮----
/**
	 * Message column.
... (85 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-marketplace-promotions.php">
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\FailRuleProcessor;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\GetRuleProcessor;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\OrdersProvider;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
⋮----
class WC_Admin_Marketplace_Promotions {
⋮----
public static string $locale;
⋮----
private static $orders_promo_card = null;
⋮----
private static $orders_promo_card_resolved = false;
⋮----
public static function init() {
⋮----
self::schedule_cron_event();
⋮----
self::maybe_show_bubble_promotions();
⋮----
private static function schedule_cron_event() {
⋮----
public static function update_promotions() {
⋮----
$promotions = self::fetch_marketplace_promotions();
⋮----
public static function get_active_promotions() {
⋮----
$promotions = self::merge_promos( $promotions );
$promotions = self::resolve_rule_based_promotions( $promotions );
... (113 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-menus.php">
use Automattic\WooCommerce\Internal\Admin\Marketplace;
use Automattic\WooCommerce\Internal\Admin\Orders\COTRedirectionController;
use Automattic\WooCommerce\Internal\Admin\Orders\PageController as Custom_Orders_PageController;
use Automattic\WooCommerce\Internal\Admin\Logging\PageController as LoggingPageController;
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\{ FileListTable, SearchListTable };
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
⋮----
class WC_Admin_Menus {
⋮----
public function __construct() {
⋮----
$container->get( Marketplace::class );
⋮----
public function admin_menu() {
⋮----
if ( self::can_view_woocommerce_menu_item() ) {
⋮----
public function reports_menu() {
⋮----
public function settings_menu() {
⋮----
public static function can_view_woocommerce_menu_item() {
⋮----
public function settings_page_init() {
WC()->payment_gateways();
WC()->shipping();
⋮----
WC_Admin_Settings::get_settings_pages();
⋮----
WC_Admin_Settings::add_error( wp_kses_post( wp_unslash( $_GET['wc_error'] ) ) );
... (80 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-meta-boxes.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Orders\Edit as OrderEdit;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class WC_Admin_Meta_Boxes {
⋮----
private static $saved_meta_boxes = false;
⋮----
public static $meta_box_errors = array();
⋮----
public function __construct() {
⋮----
OrderEdit::add_save_meta_boxes();
⋮----
public static function add_error( $text ) {
⋮----
public function save_errors() {
⋮----
public function append_to_error_store() {
⋮----
public function output_errors() {
⋮----
public function add_meta_boxes() {
⋮----
// Products.
⋮----
OrderEdit::add_order_meta_boxes( $type, $order_type_object->labels->singular_name );
⋮----
public function add_product_boxes_sort_order() {
⋮----
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-notices.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Admin_Notices {
⋮----
private static $notices = array();
⋮----
private static $core_notices = array(
⋮----
private static bool $is_multisite;
⋮----
public static function init() {
⋮----
self::set_notices( get_option( 'woocommerce_admin_notices', array() ) );
⋮----
self::remove_notice( WC_PHP_MIN_REQUIREMENTS_NOTICE );
⋮----
if ( ! WC_Install::is_new_install() || ! wc_is_running_from_async_action_scheduler() ) {
⋮----
public static function prepare_note_with_nonce( $response ) {
⋮----
public static function store_notices() {
$current_notices = self::get_notices();
⋮----
public static function get_notices() {
⋮----
private static function set_notices( array $notices ) {
⋮----
public static function remove_all_notices() {
self::set_notices( array() );
⋮----
... (110 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-permalink-settings.php">
class WC_Admin_Permalink_Settings {
⋮----
private $permalinks = array();
⋮----
public function __construct() {
$this->settings_init();
$this->settings_save();
⋮----
public function settings_init() {
⋮----
public function product_category_slug_input() {
⋮----
public function product_tag_slug_input() {
⋮----
public function product_attribute_slug_input() {
⋮----
private function get_shop_base_slug( int $shop_page_id ): string {
⋮----
private function get_stored_product_base( string $posted_base, ?string $posted_structure = null ): string {
⋮----
// A base of nothing but the category token gives products the same URL shape as the
// category archives they sit under, so the two collide. Prefix the default base.
⋮----
// The Default radio posts an empty value; store the site-locale slug.
⋮----
/*
		 * Resolve an empty base to the default one. A custom base that is blank, whitespace, or
		 * nothing but hashes and slashes sanitizes down to empty, and an empty base does not
		 * survive: wc_get_permalink_structure() drops it and refills the option from the request
		 * locale, outside any locale window, persisting a slug the site locale never chose -- the
... (32 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-pointers.php">
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
use Automattic\WooCommerce\Admin\Features\Features;
⋮----
class WC_Admin_Pointers {
⋮----
public function __construct() {
⋮----
public function setup_pointers_for_screen() {
⋮----
$this->create_product_tutorial();
$this->create_variable_product_tutorial();
⋮----
$this->create_wc_addons_tutorial();
⋮----
public function create_product_tutorial() {
⋮----
WCAdminAssets::register_script( 'wp-admin-scripts', 'product-tour', true );
⋮----
public function create_variable_product_tutorial() {
⋮----
WCAdminAssets::register_script( 'wp-admin-scripts', 'variable-product-tour', true );
⋮----
public function create_wc_addons_tutorial() {
⋮----
WCAdminAssets::register_script( 'wp-admin-scripts', 'wc-addons-tour', true );
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-post-types.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
use Automattic\WooCommerce\Utilities\NumberUtil;
use Automattic\WooCommerce\Utilities\TimeUtil;
⋮----
class WC_Admin_Post_Types {
⋮----
public function __construct() {
⋮----
$this->maybe_display_warning_for_password_protected_coupon();
⋮----
public function setup_screen() {
⋮----
$request_data = $this->request_data();
⋮----
public function post_updated_messages( $messages ) {
⋮----
0  => '', // Unused. Messages start at index 1.
/* translators: %1$s: Product link opening tag. %2$s: Product link closing tag.*/
⋮----
$messages = $this->order_updated_messages( $messages );
⋮----
public function order_updated_messages( array $messages ) {
⋮----
\Automattic\WooCommerce\Utilities\OrderUtil::init_theorder_object( $post );
⋮----
'<strong>' . date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $theorder->get_date_created() ?? $post->post_date ) ) . '</strong>'
⋮----
... (199 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-profile.php">
class WC_Admin_Profile {
⋮----
public function __construct() {
⋮----
public function get_customer_meta_fields() {
⋮----
'options'     => array( '' => __( 'Select a country / region&hellip;', 'woocommerce' ) ) + WC()->countries->get_allowed_countries(),
⋮----
/**
		 * Show Address Fields on edit user pages.
		 *
		 * @param WP_User $user
		 */
public function add_customer_meta_fields( $user ) {
⋮----
$show_fields = $this->get_customer_meta_fields();
⋮----
<input type="text" name="<?php echo esc_attr( $key ); ?>" id="<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $this->get_user_meta( $user->ID, $key ) ); ?>" class="<?php echo ( ! empty( $field['class'] ) ? esc_attr( $field['class'] ) : 'regular-text' ); ?>" />
⋮----
public function save_customer_meta_fields( $user_id ) {
⋮----
$save_fields = $this->get_customer_meta_fields();
⋮----
protected function get_user_meta( $user_id, $key ) {
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-reports.php">
class WC_Admin_Reports {
⋮----
public static function register_hook_handlers() {
⋮----
public static function register_orders_hook_handlers(): void {
⋮----
public static function delete_legacy_reports_transients( int $order_id, bool $defer = true ): void {
⋮----
foreach ( self::get_reports() as $report_group ) {
⋮----
public static function get_report_instance() {
⋮----
public static function replace_dashboard_status_widget_reports( $status_widget_reports ) {
$report = self::get_report_instance();
⋮----
$status_widget_reports['report_data']         = $sales_by_date->get_report_data();
⋮----
public static function output() {
$reports        = self::get_reports();
⋮----
public static function get_reports() {
⋮----
public static function get_report( $name ) {
⋮----
$report = new $class();
$report->output_report();
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-settings.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Admin_Settings {
⋮----
private static $settings = array();
⋮----
private static $errors = array();
⋮----
private static $messages = array();
⋮----
public static function get_settings_pages() {
⋮----
$screen->remove_help_tabs();
⋮----
public static function save() {
⋮----
self::add_message( __( 'Your settings have been saved.', 'woocommerce' ) );
self::check_download_folder_protection();
⋮----
WC()->query->init_query_vars();
WC()->query->add_endpoints();
⋮----
self::maybe_redirect_after_settings_ui_save();
⋮----
private static function maybe_redirect_after_settings_ui_save(): void {
⋮----
/**
		 * Add a message.
		 *
		 * @param string $text Message.
... (67 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-setup-wizard.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Admin_Setup_Wizard {
⋮----
private $step = '';
⋮----
/**
	 * Steps for the setup wizard
	 *
	 * @var array
	 */
private $steps = array();
⋮----
/**
	 * Actions to be executed after the HTTP response has completed
	 *
	 * @var array
	 */
private $deferred_actions = array();
⋮----
/**
	 * Tweets user can optionally send after install
	 *
	 * @var array
	 */
private $tweets = array(
⋮----
'Someone give me high five, I just set up a new store with #WordPress and @WooCommerce!',
⋮----
private $wc_admin_plugin_minimum_wordpress_version = '5.3';
... (322 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-status.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Logging\PageController as LoggingPageController;
⋮----
class WC_Admin_Status {
⋮----
private static $db_log_list_table;
⋮----
public static function output() {
⋮----
public static function status_report() {
⋮----
public static function status_tools() {
⋮----
$tools                 = self::get_tools();
⋮----
$response = $tools_controller->execute_tool( $action );
⋮----
$tools = self::get_tools();
⋮----
public static function get_tools() {
⋮----
return $tools_controller->get_tools();
⋮----
public static function status_logs() {
wc_get_container()->get( LoggingPageController::class )->render();
⋮----
public static function status_logs_file() {
$logs = self::scan_log_files();
⋮----
$handle = ! empty( $viewed_log ) ? self::get_log_file_handle( $viewed_log ) : '';
... (51 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-taxonomies.php">
use Automattic\WooCommerce\Internal\AssignDefaultCategory;
⋮----
class WC_Admin_Taxonomies {
⋮----
protected static $instance = false;
⋮----
private $default_cat_id = 0;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
wc_get_container()->get( AssignDefaultCategory::class )->schedule_action();
⋮----
public function create_term( $term_id, $tt_id = '', $taxonomy = '' ) {
⋮----
public function delete_term( $term_id ) {
⋮----
public function add_category_fields() {
⋮----
/**
	 * Edit category thumbnail field.
	 *
	 * @param mixed $term Term (category) being edited.
	 */
public function edit_category_fields( $term ) {
⋮----
public function save_category_fields( $term_id, $tt_id = '', $taxonomy = '' ) {
⋮----
$display_type = is_string( $_POST['display_type'] ) ? sanitize_key( $_POST['display_type'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Core term-edit flow verifies the nonce before firing this hook.
... (29 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-upload-downloadable-product.php">
class WC_Admin_Upload_Downloadable_Product {
⋮----
public function __construct() {
⋮----
public function upload_dir( $pathdata ) {
⋮----
public function update_filename( $full_filename, $ext, $dir ) {
⋮----
return $this->unique_filename( $full_filename, $ext );
⋮----
public function unique_filename( $full_filename, $ext ) {
⋮----
public function woocommerce_media_upload_downloadable_product() {
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-webhooks-table-list.php">
class WC_Admin_Webhooks_Table_List extends WP_List_Table {
⋮----
public function __construct() {
parent::__construct(
⋮----
public function no_items() {
⋮----
public function get_columns() {
⋮----
public function column_cb( $webhook ) {
return sprintf( '<input type="checkbox" name="%1$s[]" value="%2$s" />', $this->_args['singular'], $webhook->get_id() );
⋮----
public function column_title( $webhook ) {
$edit_link = admin_url( 'admin.php?page=wc-settings&amp;tab=advanced&amp;section=webhooks&amp;edit-webhook=' . $webhook->get_id() );
$output    = '<strong><a href="' . esc_url( $edit_link ) . '" class="row-title">' . esc_html( $webhook->get_name() ) . '</a></strong>';
⋮----
'id'     => sprintf( __( 'ID: %d', 'woocommerce' ), $webhook->get_id() ),
⋮----
'delete' => '<a class="submitdelete" aria-label="' . esc_attr( sprintf( __( 'Delete "%s" permanently', 'woocommerce' ), $webhook->get_name() ) ) . '" href="' . esc_url(
⋮----
'delete' => $webhook->get_id(),
⋮----
public function column_status( $webhook ) {
return $webhook->get_i18n_status();
⋮----
public function column_topic( $webhook ) {
return $webhook->get_topic();
⋮----
public function column_delivery_url( $webhook ) {
return $webhook->get_delivery_url();
... (46 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin-webhooks.php">
class WC_Admin_Webhooks {
⋮----
public function __construct() {
⋮----
public function allow_save_settings( $allow ) {
⋮----
private function is_webhook_settings_page() {
⋮----
private function save() {
⋮----
(new DateTime('now'))->format( _x( 'M d, Y @ h:i A', 'Webhook created on date parsed by DateTime::format', 'woocommerce' ) )
⋮----
$webhook->set_name( $name );
⋮----
if ( ! $webhook->get_user_id() ) {
$webhook->set_user_id( get_current_user_id() );
⋮----
$webhook->set_status( ! empty( $_POST['webhook_status'] ) ? sanitize_text_field( wp_unslash( $_POST['webhook_status'] ) ) : 'disabled' );
⋮----
$webhook->set_delivery_url( $delivery_url );
⋮----
// Secret.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
⋮----
$webhook->set_secret( $secret );
⋮----
$webhook->set_topic( $topic );
⋮----
$webhook->set_api_version( ! empty( $_POST['webhook_api_version'] ) ? sanitize_text_field( wp_unslash( $_POST['webhook_api_version'] ) ) : end( $rest_api_versions ) );
⋮----
... (68 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/class-wc-admin.php">
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Internal\Admin\EmailPreview\EmailPreview;
⋮----
class WC_Admin {
⋮----
public function __construct() {
⋮----
public function buffer() {
⋮----
public function includes() {
⋮----
public function init_page_controller() {
⋮----
PageController::get_instance();
⋮----
public function conditional_includes() {
⋮----
public function admin_redirects() {
⋮----
public function prevent_admin_access() {
⋮----
public function preview_emails() {
⋮----
$email_preview = wc_get_container()->get( EmailPreview::class );
⋮----
$email_preview->set_email_type( $type_param );
⋮----
$message = $email_preview->render();
$message = $email_preview->ensure_links_open_in_new_tab( $message );
⋮----
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/wc-admin-functions.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
use Automattic\WooCommerce\Internal\Utilities\OrderItemMetaUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
function wc_get_screen_ids() {
⋮----
function wc_get_page_screen_id( $for ) {
⋮----
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
$screen_id = ( \WC_Admin_Menus::can_view_woocommerce_menu_item() ? 'woocommerce_page_wc-orders' : 'admin_page_wc-orders' ) . ( 'shop_order' === $for ? '' : '--' . $for );
⋮----
/**
 * Create a page and store the ID in an option.
 *
 * @param mixed  $slug Slug for the new page.
 * @param string $option Option name to store the page's ID.
 * @param string $page_title (default: '') Title for the new page.
 * @param string $page_content (default: '') Content for the new page.
 * @param int    $post_parent (default: 0) Parent for the new page.
 * @param string $post_status (default: publish) The post status of the new page.
 * @return int page ID.
 */
function wc_create_page( $slug, $option = '', $page_title = '', $page_content = '', $post_parent = 0, $post_status = 'publish' ) {
⋮----
$valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' ) AND post_content LIKE %s LIMIT 1;", "%{$shortcode}%" ) );
⋮----
// Search for an existing page with the specified page slug.
$valid_page_found = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type='page' AND post_status NOT IN ( 'pending', 'trash', 'future', 'auto-draft' )  AND post_name = %s LIMIT 1;", $slug ) );
⋮----
... (156 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/wc-meta-box-functions.php">
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
function woocommerce_wp_text_input( $field, ?WC_Data $data = null ) {
⋮----
$field['value']         = $field['value'] ?? OrderUtil::get_post_or_object_meta( $post, $data, $field['id'], true );
⋮----
//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
⋮----
/**
 * Output a hidden input box.
 *
 * @param array        $field Field data.
 * @param WC_Data|null $data  WC_Data object, will be preferred over post object when passed.
 */
function woocommerce_wp_hidden_input( $field, ?WC_Data $data = null ) {
⋮----
$field['value'] = isset( $field['value'] ) ? $field['value'] : OrderUtil::get_post_or_object_meta( $post, $data, $field['id'], true );
⋮----
/**
 * Output a textarea input box.
 *
 * @param array        $field Field data.
 * @param WC_Data|null $data  WC_Data object, will be preferred over post object when passed.
 */
function woocommerce_wp_textarea_input( $field, ?WC_Data $data = null ) {
⋮----
function woocommerce_wp_checkbox( $field, ?WC_Data $data = null ) {
⋮----
function woocommerce_wp_select( $field, ?WC_Data $data = null ) {
⋮----
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/includes/admin/woocommerce-legacy-reports.php">
function woocommerce_legacy_reports_init() {
⋮----
WC_Admin_Reports::register_hook_handlers();
</file>

<file path="plugins/woocommerce/includes/blocks/class-wc-blocks-utils.php">
class WC_Blocks_Utils {
⋮----
private static function get_all_blocks_from_page( $woo_page_name ) {
⋮----
public static function get_blocks_from_page( $block_name, $woo_page_name ) {
$page_blocks = self::get_all_blocks_from_page( $woo_page_name );
⋮----
public static function has_block_in_page( $page, $block_name ): bool {
</file>

<file path="plugins/woocommerce/includes/cli/class-wc-cli-com-command.php">
class WC_CLI_COM_Command {
⋮----
public static function register_commands() {
WP_CLI::add_command( 'wc com extension list', array( 'WC_CLI_COM_Command', 'list_extensions' ) );
WP_CLI::add_command( 'wc com disconnect', array( 'WC_CLI_COM_Command', 'disconnect' ) );
WP_CLI::add_command( 'wc com connect', array( 'WC_CLI_COM_Command', 'connect' ) );
⋮----
public static function list_extensions( array $args, array $assoc_args ) {
⋮----
$data = WC_Helper::get_subscriptions();
⋮----
$formatter = new \WP_CLI\Formatter(
⋮----
$formatter->display_items( $data );
⋮----
public static function disconnect( array $args, array $assoc_args ) {
if ( ! WC_Helper::is_site_connected() ) {
WP_CLI::error( __( 'Your store is not connected to WooCommerce.com. Run `wp wc com connect` command.', 'woocommerce' ) );
⋮----
WP_CLI::confirm( __( 'Are you sure you want to disconnect your store from WooCommerce.com?', 'woocommerce' ), $assoc_args );
WC_Helper::disconnect();
WP_CLI::success( __( 'You have successfully disconnected your store from WooCommerce.com', 'woocommerce' ) );
⋮----
public static function connect( array $args, array $assoc_args ) {
$password = \WP_CLI\Utils\get_flag_value( $assoc_args, 'password' );
$force    = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force', false );
⋮----
if ( WC_Helper::is_site_connected() ) {
⋮----
WP_CLI::error( __( 'Your store is already connected.', 'woocommerce' ) );
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/includes/cli/class-wc-cli-com-extension-command.php">
class WC_CLI_COM_Extension_Command extends Plugin_Command {
⋮----
public static function register_commands() {
WP_CLI::add_command( 'wc com extension', 'WC_CLI_COM_Extension_Command' );
⋮----
public function install( $args, $assoc_args ) {
$subscriptions         = WC_Helper_Updater::get_available_extensions_downloads_data();
⋮----
WP_CLI::warning( sprintf( 'We couldn\'t find a Subscription for \'%s\'', $extension ) );
WP_CLI\Utils\report_batch_operation_results( $this->item_type, 'install', count( $args ), 0, 1 );
⋮----
parent::install( array( $extension_package_url ), $assoc_args );
</file>

<file path="plugins/woocommerce/includes/cli/class-wc-cli-rest-command.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
class WC_CLI_REST_Command {
⋮----
protected $routes_with_parent_id = array(
⋮----
private $name;
⋮----
private $route;
⋮----
private $resource_identifier;
⋮----
private $schema;
⋮----
private $supported_ids = array();
⋮----
public function __construct( $name, $route, $schema ) {
⋮----
public function set_supported_ids( $supported_ids = array() ) {
⋮----
public function get_supported_ids() {
⋮----
public function create_item( $args, $assoc_args ) {
$assoc_args            = self::decode_json( $assoc_args );
list( $status, $body ) = $this->do_request( 'POST', $this->get_filled_route( $args ), $assoc_args );
if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) {
WP_CLI::line( $body['id'] );
⋮----
WP_CLI::success( "Created {$this->name} {$body['id']}." );
... (77 lines truncated)
</file>

<file path="plugins/woocommerce/includes/cli/class-wc-cli-runner.php">
class WC_CLI_Runner {
⋮----
private static $disabled_endpoints = array(
⋮----
private static $target_rest_version = 'v2';
⋮----
public static function after_wp_load() {
⋮----
$request->set_param( 'context', 'help' );
$response      = $wp_rest_server->dispatch( $request );
$response_data = $response->get_data();
⋮----
WP_CLI::debug( sprintf( __( 'No schema title found for %s, skipping REST command registration.', 'woocommerce' ), $route ), 'wc' );
⋮----
self::register_route_commands( new WC_CLI_REST_Command( $route_data['schema']['title'], $route, $route_data['schema'] ), $route, $route_data );
⋮----
private static function register_route_commands( $rest_command, $route, $route_data, $command_args = array() ) {
⋮----
$rest_command->set_supported_ids( $supported_ids );
⋮----
// List a collection.
⋮----
if ( empty( $command_args['when'] ) && \WP_CLI::get_config( 'debug' ) ) {
⋮----
WP_CLI::add_command(
</file>

<file path="plugins/woocommerce/includes/cli/class-wc-cli-tool-command.php">
class WC_CLI_Tool_Command {
⋮----
public static function register_commands() {
⋮----
$response      = $wp_rest_server->dispatch( $request );
$response_data = $response->get_data();
⋮----
if ( empty( $command_args['when'] ) && WP_CLI::get_config( 'debug' ) ) {
⋮----
WP_CLI::add_command(
</file>

<file path="plugins/woocommerce/includes/cli/class-wc-cli-tracker-command.php">
class WC_CLI_Tracker_Command {
⋮----
public static function register_commands() {
WP_CLI::add_command( 'wc tracker snapshot', array( 'WC_CLI_Tracker_Command', 'show_tracker_snapshot' ) );
⋮----
public static function show_tracker_snapshot( $args, $assoc_args ) {
$snapshot_data = WC_Tracker::get_tracking_data();
⋮----
$formatter = new \WP_CLI\Formatter(
⋮----
$formatter->display_items( array( $snapshot_data ) );
</file>

<file path="plugins/woocommerce/includes/cli/class-wc-cli-update-command.php">
class WC_CLI_Update_Command {
⋮----
public static function register_commands() {
WC()->call_static( WP_CLI::class, 'add_command', 'wc update', array( 'WC_CLI_Update_Command', 'update' ) );
⋮----
public static function update() {
⋮----
$wpdb->hide_errors();
⋮----
$callbacks          = WC_Install::get_db_update_callbacks();
⋮----
WC_Install::update_db_version();
⋮----
WC()->call_static(
⋮----
$progress = WC()->call_function(
⋮----
$progress->tick();
⋮----
$progress->finish();
⋮----
\WC_Install::remove_update_db_notice();
</file>

<file path="plugins/woocommerce/includes/customizer/class-wc-customizer-control-cropping.php">
class WC_Customizer_Control_Cropping extends WP_Customize_Control {
⋮----
public $type = 'woocommerce-cropping-control';
⋮----
public function render_content() {
⋮----
$value         = $this->value( 'cropping' );
$custom_width  = $this->value( 'custom_width' );
$custom_height = $this->value( 'custom_height' );
⋮----
<input type="radio" name="<?php echo esc_attr( $this->id ); ?>" value="<?php echo esc_attr( $key ); ?>" id="<?php echo esc_attr( $this->id . $key ); ?>" <?php $this->link( 'cropping' ); ?> <?php checked( $value, $key ); ?> />
⋮----
<input type="text" pattern="\d*" size="3" value="<?php echo esc_attr( $custom_width ); ?>" <?php $this->link( 'custom_width' ); ?> /> : <input type="text" pattern="\d*" size="3" value="<?php echo esc_attr( $custom_height ); ?>" <?php $this->link( 'custom_height' ); ?> />
</file>

<file path="plugins/woocommerce/includes/customizer/class-wc-shop-customizer.php">
class WC_Shop_Customizer {
⋮----
public function __construct() {
⋮----
public function add_sections( $wp_customize ) {
$wp_customize->add_panel(
⋮----
$this->add_store_notice_section( $wp_customize );
$this->add_product_catalog_section( $wp_customize );
$this->add_product_images_section( $wp_customize );
$this->add_checkout_section( $wp_customize );
⋮----
public function add_frontend_scripts() {
⋮----
public function add_styles() {
if ( $this->has_block_checkout() ) {
⋮----
public function add_scripts() {
⋮----
/* translators: %d: Setting value */
⋮----
public function enqueue_scripts() {
⋮----
public function sanitize_archive_display( $value ) {
⋮----
/**
	 * Sanitize the catalog orderby setting.
	 *
	 * @param string $value An array key from the below array.
	 * @return string
... (44 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/abstract-wc-order-data-store-cpt.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Caches\OrderCache;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP implements WC_Abstract_Order_Data_Store_Interface, WC_Object_Data_Store_Interface {
⋮----
protected $meta_type = 'post';
⋮----
protected $internal_meta_keys = array(
⋮----
protected $internal_data_store_key_getters = array();
⋮----
public function get_internal_data_store_key_getters() {
⋮----
public function create( &$order ) {
$order->set_version( Constants::get_constant( 'WC_VERSION' ) );
$order->set_currency( $order->get_currency() ? $order->get_currency() : get_woocommerce_currency() );
if ( ! $order->get_date_created( 'edit' ) ) {
$order->set_date_created( time() );
⋮----
'post_date'     => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getOffsetTimestamp() ),
'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
'post_type'     => $order->get_type( 'edit' ),
'post_status'   => $this->get_post_status( $order ),
⋮----
'post_title'    => $this->get_post_title(),
'post_password' => $this->get_order_key( $order ),
'post_parent'   => $order->get_parent_id( 'edit' ),
... (277 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/abstract-wc-order-item-type-data-store.php">
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
⋮----
abstract class Abstract_WC_Order_Item_Type_Data_Store extends WC_Data_Store_WP implements WC_Object_Data_Store_Interface {
⋮----
protected $meta_type = 'order_item';
⋮----
protected $object_id_field_for_meta = 'order_item_id';
⋮----
private bool $cogs_is_enabled;
⋮----
private WC_Data_Store $order_item_data_store;
⋮----
public function __construct() {
$this->cogs_is_enabled = $this->cogs_is_enabled();
⋮----
$this->order_item_data_store = WC_Data_Store::load( 'order-item' );
⋮----
public function create( &$item ) {
⋮----
$wpdb->insert(
⋮----
'order_item_name' => $item->get_name(),
'order_item_type' => $item->get_type(),
'order_id'        => $item->get_order_id(),
⋮----
$item->set_id( $wpdb->insert_id );
$this->save_item_data( $item );
$item->save_meta_data();
⋮----
if ( $this->cogs_is_enabled && $item->has_cogs() ) {
... (65 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-coupon-data-store-cpt.php">
class WC_Coupon_Data_Store_CPT extends WC_Data_Store_WP implements WC_Coupon_Data_Store_Interface, WC_Object_Data_Store_Interface {
⋮----
protected $meta_type = 'post';
⋮----
protected $internal_meta_keys = array(
⋮----
protected $updated_props = array();
⋮----
public function create( &$coupon ) {
if ( ! $coupon->get_date_created( 'edit' ) ) {
$coupon->set_date_created( time() );
⋮----
'post_status'   => $coupon->get_status( 'edit' ) ? $coupon->get_status( 'edit' ) : 'publish',
⋮----
'post_title'    => $coupon->get_code( 'edit' ),
⋮----
'post_excerpt'  => $coupon->get_description( 'edit' ),
'post_date'     => gmdate( 'Y-m-d H:i:s', $coupon->get_date_created()->getOffsetTimestamp() ),
'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $coupon->get_date_created()->getTimestamp() ),
⋮----
$coupon->set_id( $coupon_id );
$this->update_post_meta( $coupon );
$coupon->save_meta_data();
$coupon->apply_changes();
⋮----
public function read( &$coupon ) {
$coupon->set_defaults();
⋮----
$post_object = get_post( $coupon->get_id() );
⋮----
... (182 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-customer-data-store-session.php">
class WC_Customer_Data_Store_Session extends WC_Data_Store_WP implements WC_Customer_Data_Store_Interface, WC_Object_Data_Store_Interface {
⋮----
protected $session_keys = array(
⋮----
public function create( &$customer ) {
$this->save_to_session( $customer );
⋮----
public function update( &$customer ) {
⋮----
public function save_to_session( $customer ) {
⋮----
$data = $this->get_customer_session_data( $customer );
⋮----
if ( $this->is_default_customer_data( $data ) ) {
⋮----
WC()->session->set( 'customer', null );
⋮----
WC()->session->set( 'customer', $data );
⋮----
public function read( &$customer ) {
$data = (array) WC()->session->get( 'customer' );
⋮----
if ( isset( $data['id'], $data['date_modified'] ) && $data['id'] === (string) $customer->get_id() && $data['date_modified'] === (string) $customer->get_date_modified( 'edit' ) ) {
⋮----
$customer->add_meta_data( $meta_data_value['key'], $meta_data_value['value'], true );
⋮----
$this->set_defaults( $customer );
$customer->set_object_read( true );
⋮----
protected function set_defaults( &$customer ) {
... (37 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-customer-data-store.php">
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\Internal\Utilities\Users;
⋮----
class WC_Customer_Data_Store extends WC_Data_Store_WP implements WC_Customer_Data_Store_Interface, WC_Object_Data_Store_Interface {
⋮----
protected $internal_meta_keys = array(
⋮----
protected $meta_type = 'user';
⋮----
protected function exclude_internal_meta_keys( $meta ) {
⋮----
public function create( &$customer ) {
$id = wc_create_new_customer( $customer->get_email(), $customer->get_username(), $customer->get_password() );
⋮----
throw new WC_Data_Exception( $id->get_error_code(), $id->get_error_message() );
⋮----
$customer->set_id( $id );
⋮----
if ( $wp_user->exists() ) {
$customer->set_username( $wp_user->user_login );
$customer->set_date_created( $wp_user->user_registered );
⋮----
$this->update_user_meta( $customer );
⋮----
$customer->set_password( '' );
⋮----
'ID'           => $customer->get_id(),
'role'         => $customer->get_role(),
'display_name' => $customer->get_display_name(),
... (130 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-customer-download-data-store.php">
class WC_Customer_Download_Data_Store implements WC_Customer_Download_Data_Store_Interface {
⋮----
public function create_from_data( $data ) {
⋮----
$id = $this->insert_new_download_permission( $data );
⋮----
public function create( &$download ) {
⋮----
if ( is_null( $download->get_access_granted( 'edit' ) ) ) {
$download->set_access_granted( time() );
⋮----
$inserted_id = $this->insert_new_download_permission( $data );
⋮----
$download->set_id( $inserted_id );
$download->apply_changes();
⋮----
private function insert_new_download_permission( $data ) {
⋮----
$data['access_granted'] = $this->adjust_date_for_db( $data['access_granted'] );
⋮----
$data['access_expires'] = $this->adjust_date_for_db( $data['access_expires'] );
⋮----
$result = $wpdb->insert(
⋮----
private function adjust_date_for_db( $date ) {
⋮----
$date = $date->getTimestamp();
⋮----
public function read( &$download ) {
⋮----
... (92 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-customer-download-log-data-store.php">
class WC_Customer_Download_Log_Data_Store implements WC_Customer_Download_Log_Data_Store_Interface {
⋮----
public static function get_table_name() {
⋮----
public function create( WC_Customer_Download_Log &$download_log ) {
⋮----
if ( is_null( $download_log->get_timestamp( 'edit' ) ) ) {
$download_log->set_timestamp( time() );
⋮----
'timestamp'       => date( 'Y-m-d H:i:s', $download_log->get_timestamp( 'edit' )->getTimestamp() ),
'permission_id'   => $download_log->get_permission_id( 'edit' ),
'user_id'         => $download_log->get_user_id( 'edit' ),
'user_ip_address' => $download_log->get_user_ip_address( 'edit' ),
⋮----
$result = $wpdb->insert(
$wpdb->prefix . self::get_table_name(),
⋮----
$download_log->set_id( $wpdb->insert_id );
$download_log->apply_changes();
⋮----
public function read( &$download_log ) {
⋮----
$download_log->set_defaults();
⋮----
if ( ! $download_log->get_id() ) {
⋮----
$table = $wpdb->prefix . self::get_table_name();
⋮----
$raw_download_log = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table} WHERE download_log_id = %d", $download_log->get_id() ) );
⋮----
... (40 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-data-store-wp.php">
class WC_Data_Store_WP {
⋮----
protected $meta_type = 'post';
⋮----
protected $object_id_field_for_meta = '';
⋮----
/**
	 * Data stored in meta keys, but not considered "meta" for an object.
	 *
	 * @since 3.0.0
	 *
	 * @var array
	 */
protected $internal_meta_keys = array();
⋮----
/**
	 * Meta data which should exist in the DB, even if empty.
	 *
	 * @since 3.6.0
	 *
	 * @var array
	 */
protected $must_exist_meta_keys = array();
⋮----
/**
	 * Get and store terms from a taxonomy.
	 *
	 * @since  3.0.0
	 * @param  WC_Data|integer $object WC_Data object or object ID.
	 * @param  string          $taxonomy Taxonomy name e.g. product_cat.
... (116 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-order-data-store-cpt.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\OrderInternalStatus;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
⋮----
class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implements WC_Object_Data_Store_Interface, WC_Order_Data_Store_Interface {
⋮----
protected $internal_meta_keys = array(
⋮----
protected $internal_data_store_key_getters = array(
⋮----
public function create( &$order ) {
if ( '' === $order->get_order_key() ) {
$order->set_order_key( wc_generate_order_key() );
⋮----
parent::create( $order );
⋮----
// Do not fire 'woocommerce_new_order' for draft statuses.
if ( in_array( $order->get_status( 'edit' ), array( OrderStatus::AUTO_DRAFT, OrderStatus::DRAFT, 'checkout-draft' ), true ) ) {
⋮----
do_action( 'woocommerce_new_order', $order->get_id(), $order );
⋮----
protected function read_order_data( &$order, $post_object ) {
parent::read_order_data( $order, $post_object );
$id = $order->get_id();
⋮----
$order->set_props(
⋮----
if ( $this->cogs_is_enabled() && $order->has_cogs() ) {
... (249 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-order-item-coupon-data-store.php">
class WC_Order_Item_Coupon_Data_Store extends Abstract_WC_Order_Item_Type_Data_Store implements WC_Object_Data_Store_Interface, WC_Order_Item_Type_Data_Store_Interface {
⋮----
protected $internal_meta_keys = array( 'discount_amount', 'discount_amount_tax' );
⋮----
public function read( &$item ) {
parent::read( $item );
$id = $item->get_id();
$item->set_props(
⋮----
$item->set_object_read( true );
⋮----
public function save_item_data( &$item ) {
$id          = $item->get_id();
⋮----
'discount_amount'     => $item->get_discount( 'edit' ),
'discount_amount_tax' => $item->get_discount_tax( 'edit' ),
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-order-item-data-store.php">
class WC_Order_Item_Data_Store implements WC_Order_Item_Data_Store_Interface {
⋮----
public function add_order_item( $order_id, $item ) {
⋮----
$wpdb->insert(
⋮----
$this->clear_caches( $item_id, $order_id );
⋮----
public function update_order_item( $item_id, $item ) {
⋮----
$updated = $wpdb->update( $wpdb->prefix . 'woocommerce_order_items', $item, array( 'order_item_id' => $item_id ) );
$this->clear_caches( $item_id, null );
⋮----
public function delete_order_item( $item_id ) {
⋮----
$order_id = $this->get_order_id_by_order_item_id( $item_id );
⋮----
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d", $item_id ) );
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d", $item_id ) );
⋮----
public function update_metadata( $item_id, $meta_key, $meta_value, $prev_value = '' ) {
⋮----
public function add_metadata( $item_id, $meta_key, $meta_value, $unique = false ) {
⋮----
public function delete_metadata( $item_id, $meta_key, $meta_value = '', $delete_all = false ) {
⋮----
public function get_metadata( $item_id, $key, $single = true ) {
⋮----
public function get_order_id_by_order_item_id( $item_id ) {
⋮----
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-order-item-fee-data-store.php">
class WC_Order_Item_Fee_Data_Store extends Abstract_WC_Order_Item_Type_Data_Store implements WC_Object_Data_Store_Interface, WC_Order_Item_Type_Data_Store_Interface {
⋮----
protected $internal_meta_keys = array( '_fee_amount', '_tax_class', '_tax_status', '_line_subtotal', '_line_subtotal_tax', '_line_total', '_line_tax', '_line_tax_data' );
⋮----
public function read( &$item ) {
parent::read( $item );
$id = $item->get_id();
$item->set_props(
⋮----
$item->set_object_read( true );
⋮----
public function save_item_data( &$item ) {
$id          = $item->get_id();
⋮----
'_fee_amount'    => $item->get_amount( 'edit' ),
'_tax_class'     => $item->get_tax_class( 'edit' ),
'_tax_status'    => $item->get_tax_status( 'edit' ),
'_line_total'    => $item->get_total( 'edit' ),
'_line_tax'      => $item->get_total_tax( 'edit' ),
'_line_tax_data' => $item->get_taxes( 'edit' ),
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-order-item-product-data-store.php">
class WC_Order_Item_Product_Data_Store extends Abstract_WC_Order_Item_Type_Data_Store implements WC_Object_Data_Store_Interface, WC_Order_Item_Product_Data_Store_Interface, WC_Order_Item_Type_Data_Store_Interface {
⋮----
protected $internal_meta_keys = array( '_product_id', '_variation_id', '_qty', '_tax_class', '_line_subtotal', '_line_subtotal_tax', '_line_total', '_line_tax', '_line_tax_data' );
⋮----
public function read( &$item ) {
parent::read( $item );
$id = $item->get_id();
$item->set_props(
⋮----
$item->set_object_read( true );
⋮----
public function save_item_data( &$item ) {
$id                = $item->get_id();
$changes           = $item->get_changes();
⋮----
$props_to_update   = $this->get_props_to_update( $item, $meta_key_to_props, 'order_item' );
⋮----
public function get_download_ids( $item, $order ) {
⋮----
return $wpdb->get_col(
$wpdb->prepare(
⋮----
$order->get_billing_email(),
$order->get_order_key(),
$item->get_variation_id() ? $item->get_variation_id() : $item->get_product_id()
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-order-item-shipping-data-store.php">
class WC_Order_Item_Shipping_Data_Store extends Abstract_WC_Order_Item_Type_Data_Store implements WC_Object_Data_Store_Interface, WC_Order_Item_Type_Data_Store_Interface {
⋮----
protected $internal_meta_keys = array( 'method_id', 'instance_id', 'cost', 'total_tax', 'taxes' );
⋮----
public function read( &$item ) {
parent::read( $item );
$id = $item->get_id();
$item->set_props(
⋮----
if ( '' === $item->get_instance_id() && strstr( $item->get_method_id(), ':' ) ) {
$legacy_method_id = explode( ':', $item->get_method_id() );
$item->set_method_id( $legacy_method_id[0] );
$item->set_instance_id( $legacy_method_id[1] );
⋮----
$item->set_object_read( true );
⋮----
/**
	 * Saves an item's data to the database / item meta.
	 * Ran after both create and update, so $id will be set.
	 *
	 * @since 3.0.0
	 * @param WC_Order_Item_Shipping $item Item to save.
	 */
public function save_item_data( &$item ) {
$id                = $item->get_id();
$changes           = $item->get_changes();
⋮----
$props_to_update   = $this->get_props_to_update( $item, $meta_key_to_props, 'order_item' );
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-order-item-tax-data-store.php">
class WC_Order_Item_Tax_Data_Store extends Abstract_WC_Order_Item_Type_Data_Store implements WC_Object_Data_Store_Interface, WC_Order_Item_Type_Data_Store_Interface {
⋮----
protected $internal_meta_keys = array( 'rate_id', 'label', 'compound', 'tax_amount', 'shipping_tax_amount', 'rate_percent' );
⋮----
public function read( &$item ) {
parent::read( $item );
$id = $item->get_id();
$item->set_props(
⋮----
$item->set_object_read( true );
⋮----
public function save_item_data( &$item ) {
$id                = $item->get_id();
$changes           = $item->get_changes();
⋮----
$props_to_update   = $this->get_props_to_update( $item, $meta_key_to_props, 'order_item' );
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-order-refund-data-store-cpt.php">
class WC_Order_Refund_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implements WC_Object_Data_Store_Interface, WC_Order_Refund_Data_Store_Interface {
⋮----
protected $internal_meta_keys = array(
⋮----
public function delete( &$order, $args = array() ) {
$id = $order->get_id();
⋮----
$parent_order_id  = $order->get_parent_id();
$refund_cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'refund_ids' . $parent_order_id;
⋮----
$order->set_id( 0 );
⋮----
protected function read_order_data( &$refund, $post_object ) {
parent::read_order_data( $refund, $post_object );
$id = $refund->get_id();
⋮----
$refund->set_props(
⋮----
public function update( &$refund ) {
parent::update( $refund );
⋮----
do_action( 'woocommerce_update_order_refund', $refund->get_id(), $refund );
⋮----
protected function update_post_meta( &$refund ) {
parent::update_post_meta( $refund );
⋮----
$props_to_update = $this->get_props_to_update( $refund, $meta_key_to_props );
⋮----
update_post_meta( $refund->get_id(), $meta_key, $value );
⋮----
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-payment-token-data-store.php">
class WC_Payment_Token_Data_Store extends WC_Data_Store_WP implements WC_Object_Data_Store_Interface, WC_Payment_Token_Data_Store_Interface {
⋮----
protected $meta_type = 'payment_token';
⋮----
protected $extra_data_saved = false;
⋮----
public function create( &$token ) {
if ( false === $token->validate() ) {
⋮----
if ( ! $token->is_default() && $token->get_user_id() > 0 ) {
$default_token = WC_Payment_Tokens::get_customer_default_token( $token->get_user_id() );
⋮----
$token->set_default( true );
⋮----
'gateway_id' => $token->get_gateway_id( 'edit' ),
'token'      => $token->get_token( 'edit' ),
'user_id'    => $token->get_user_id( 'edit' ),
'type'       => $token->get_type( 'edit' ),
⋮----
$wpdb->insert( $wpdb->prefix . 'woocommerce_payment_tokens', $payment_token_data );
⋮----
$token->set_id( $token_id );
$this->save_extra_data( $token, true );
$token->save_meta_data();
$token->apply_changes();
⋮----
if ( $token->is_default() && $token->get_user_id() > 0 ) {
WC_Payment_Tokens::set_users_default( $token->get_user_id(), $token_id );
⋮----
public function update( &$token ) {
... (70 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Caches\ProductCache;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\CatalogVisibility;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
use Automattic\WooCommerce\Internal\DownloadPermissionsAdjuster;
use Automattic\WooCommerce\Utilities\NumberUtil;
use Automattic\WooCommerce\Enums\ProductStockStatus;
⋮----
class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Data_Store_Interface, WC_Product_Data_Store_Interface {
⋮----
protected $internal_meta_keys = array(
⋮----
protected $must_exist_meta_keys = array(
⋮----
protected $extra_data_saved = false;
⋮----
protected $updated_props = array();
⋮----
private function obtain_lock_on_sku_for_concurrent_requests( $product ) {
⋮----
$product_id = $product->get_id();
$sku        = $product->get_sku();
⋮----
$query = $wpdb->prepare(
⋮----
$result = $wpdb->query( $query );
⋮----
wc_get_logger()->warning(
... (592 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-product-grouped-data-store-cpt.php">
class WC_Product_Grouped_Data_Store_CPT extends WC_Product_Data_Store_CPT implements WC_Object_Data_Store_Interface {
⋮----
protected function update_post_meta( &$product, $force = false ) {
⋮----
$props_to_update = $force ? $meta_key_to_props : $this->get_props_to_update( $product, $meta_key_to_props );
⋮----
$updated = update_post_meta( $product->get_id(), $meta_key, $value );
⋮----
parent::update_post_meta( $product, $force );
⋮----
protected function handle_updated_props( &$product ) {
⋮----
$this->update_prices_from_children( $product );
⋮----
parent::handle_updated_props( $product );
⋮----
public function sync_price( &$product ) {
⋮----
protected function update_prices_from_children( &$product ) {
$product_id   = $product->get_id();
⋮----
$child_ids = $product->get_children( 'edit' );
⋮----
$child_prices[] = $child->get_price( 'edit' );
⋮----
$this->update_lookup_table( $product_id, 'wc_product_meta_lookup' );
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php">
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
use Automattic\WooCommerce\Internal\Caches\ProductVersionStringInvalidator;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use Automattic\WooCommerce\Utilities\CallbackUtil;
⋮----
class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT implements WC_Object_Data_Store_Interface, WC_Product_Variable_Data_Store_Interface {
⋮----
protected $prices_array = array();
⋮----
protected function read_attributes( &$product ) {
$product_id      = $product->get_id();
⋮----
$child_ids = $product->get_children();
⋮----
$old_meta_rows       = $wpdb->get_results(
$wpdb->prepare(
⋮----
$attribute->set_id( $id );
$attribute->set_name( $meta_value['name'] );
$attribute->set_options( $options );
$attribute->set_position( $meta_value['position'] );
$attribute->set_visible( $meta_value['is_visible'] );
$attribute->set_variation( $meta_value['is_variation'] );
⋮----
$product->set_attributes( $attributes );
⋮----
$this->update_attributes( $product, true );
⋮----
... (192 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-product-variation-data-store-cpt.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\CatalogVisibility;
use Automattic\WooCommerce\Enums\ProductStockStatus;
⋮----
class WC_Product_Variation_Data_Store_CPT extends WC_Product_Data_Store_CPT implements WC_Object_Data_Store_Interface {
⋮----
protected function exclude_internal_meta_keys( $meta ) {
⋮----
public function read( &$product ) {
$product->set_defaults();
⋮----
if ( ! $product->get_id() ) {
⋮----
$post_object = get_post( $product->get_id() );
⋮----
$product->set_props(
⋮----
'date_created'      => $this->string_to_timestamp( $post_object->post_date_gmt ),
'date_modified'     => $this->string_to_timestamp( $post_object->post_modified_gmt ),
⋮----
if ( $product->get_parent_id( 'edit' ) && 'product' !== get_post_type( $product->get_parent_id( 'edit' ) ) ) {
$product->set_parent_id( 0 );
⋮----
$this->read_downloads( $product );
$this->read_product_data( $product );
$this->read_extra_data( $product );
$product->set_attributes( wc_get_product_variation_attributes( $product->get_id() ) );
⋮----
$new_title = $this->generate_product_title( $product );
... (183 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-shipping-zone-data-store.php">
class WC_Shipping_Zone_Data_Store extends WC_Data_Store_WP implements WC_Object_Data_Store_Interface, WC_Shipping_Zone_Data_Store_Interface {
⋮----
public function create( &$zone ) {
⋮----
$wpdb->insert(
⋮----
'zone_name'  => $zone->get_zone_name(),
'zone_order' => $zone->get_zone_order(),
⋮----
$zone->set_id( $wpdb->insert_id );
$zone->save_meta_data();
$this->save_locations( $zone );
$zone->apply_changes();
WC_Cache_Helper::invalidate_cache_group( 'shipping_zones' );
WC_Cache_Helper::get_transient_version( 'shipping', true );
⋮----
public function update( &$zone ) {
⋮----
if ( $zone->get_id() ) {
$wpdb->update(
⋮----
array( 'zone_id' => $zone->get_id() )
⋮----
public function read( &$zone ) {
$zones = array( $zone->get_id() => $zone );
$this->read_multiple( $zones );
⋮----
public function read_multiple( array &$zones ) {
⋮----
$zone_data = $this->get_zone_data_for_ids( $zone_ids );
... (90 lines truncated)
</file>

<file path="plugins/woocommerce/includes/data-stores/class-wc-webhook-data-store.php">
class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
⋮----
public function create( &$webhook ) {
⋮----
$changes = $webhook->get_changes();
⋮----
$date_created     = $webhook->get_date_created()->date( 'Y-m-d H:i:s' );
$date_created_gmt = gmdate( 'Y-m-d H:i:s', $webhook->get_date_created()->getTimestamp() );
⋮----
$webhook->set_date_created( $date_created );
⋮----
$webhook->set_pending_delivery( true );
⋮----
'status'           => $webhook->get_status( 'edit' ),
'name'             => $webhook->get_name( 'edit' ),
'user_id'          => $webhook->get_user_id( 'edit' ),
'delivery_url'     => $webhook->get_delivery_url( 'edit' ),
'secret'           => $webhook->get_secret( 'edit' ),
'topic'            => $webhook->get_topic( 'edit' ),
⋮----
'api_version'      => $this->get_api_version_number( $webhook->get_api_version( 'edit' ) ),
'failure_count'    => $webhook->get_failure_count( 'edit' ),
'pending_delivery' => $webhook->get_pending_delivery( 'edit' ),
⋮----
$wpdb->insert( $wpdb->prefix . 'wc_webhooks', $data );
⋮----
$webhook->set_id( $webhook_id );
$webhook->apply_changes();
⋮----
$this->delete_transients( $webhook->get_status( 'edit' ) );
... (100 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-admin-payment-gateway-enabled.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Email_Admin_Payment_Gateway_Enabled extends WC_Email {
⋮----
public $gateway_title = '';
⋮----
/**
		 * Gateway settings URL.
		 *
		 * @var string
		 */
public $gateway_settings_url = '';
⋮----
/**
		 * Admin username.
		 *
		 * @var string
		 */
public $username = '';
⋮----
/**
		 * Admin email address.
		 *
		 * @var string
		 */
public $admin_email = '';
⋮----
/**
		 * Constructor.
		 */
... (57 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-cancelled-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Email_Cancelled_Order extends WC_Email {
⋮----
public function __construct() {
⋮----
// Triggers for this email.
⋮----
parent::__construct();
⋮----
$this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) );
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function trigger( $order_id, $order = false ) {
$this->setup_locale();
⋮----
$this->placeholders['{order_date}']              = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}']            = $this->object->get_order_number();
$this->placeholders['{order_billing_full_name}'] = $this->object->get_formatted_billing_full_name();
⋮----
$this->send_notification();
⋮----
$this->restore_locale();
⋮----
public function get_content_html() {
⋮----
'email_heading'      => $this->get_heading(),
... (24 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-cancelled-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Email_Customer_Cancelled_Order extends WC_Email {
⋮----
public function __construct() {
⋮----
// Triggers for this email.
⋮----
parent::__construct();
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function trigger( $order_id, $order = false ) {
$this->setup_locale();
⋮----
$this->recipient                                 = $this->object->get_billing_email();
$this->placeholders['{order_date}']              = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}']            = $this->object->get_order_number();
$this->placeholders['{order_billing_full_name}'] = $this->object->get_formatted_billing_full_name();
⋮----
$this->send_notification();
⋮----
$this->restore_locale();
⋮----
public function get_content_html() {
⋮----
'email_heading'      => $this->get_heading(),
'additional_content' => $this->get_additional_content(),
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-completed-order.php">
class WC_Email_Customer_Completed_Order extends WC_Email {
⋮----
public function __construct() {
⋮----
// Triggers for this email.
⋮----
parent::__construct();
⋮----
public function trigger( $order_id, $order = false ) {
$this->setup_locale();
⋮----
$this->recipient                      = $this->object->get_billing_email();
$this->placeholders['{order_date}']   = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
⋮----
$this->send_notification();
⋮----
$this->restore_locale();
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function get_content_html() {
⋮----
'email_heading'      => $this->get_heading(),
'additional_content' => $this->get_additional_content(),
⋮----
public function get_content_plain() {
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-failed-order.php">
class WC_Email_Customer_Failed_Order extends WC_Email {
⋮----
public function __construct() {
⋮----
// Triggers for this email.
⋮----
parent::__construct();
⋮----
public function trigger( $order_id, $order = false ) {
$this->setup_locale();
⋮----
$this->recipient                      = $this->object->get_billing_email();
$this->placeholders['{order_date}']   = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
⋮----
$this->send_notification();
⋮----
$this->restore_locale();
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function get_content_html() {
⋮----
'email_heading'      => $this->get_heading(),
'additional_content' => $this->get_additional_content(),
'blogname'           => $this->get_blogname(),
⋮----
public function get_content_plain() {
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-fulfillment-created.php">
use Automattic\WooCommerce\Admin\Features\Fulfillments\Fulfillment;
⋮----
class WC_Email_Customer_Fulfillment_Created extends WC_Email {
⋮----
private $fulfillment;
⋮----
public function __construct() {
⋮----
// Triggers for this email.
⋮----
parent::__construct();
⋮----
public function trigger( $order_id, $fulfillment, $order = false ) {
$this->setup_locale();
⋮----
$this->recipient                      = $this->object->get_billing_email();
$this->placeholders['{order_date}']   = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
⋮----
$this->send_notification();
⋮----
$this->restore_locale();
⋮----
private function get_fulfillment_item_count() {
⋮----
$this->fulfillment->get_items(),
⋮----
public function get_default_subject() {
if ( $this->get_fulfillment_item_count() > 1 ) {
⋮----
... (29 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-fulfillment-deleted.php">
use Automattic\WooCommerce\Admin\Features\Fulfillments\Fulfillment;
⋮----
class WC_Email_Customer_Fulfillment_Deleted extends WC_Email {
⋮----
private $fulfillment;
⋮----
public function __construct() {
⋮----
// Triggers for this email.
⋮----
parent::__construct();
⋮----
public function trigger( $order_id, $fulfillment, $order = false ) {
$this->setup_locale();
⋮----
$this->recipient                      = $this->object->get_billing_email();
$this->placeholders['{order_date}']   = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
⋮----
$this->send_notification();
⋮----
$this->restore_locale();
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function get_content_html() {
$this->maybe_init_fulfillment_for_preview( $this->object );
⋮----
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-fulfillment-updated.php">
use Automattic\WooCommerce\Admin\Features\Fulfillments\Fulfillment;
⋮----
class WC_Email_Customer_Fulfillment_Updated extends WC_Email {
⋮----
private $fulfillment;
⋮----
private $customer_note = '';
⋮----
/**
		 * Constructor.
		 */
public function __construct() {
⋮----
// Triggers for this email.
⋮----
parent::__construct();
⋮----
public function trigger( $order_id, $fulfillment, $order = false, $customer_note = '' ) {
$this->setup_locale();
⋮----
$this->recipient                      = $this->object->get_billing_email();
$this->placeholders['{order_date}']   = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
⋮----
$this->send_notification();
⋮----
$this->restore_locale();
⋮----
public function get_default_subject() {
⋮----
... (29 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-invoice.php">
use Automattic\WooCommerce\EmailEditor\Engine\Personalizer;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Email_Customer_Invoice extends WC_Email {
⋮----
public function __construct() {
⋮----
// Call parent constructor.
parent::__construct();
⋮----
// Must be after parent's constructor which sets `email_improvements_enabled` property.
⋮----
public function get_default_subject( $paid = false ) {
⋮----
public function get_default_heading( $paid = false ) {
⋮----
public function get_subject() {
if ( $this->object->has_status( array( OrderStatus::COMPLETED, OrderStatus::PROCESSING ) ) ) {
$subject = $this->get_option( 'subject_paid', $this->get_default_subject( true ) );
⋮----
$subject = $this->personalizer->personalize_transactional_content( $subject, $this, Personalizer::RENDERING_CONTEXT_TEXT );
⋮----
return apply_filters( 'woocommerce_email_subject_customer_invoice_paid', $this->format_string( $subject ), $this->object, $this );
⋮----
$subject = $this->get_option( 'subject', $this->get_default_subject() );
⋮----
return apply_filters( 'woocommerce_email_subject_customer_invoice', $this->format_string( $subject ), $this->object, $this );
⋮----
public function get_heading() {
... (47 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-new-account.php">
class WC_Email_Customer_New_Account extends WC_Email {
⋮----
public $user_login;
⋮----
public $user_email;
⋮----
public $user_pass;
⋮----
public $password_generated;
⋮----
public $set_password_url;
⋮----
public $user_display_name;
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function trigger( $user_id, $user_pass = '', $password_generated = false ) {
$this->setup_locale();
⋮----
$this->set_password_url   = $this->generate_set_password_url();
⋮----
$first_name               = ! empty( $customer->get_billing_first_name() ) ? $customer->get_billing_first_name() : $this->object->first_name;
⋮----
$this->send_notification();
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-note.php">
class WC_Email_Customer_Note extends WC_Email {
⋮----
public $customer_note;
⋮----
public function __construct() {
⋮----
// Triggers.
⋮----
parent::__construct();
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function trigger( $args ) {
$this->setup_locale();
⋮----
$this->recipient                      = $this->object->get_billing_email();
⋮----
$this->placeholders['{order_date}']   = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
⋮----
$this->send_notification();
⋮----
$this->restore_locale();
⋮----
public function get_content_html() {
⋮----
'email_heading'      => $this->get_heading(),
'additional_content' => $this->get_additional_content(),
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-on-hold-order.php">
class WC_Email_Customer_On_Hold_Order extends WC_Email {
⋮----
public function __construct() {
⋮----
// Triggers for this email.
⋮----
parent::__construct();
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function trigger( $order_id, $order = false ) {
$this->setup_locale();
⋮----
$this->recipient                      = $this->object->get_billing_email();
$this->placeholders['{order_date}']   = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
⋮----
$this->send_notification();
⋮----
$this->restore_locale();
⋮----
public function get_content_html() {
⋮----
'email_heading'      => $this->get_heading(),
'additional_content' => $this->get_additional_content(),
⋮----
public function get_content_plain() {
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-order-withdrawal-requested.php">
use Automattic\WooCommerce\Internal\OrderWithdrawal\Emails\OrderWithdrawalEmailDataFormatter;
use Automattic\WooCommerce\Internal\OrderWithdrawal\OrderWithdrawalFormProcessor;
⋮----
class WC_Email_Customer_Order_Withdrawal_Requested extends WC_Email {
⋮----
public array $withdrawal_data = array();
⋮----
public int $submitted_at = 0;
⋮----
private OrderWithdrawalEmailDataFormatter $formatter;
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
/**
		 * Get email subject.
		 *
		 * @return string
		 */
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function get_default_additional_content() {
⋮----
public function trigger( array $data, int $submitted_at ): bool {
$this->setup_locale();
⋮----
$data = $this->formatter->normalize_withdrawal_data( $data );
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-partially-refunded-order.php">
use Automattic\WooCommerce\EmailEditor\Engine\Personalizer;
⋮----
class WC_Email_Customer_Partially_Refunded_Order extends WC_Email_Customer_Refunded_Order {
⋮----
public function __construct() {
parent::__construct();
⋮----
public function get_block_editor_email_template_content() {
⋮----
public function get_subject() {
$subject = $this->get_option( 'subject_partial', $this->get_default_subject( true ) );
⋮----
$subject = apply_filters( 'woocommerce_email_subject_customer_refunded_order', $this->format_string( $subject ), $this->object, $this );
⋮----
$subject = $this->personalizer->personalize_transactional_content( $subject, $this, Personalizer::RENDERING_CONTEXT_TEXT );
⋮----
public function get_option_key() {
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-pos-completed-order.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\Email\OrderPriceFormatter;
use Automattic\WooCommerce\Internal\Orders\PointOfSaleOrderUtil;
use Automattic\WooCommerce\Internal\Settings\PointOfSaleDefaultSettings;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Email_Customer_POS_Completed_Order extends WC_Email {
⋮----
public function __construct() {
⋮----
$this->enable_order_email_actions_for_pos_orders();
⋮----
// Call parent constructor.
parent::__construct();
⋮----
// Must be after parent's constructor which sets `email_improvements_enabled` property.
⋮----
public function trigger( $order_id, $template_id ) {
⋮----
$this->setup_locale();
⋮----
$this->recipient                      = $this->object->get_billing_email();
$this->placeholders['{order_date}']   = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
⋮----
$this->send_if_recipient();
⋮----
$this->restore_locale();
⋮----
public function get_default_subject() {
... (103 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-pos-refunded-order.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\Email\OrderPriceFormatter;
use Automattic\WooCommerce\Internal\Orders\PointOfSaleOrderUtil;
use Automattic\WooCommerce\Internal\Settings\PointOfSaleDefaultSettings;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Email_Customer_POS_Refunded_Order extends WC_Email {
⋮----
public $refund;
⋮----
public $partial_refund;
⋮----
public function __construct() {
⋮----
$this->enable_order_email_actions();
⋮----
// Call parent constructor.
parent::__construct();
⋮----
// Must be after parent's constructor which sets `email_improvements_enabled` property.
⋮----
public function get_default_subject( $partial = false ) {
$store_name = $this->get_pos_store_name();
⋮----
public function get_default_heading( $partial = false ) {
⋮----
public function get_subject() {
⋮----
$subject = $this->get_option( 'subject_partial', $this->get_default_subject( true ) );
⋮----
... (131 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-processing-order.php">
class WC_Email_Customer_Processing_Order extends WC_Email {
⋮----
public function __construct() {
⋮----
// Triggers for this email.
⋮----
parent::__construct();
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function trigger( $order_id, $order = false ) {
$this->setup_locale();
⋮----
$this->recipient                      = $this->object->get_billing_email();
$this->placeholders['{order_date}']   = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
⋮----
$this->send_notification();
⋮----
$this->restore_locale();
⋮----
public function get_content_html() {
⋮----
'email_heading'      => $this->get_heading(),
'additional_content' => $this->get_additional_content(),
⋮----
public function get_content_plain() {
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-refunded-order.php">
use Automattic\WooCommerce\EmailEditor\Engine\Personalizer;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Email_Customer_Refunded_Order extends WC_Email {
⋮----
public $refund;
⋮----
public $partial_refund;
⋮----
public function __construct() {
⋮----
// Triggers for this email.
⋮----
parent::__construct();
⋮----
public function get_default_subject( $partial = false ) {
⋮----
public function get_default_heading( $partial = false ) {
⋮----
public function get_subject() {
⋮----
$subject = $this->get_option( 'subject_partial', $this->get_default_subject( true ) );
⋮----
$subject = $this->get_option( 'subject_full', $this->get_default_subject() );
⋮----
$subject = apply_filters( 'woocommerce_email_subject_customer_refunded_order', $this->format_string( $subject ), $this->object, $this );
⋮----
$subject = $this->personalizer->personalize_transactional_content( $subject, $this, Personalizer::RENDERING_CONTEXT_TEXT );
⋮----
public function get_heading() {
... (58 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-reset-password.php">
class WC_Email_Customer_Reset_Password extends WC_Email {
⋮----
public $user_id;
⋮----
public $user_login;
⋮----
public $user_email;
⋮----
public $reset_key;
⋮----
public $user_display_name;
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function trigger( $user_login = '', $reset_key = '' ) {
$this->setup_locale();
⋮----
$this->restore_locale();
⋮----
$first_name              = ! empty( $customer->get_billing_first_name() ) ? $customer->get_billing_first_name() : $this->object->first_name;
⋮----
$this->send_notification();
⋮----
public function get_content_html() {
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-customer-review-request.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\OrderReviews\ItemEligibility;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Email_Customer_Review_Request extends WC_Email {
⋮----
public function __construct() {
⋮----
// Trigger fires via WC_Emails' transactional pipeline after Action Scheduler fires `woocommerce_send_review_request`.
⋮----
parent::__construct();
⋮----
public function trigger( $order_id ): void {
$this->setup_locale();
⋮----
$this->recipient                      = $order->get_billing_email();
$date_created                         = $order->get_date_created();
⋮----
$this->placeholders['{order_number}'] = $order->get_order_number();
⋮----
if ( $this->is_enabled() && $this->get_recipient() && $this->is_order_eligible_for_send() ) {
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
⋮----
$this->restore_locale();
⋮----
/**
		 * Defence-in-depth status check at send time.
		 *
		 * The scheduler unschedules the pending action when the order leaves
		 * `completed`, but a race window or a direct invocation of the action
... (102 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-failed-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Email_Failed_Order extends WC_Email {
⋮----
public function __construct() {
⋮----
// Triggers for this email.
⋮----
parent::__construct();
⋮----
$this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) );
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function trigger( $order_id, $order = false ) {
$this->setup_locale();
⋮----
$this->placeholders['{order_date}']   = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
⋮----
$this->send_notification();
⋮----
$this->restore_locale();
⋮----
public function get_content_html() {
⋮----
'email_heading'      => $this->get_heading(),
'additional_content' => $this->get_additional_content(),
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-new-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Email_New_Order extends WC_Email {
⋮----
public function __construct() {
⋮----
// Triggers for this email.
⋮----
parent::__construct();
⋮----
$this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) );
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function trigger( $order_id, $order = false ) {
$this->setup_locale();
⋮----
$this->placeholders['{order_date}']   = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
⋮----
$email_already_sent = $order->get_new_order_email_sent();
⋮----
$this->restore_locale();
⋮----
$email_sent_successfully = $this->send_notification();
⋮----
$order->update_meta_data( '_new_order_email_sent', 'true' );
$order->save();
... (32 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email-order-withdrawal-requested.php">
use Automattic\WooCommerce\Internal\OrderWithdrawal\Emails\OrderWithdrawalEmailDataFormatter;
use Automattic\WooCommerce\Internal\OrderWithdrawal\OrderWithdrawalFormProcessor;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Email_Order_Withdrawal_Requested extends WC_Email {
⋮----
public array $withdrawal_data = array();
⋮----
public ?WC_Order $matched_order = null;
⋮----
public int $submitted_at = 0;
⋮----
public bool $outside_withdrawal_window = false;
⋮----
public string $withdrawal_window_warning = '';
⋮----
/**
		 * Data formatter.
		 *
		 * @var OrderWithdrawalEmailDataFormatter
		 */
private OrderWithdrawalEmailDataFormatter $formatter;
⋮----
/**
		 * Constructor.
		 */
public function __construct() {
⋮----
parent::__construct();
⋮----
... (52 lines truncated)
</file>

<file path="plugins/woocommerce/includes/emails/class-wc-email.php">
use Automattic\WooCommerce\EmailEditor\Engine\Personalizer;
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
use Automattic\WooCommerce\Internal\EmailEditor\TransactionalEmailPersonalizer;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use Automattic\WooCommerce\Vendor\Pelago\Emogrifier\CssInliner;
use Automattic\WooCommerce\Vendor\Pelago\Emogrifier\HtmlProcessor\CssToAttributeConverter;
use Automattic\WooCommerce\Vendor\Pelago\Emogrifier\HtmlProcessor\HtmlPruner;
⋮----
class WC_Email extends WC_Settings_API {
⋮----
public $id;
⋮----
public $title;
⋮----
public $enabled;
⋮----
public $description;
⋮----
public $heading = '';
⋮----
/**
	 * Default subject.
	 *
	 * Supported for backwards compatibility but we recommend overloading the
	 * get_default_x methods instead so localization can be done when needed.
	 *
	 * @var string
	 */
public $subject = '';
⋮----
... (585 lines truncated)
</file>

<file path="plugins/woocommerce/includes/export/abstract-wc-csv-batch-exporter.php">
abstract class WC_CSV_Batch_Exporter extends WC_CSV_Exporter {
⋮----
protected $page = 1;
⋮----
public function __construct() {
$this->column_names = $this->get_default_column_names();
⋮----
protected function get_file_path() {
⋮----
return trailingslashit( $upload_dir['basedir'] ) . $this->get_filename();
⋮----
protected function get_headers_row_file_path() {
return $this->get_file_path() . '.headers';
⋮----
public function get_headers_row_file() {
⋮----
$file = chr( 239 ) . chr( 187 ) . chr( 191 ) . $this->export_column_headers();
⋮----
if ( @file_exists( $this->get_headers_row_file_path() ) ) {
$file = @file_get_contents( $this->get_headers_row_file_path() );
⋮----
public function get_file() {
⋮----
if ( @file_exists( $this->get_file_path() ) ) { // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
$file = @file_get_contents( $this->get_file_path() ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents, WordPress.WP.AlternativeFunctions.file_system_read_file_get_contents
⋮----
@file_put_contents( $this->get_file_path(), '' ); // phpcs:ignore WordPress.VIP.FileSystemWritesDisallow.file_ops_file_put_contents, Generic.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
@chmod( $this->get_file_path(), 0664 ); // phpcs:ignore WordPress.VIP.FileSystemWritesDisallow.chmod_chmod, WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents, Generic.PHP.NoSilencedErrors.Discouraged
⋮----
/**
... (58 lines truncated)
</file>

<file path="plugins/woocommerce/includes/export/abstract-wc-csv-exporter.php">
abstract class WC_CSV_Exporter {
⋮----
protected $export_type = '';
⋮----
/**
	 * Filename to export to.
	 *
	 * @var string
	 */
protected $filename = 'wc-export.csv';
⋮----
protected $limit = 50;
⋮----
protected $exported_row_count = 0;
⋮----
protected $row_data = array();
⋮----
protected $total_rows = 0;
⋮----
protected $column_names = array();
⋮----
protected $columns_to_export = array();
⋮----
protected $delimiter = ',';
⋮----
abstract public function prepare_data_to_export();
⋮----
public function get_column_names() {
⋮----
public function set_column_names( $column_names ) {
... (132 lines truncated)
</file>

<file path="plugins/woocommerce/includes/export/class-wc-product-csv-exporter.php">
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
use Automattic\WooCommerce\Utilities\I18nUtil;
⋮----
class WC_Product_CSV_Exporter extends WC_CSV_Batch_Exporter {
⋮----
protected $export_type = 'product';
⋮----
protected $enable_meta_export = false;
⋮----
protected $product_types_to_export = array();
⋮----
protected $product_category_to_export = array();
⋮----
protected $product_ids_to_export = array();
⋮----
public function __construct() {
parent::__construct();
$this->set_product_types_to_export( array_keys( WC_Admin_Exporters::get_product_types() ) );
⋮----
public function enable_meta_export( $enable_meta_export ) {
⋮----
public function set_product_types_to_export( $product_types_to_export ) {
⋮----
public function set_product_category_to_export( $product_category_to_export ) {
⋮----
public function set_product_ids_to_export( $product_ids ) {
⋮----
... (196 lines truncated)
</file>

<file path="plugins/woocommerce/includes/gateways/bacs/class-wc-gateway-bacs.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\Admin\Settings\Utils as SettingsUtils;
⋮----
class WC_Gateway_BACS extends WC_Payment_Gateway {
⋮----
public $locale;
⋮----
public $instructions;
⋮----
public $account_details;
⋮----
public function __construct() {
⋮----
$this->init_form_fields();
$this->init_settings();
⋮----
$this->title        = $this->get_option( 'title' );
$this->description  = $this->get_option( 'description' );
$this->instructions = $this->get_option( 'instructions' );
⋮----
'account_name'   => $this->get_option( 'account_name' ),
'account_number' => $this->get_option( 'account_number' ),
'sort_code'      => $this->get_option( 'sort_code' ),
'bank_name'      => $this->get_option( 'bank_name' ),
'iban'           => $this->get_option( 'iban' ),
'bic'            => $this->get_option( 'bic' ),
⋮----
public function init_form_fields() {
⋮----
public function generate_account_details_html() {
... (54 lines truncated)
</file>

<file path="plugins/woocommerce/includes/gateways/cheque/class-wc-gateway-cheque.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\Admin\Settings\Utils as SettingsUtils;
⋮----
class WC_Gateway_Cheque extends WC_Payment_Gateway {
⋮----
public $instructions;
⋮----
public function __construct() {
⋮----
$this->init_form_fields();
$this->init_settings();
⋮----
$this->title        = $this->get_option( 'title' );
$this->description  = $this->get_option( 'description' );
$this->instructions = $this->get_option( 'instructions' );
⋮----
public function init_form_fields() {
⋮----
public function thankyou_page() {
⋮----
public function email_instructions( $order, $sent_to_admin, $plain_text = false ) {
if ( $this->instructions && ! $sent_to_admin && self::ID === $order->get_payment_method() ) {
⋮----
if ( $order->has_status( $instructions_order_status ) ) {
⋮----
public function process_payment( $order_id ) {
⋮----
if ( $order->get_total() > 0 ) {
⋮----
$order->update_status( $process_payment_status, _x( 'Awaiting check payment.', 'Check payment method', 'woocommerce' ) );
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/includes/gateways/cod/class-wc-gateway-cod.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\Admin\Settings\Utils as SettingsUtils;
⋮----
class WC_Gateway_COD extends WC_Payment_Gateway {
⋮----
public $instructions;
⋮----
public $enable_for_methods;
⋮----
public $enable_for_virtual;
⋮----
public function __construct() {
⋮----
$this->setup_properties();
⋮----
$this->init_form_fields();
$this->init_settings();
⋮----
$this->title              = $this->get_option( 'title' );
$this->description        = $this->get_option( 'description' );
$this->instructions       = $this->get_option( 'instructions' );
$this->enable_for_methods = $this->get_option( 'enable_for_methods', array() );
$this->enable_for_virtual = $this->get_option( 'enable_for_virtual', 'yes' ) === 'yes';
⋮----
protected function setup_properties() {
⋮----
public function init_form_fields() {
⋮----
'options'           => $this->load_shipping_method_options(),
... (76 lines truncated)
</file>

<file path="plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-api-handler.php">
class WC_Gateway_Paypal_API_Handler {
⋮----
public static $api_username;
⋮----
public static $api_password;
⋮----
public static $api_signature;
⋮----
public static $sandbox = false;
⋮----
public static function get_capture_request( $order, $amount = null ) {
⋮----
'AUTHORIZATIONID' => $order->get_transaction_id(),
'AMT'             => number_format( is_null( $amount ) ? $order->get_total() : $amount, 2, '.', '' ),
'CURRENCYCODE'    => $order->get_currency(),
⋮----
public static function get_refund_request( $order, $amount = null, $reason = '' ) {
⋮----
'TRANSACTIONID' => $order->get_transaction_id(),
⋮----
$request['CURRENCYCODE'] = $order->get_currency();
⋮----
public static function do_capture( $order, $amount = null ) {
⋮----
'body'        => self::get_capture_request( $order, $amount ),
⋮----
WC_Gateway_Paypal::log( 'DoCapture Response: ' . wc_print_r( $raw_response, true ) );
⋮----
public static function refund_transaction( $order, $amount = null, $reason = '' ) {
⋮----
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-constants.php">
use Automattic\WooCommerce\Gateways\PayPal\Constants as PayPalConstants;
⋮----
class WC_Gateway_Paypal_Constants {
</file>

<file path="plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-helper.php">
use Automattic\WooCommerce\Gateways\PayPal\Helper as PayPalHelper;
⋮----
class WC_Gateway_Paypal_Helper {
⋮----
public static function is_paypal_gateway_available() {
⋮----
return PayPalHelper::is_paypal_gateway_available();
⋮----
public static function is_orders_v2_migration_eligible() {
⋮----
return PayPalHelper::is_orders_v2_migration_eligible();
⋮----
public static function get_wc_order_from_paypal_custom_id( $custom_id ) {
⋮----
return PayPalHelper::get_wc_order_from_paypal_custom_id( (string) $custom_id );
⋮----
/**
	 * Remove PII (Personally Identifiable Information) from data for logging.
	 *
	 * This function recursively traverses the data array and redacts sensitive information
	 * while preserving the structure for debugging purposes.
	 *
	 * @deprecated 10.5.0 Use Automattic\WooCommerce\Gateways\PayPal\Helper::redact_data() instead.
	 * @param mixed $data The data to remove PII from (array, string, or other types).
	 * @return mixed The data with PII redacted.
	 */
public static function redact_data( $data ) {
⋮----
return PayPalHelper::redact_data( $data );
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-ipn-handler.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Gateways\PayPal\Constants as PayPalConstants;
⋮----
class WC_Gateway_Paypal_IPN_Handler extends WC_Gateway_Paypal_Response {
⋮----
protected $receiver_email;
⋮----
public function __construct( $sandbox = false, $receiver_email = '' ) {
⋮----
public function check_response() {
if ( ! empty( $_POST ) && $this->validate_ipn() ) {
⋮----
public function valid_response( $posted ) {
$order = ! empty( $posted['custom'] ) ? $this->get_paypal_order( $posted['custom'] ) : false;
⋮----
WC_Gateway_Paypal::log( 'Found order #' . $order->get_id() );
WC_Gateway_Paypal::log( 'Payment status: ' . $posted['payment_status'] );
⋮----
public function validate_ipn() {
WC_Gateway_Paypal::log( 'Checking IPN response is valid' );
⋮----
WC_Gateway_Paypal::log( 'IPN Response: ' . wc_print_r( $response, true ) );
⋮----
WC_Gateway_Paypal::log( 'Received valid response from PayPal IPN' );
⋮----
WC_Gateway_Paypal::log( 'Received invalid response from PayPal IPN' );
⋮----
WC_Gateway_Paypal::log( 'Error response: ' . $response->get_error_message() );
⋮----
protected function validate_transaction_type( $txn_type ) {
... (105 lines truncated)
</file>

<file path="plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-notices.php">
use Automattic\WooCommerce\Gateways\PayPal\Constants as PayPalConstants;
⋮----
use Automattic\WooCommerce\Gateways\PayPal\Notices as PayPalNotices;
⋮----
class WC_Gateway_Paypal_Notices {
⋮----
private $notices;
⋮----
public function __construct() {
⋮----
public function add_paypal_notices() {
⋮----
$this->notices->add_paypal_notices();
⋮----
public function add_paypal_notices_on_payments_settings_page() {
⋮----
$this->notices->add_paypal_notices_on_payments_settings_page();
⋮----
public function add_paypal_migration_notice_on_payments_settings_page() {
⋮----
$this->add_paypal_notices_on_payments_settings_page();
⋮----
public function add_paypal_migration_notice() {
⋮----
$this->notices->add_paypal_migration_notice();
⋮----
protected static function paypal_migration_notice_dismissed(): bool {
⋮----
public static function set_account_restriction_flag(): void {
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-pdt-handler.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Enums\OrderStatus;
⋮----
use Automattic\WooCommerce\Gateways\PayPal\Constants as PayPalConstants;
⋮----
class WC_Gateway_Paypal_PDT_Handler extends WC_Gateway_Paypal_Response {
⋮----
protected $identity_token;
⋮----
protected $receiver_email;
⋮----
public function __construct( $sandbox = false, $identity_token = '' ) {
⋮----
public function set_receiver_email( $receiver_email = '' ) {
⋮----
/**
	 * Validate a PDT transaction to ensure its authentic.
	 *
	 * @param  string $transaction TX ID.
	 * @return bool|array False or result array if successful and valid.
	 */
protected function validate_transaction( $transaction ) {
⋮----
'user-agent'  => 'WooCommerce/' . Constants::get_constant( 'WC_VERSION' ),
⋮----
public function check_response() {
⋮----
$this->check_response_for_order( $order_id );
⋮----
public function check_response_for_order( $wc_order_id ) {
... (35 lines truncated)
</file>

<file path="plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-request.php">
use Automattic\WooCommerce\Gateways\PayPal\Constants as PayPalConstants;
use Automattic\WooCommerce\Gateways\PayPal\Request as PayPalRequest;
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
class WC_Gateway_Paypal_Request {
⋮----
protected $line_items = array();
⋮----
protected $gateway;
⋮----
protected $notify_url;
⋮----
protected $endpoint;
⋮----
private $request;
⋮----
public function __construct( $gateway ) {
⋮----
$this->notify_url = WC()->api_request_url( 'WC_Gateway_Paypal' );
⋮----
public function get_request_url( $order, $sandbox = false ) {
⋮----
$paypal_args       = $this->get_paypal_args( $order );
⋮----
WC_Gateway_Paypal::log( 'PayPal Request Args for order ' . $order->get_order_number() . ': ' . wc_print_r( array_merge( $paypal_args, array_intersect_key( $mask, $paypal_args ) ), true ) );
⋮----
/**
	 * Create a PayPal order using the Orders v2 API.
	 *
	 * @deprecated 10.5.0 Use Automattic\WooCommerce\Gateways\PayPal\Request::create_paypal_order() instead. This method will be removed in 11.0.0.
... (194 lines truncated)
</file>

<file path="plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-response.php">
use Automattic\WooCommerce\Enums\OrderStatus;
⋮----
abstract class WC_Gateway_Paypal_Response {
⋮----
protected $sandbox = false;
⋮----
protected function get_paypal_order( $raw_custom ) {
⋮----
// Nothing was found.
WC_Gateway_Paypal::log( 'Order ID and key were not found in "custom".', 'error' );
⋮----
if ( ! $order || ! hash_equals( $order->get_order_key(), $order_key ) ) {
WC_Gateway_Paypal::log( 'Order Keys do not match.', 'error' );
⋮----
protected function payment_complete( $order, $txn_id = '', $note = '' ) {
if ( ! $order->has_status( array( OrderStatus::PROCESSING, OrderStatus::COMPLETED ) ) ) {
$order->add_order_note( $note );
$order->payment_complete( $txn_id );
⋮----
WC()->cart->empty_cart();
⋮----
/**
	 * Hold order and add note.
	 *
	 * @param  WC_Order $order Order object.
	 * @param  string   $reason Reason why the payment is on hold.
	 */
protected function payment_on_hold( $order, $reason = '' ) {
$order->update_status( OrderStatus::ON_HOLD, $reason );
</file>

<file path="plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-transact-account-manager.php">
use Automattic\WooCommerce\Gateways\PayPal\TransactAccountManager as PayPalTransactAccountManager;
⋮----
final class WC_Gateway_Paypal_Transact_Account_Manager {
⋮----
private $transact_account_manager;
⋮----
public function __construct( WC_Gateway_Paypal $gateway ) {
⋮----
public function do_onboarding() {
⋮----
$this->transact_account_manager->do_onboarding();
⋮----
public function get_transact_account_data( $account_type ) {
⋮----
return $this->transact_account_manager->get_transact_account_data( $account_type );
</file>

<file path="plugins/woocommerce/includes/gateways/paypal/includes/class-wc-gateway-paypal-webhook-handler.php">
use Automattic\WooCommerce\Gateways\PayPal\WebhookHandler as PayPalWebhookHandler;
⋮----
class WC_Gateway_Paypal_Webhook_Handler {
⋮----
private PayPalWebhookHandler $webhook_handler;
⋮----
public function __construct() {
⋮----
public function process_webhook( WP_REST_Request $request ) {
⋮----
$this->webhook_handler->process_webhook( $request );
</file>

<file path="plugins/woocommerce/includes/gateways/paypal/includes/settings-paypal.php">
use Automattic\WooCommerce\Utilities\LoggingUtil;
⋮----
esc_url( LoggingUtil::get_logs_tab_url() )
</file>

<file path="plugins/woocommerce/includes/gateways/paypal/class-wc-gateway-paypal-buttons.php">
use Automattic\WooCommerce\Gateways\PayPal\Buttons as PayPalButtons;
⋮----
class WC_Gateway_Paypal_Buttons {
⋮----
private $buttons;
⋮----
public function __construct( WC_Gateway_Paypal $gateway ) {
⋮----
public function get_options() {
⋮----
return $this->buttons->get_options();
⋮----
public function get_common_options() {
⋮----
return $this->buttons->get_common_options();
⋮----
public function get_client_id() {
⋮----
return $this->buttons->get_client_id();
⋮----
public function get_page_type() {
⋮----
return $this->buttons->get_page_type();
⋮----
public function is_enabled() {
⋮----
return $this->buttons->is_enabled();
⋮----
public function get_current_page_for_app_switch() {
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/includes/gateways/paypal/class-wc-gateway-paypal.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Enums\PaymentGatewayFeature;
use Automattic\Jetpack\Connection\Manager as Jetpack_Connection_Manager;
use Automattic\WooCommerce\Gateways\PayPal\Buttons as PayPalButtons;
use Automattic\WooCommerce\Gateways\PayPal\Constants as PayPalConstants;
use Automattic\WooCommerce\Gateways\PayPal\Helper as PayPalHelper;
use Automattic\WooCommerce\Gateways\PayPal\Notices as PayPalNotices;
use Automattic\WooCommerce\Gateways\PayPal\Request as PayPalRequest;
use Automattic\WooCommerce\Gateways\PayPal\TransactAccountManager as PayPalTransactAccountManager;
⋮----
class WC_Gateway_Paypal extends WC_Payment_Gateway {
⋮----
public static $log_enabled = null;
⋮----
public static $log = false;
⋮----
public $testmode;
⋮----
public $debug;
⋮----
public $intent;
⋮----
public $email;
⋮----
public $receiver_email;
⋮----
public $identity_token;
⋮----
private $jetpack_connection_manager;
⋮----
... (227 lines truncated)
</file>

<file path="plugins/woocommerce/includes/gateways/class-wc-payment-gateway-cc.php">
use Automattic\WooCommerce\Enums\PaymentGatewayFeature;
⋮----
class WC_Payment_Gateway_CC extends WC_Payment_Gateway {
⋮----
public function payment_fields() {
if ( $this->supports( PaymentGatewayFeature::TOKENIZATION ) && is_checkout() ) {
$this->tokenization_script();
$this->saved_payment_methods();
$this->form();
$this->save_payment_method_checkbox();
⋮----
public function field_name( $name ) {
return $this->supports( PaymentGatewayFeature::TOKENIZATION ) ? '' : ' name="' . esc_attr( $this->id . '-' . $name ) . '" ';
⋮----
/**
	 * Outputs fields for entering credit card information.
	 *
	 * @since 2.6.0
	 */
public function form() {
⋮----
<input id="' . esc_attr( $this->id ) . '-card-cvc" class="input-text wc-credit-card-form-card-cvc" inputmode="numeric" autocomplete="off" autocorrect="no" autocapitalize="no" spellcheck="no" type="tel" maxlength="4" placeholder="' . esc_attr__( 'CVC', 'woocommerce' ) . '" ' . $this->field_name( 'card-cvc' ) . ' style="width:100px" />
⋮----
<input id="' . esc_attr( $this->id ) . '-card-number" class="input-text wc-credit-card-form-card-number" inputmode="numeric" autocomplete="cc-number" autocorrect="no" autocapitalize="no" spellcheck="no" type="tel" placeholder="&bull;&bull;&bull;&bull; &bull;&bull;&bull;&bull; &bull;&bull;&bull;&bull; &bull;&bull;&bull;&bull;" ' . $this->field_name( 'card-number' ) . ' />
⋮----
<input id="' . esc_attr( $this->id ) . '-card-expiry" class="input-text wc-credit-card-form-card-expiry" inputmode="numeric" autocomplete="cc-exp" autocorrect="no" autocapitalize="no" spellcheck="no" type="tel" placeholder="' . esc_attr__( 'MM / YY', 'woocommerce' ) . '" ' . $this->field_name( 'card-expiry' ) . ' />
⋮----
if ( ! $this->supports( PaymentGatewayFeature::CREDIT_CARD_FORM_CVC_ON_SAVED_METHOD ) ) {
⋮----
if ( $this->supports( PaymentGatewayFeature::CREDIT_CARD_FORM_CVC_ON_SAVED_METHOD ) ) {
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/includes/gateways/class-wc-payment-gateway-echeck.php">
use Automattic\WooCommerce\Enums\PaymentGatewayFeature;
⋮----
class WC_Payment_Gateway_ECheck extends WC_Payment_Gateway {
⋮----
public function payment_fields() {
if ( $this->supports( PaymentGatewayFeature::TOKENIZATION ) && is_checkout() ) {
$this->tokenization_script();
$this->saved_payment_methods();
$this->form();
$this->save_payment_method_checkbox();
⋮----
public function form() {
</file>

<file path="plugins/woocommerce/includes/import/abstract-wc-product-importer.php">
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
abstract class WC_Product_Importer implements WC_Importer_Interface {
⋮----
protected $file = '';
⋮----
/**
	 * The file position after the last read.
	 *
	 * @var int
	 */
protected $file_position = 0;
⋮----
/**
	 * Importer parameters.
	 *
	 * @var array
	 */
protected $params = array();
⋮----
/**
	 * Raw keys - CSV raw headers.
	 *
	 * @var array
	 */
protected $raw_keys = array();
⋮----
/**
... (228 lines truncated)
</file>

<file path="plugins/woocommerce/includes/import/class-wc-product-csv-importer.php">
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
use Automattic\WooCommerce\Utilities\ArrayUtil;
⋮----
class WC_Product_CSV_Importer extends WC_Product_Importer {
⋮----
protected $parsing_raw_data_index = 0;
⋮----
private $cogs_is_enabled = false;
⋮----
private $original_id_map = array();
⋮----
public function __construct( $file, $params = array() ) {
$this->cogs_is_enabled = wc_get_container()->get( CostOfGoodsSoldController::class )->feature_is_enabled();
⋮----
$this->read_file();
⋮----
private function adjust_character_encoding( $value ) {
⋮----
protected function read_file() {
if ( ! WC_Product_CSV_Importer_Controller::is_file_valid_csv( $this->file ) ) {
⋮----
if ( ArrayUtil::is_truthy( $this->params, 'character_encoding' ) ) {
⋮----
$this->raw_keys[0] = $this->remove_utf8_bom( $this->raw_keys[0] );
⋮----
$this->set_mapped_keys();
... (293 lines truncated)
</file>

<file path="plugins/woocommerce/includes/integrations/maxmind-geolocation/views/html-admin-options.php">
<input class="input-text regular-input" type="text" value="<?php echo esc_attr( $this->database_service->get_database_path() ); ?>" readonly>
</file>

<file path="plugins/woocommerce/includes/integrations/maxmind-geolocation/class-wc-integration-maxmind-database-service.php">
class WC_Integration_MaxMind_Database_Service {
⋮----
private $database_prefix;
⋮----
public function __construct( $database_prefix ) {
⋮----
public function get_database_path() {
⋮----
public function download_database( $license_key ) {
⋮----
$error_data = $tmp_archive_path->get_error_data();
⋮----
$tmp_database_path = trailingslashit( dirname( $tmp_archive_path ) ) . trailingslashit( $file->current()->getFilename() ) . self::DATABASE . self::DATABASE_EXTENSION;
⋮----
$file->extractTo(
⋮----
trailingslashit( $file->current()->getFilename() ) . self::DATABASE . self::DATABASE_EXTENSION,
⋮----
return new WP_Error( 'woocommerce_maxmind_geolocation_database_archive', $exception->getMessage() );
⋮----
public function get_iso_country_code_for_ip( $ip_address ) {
⋮----
wc_get_logger()->notice( __( 'Missing MaxMind Reader library!', 'woocommerce' ), array( 'source' => 'maxmind-geolocation' ) );
⋮----
$database_path = $this->get_database_path();
⋮----
$reader = new MaxMind\Db\Reader( $database_path );
$data   = $reader->get( $ip_address );
⋮----
$reader->close();
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/includes/integrations/maxmind-geolocation/class-wc-integration-maxmind-geolocation.php">
use Automattic\WooCommerce\Enums\DefaultCustomerAddress;
⋮----
class WC_Integration_MaxMind_Geolocation extends WC_Integration {
⋮----
private $database_service;
⋮----
public function __construct() {
⋮----
$this->database_service = new WC_Integration_MaxMind_Database_Service( $this->get_database_prefix() );
⋮----
$this->init_form_fields();
$this->init_settings();
⋮----
public function admin_options() {
parent::admin_options();
⋮----
public function init_form_fields() {
⋮----
/**
	 * Get database service.
	 *
	 * @return WC_Integration_MaxMind_Database_Service|null
	 */
public function get_database_service() {
⋮----
/**
	 * Checks to make sure that the license key is valid.
	 *
	 * @param string $key The key of the field.
	 * @param mixed  $value The value of the field.
... (62 lines truncated)
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-abstract-order-data-store-interface.php">
interface WC_Abstract_Order_Data_Store_Interface {
⋮----
public function read_items( $order, $type );
⋮----
public function delete_items( $order, $type = null );
⋮----
public function get_payment_token_ids( $order );
⋮----
public function update_payment_token_ids( $order, $token_ids );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-coupon-data-store-interface.php">
interface WC_Coupon_Data_Store_Interface {
⋮----
public function increase_usage_count( &$coupon, $used_by = '' );
⋮----
/**
	 *  Decrease usage count for current coupon.
	 *
	 * @param WC_Coupon $coupon Coupon object.
	 * @param string    $used_by Either user ID or billing email.
	 */
public function decrease_usage_count( &$coupon, $used_by = '' );
⋮----
public function get_usage_by_user_id( &$coupon, $user_id );
⋮----
public function get_code_by_id( $id );
⋮----
public function get_ids_by_code( $code );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-customer-data-store-interface.php">
interface WC_Customer_Data_Store_Interface {
⋮----
public function get_last_order( &$customer );
⋮----
public function get_order_count( &$customer );
⋮----
public function get_total_spent( &$customer );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-customer-download-data-store-interface.php">
interface WC_Customer_Download_Data_Store_Interface {
⋮----
public function delete_by_id( $id );
⋮----
public function delete_by_order_id( $id );
⋮----
public function delete_by_download_id( $id );
⋮----
public function get_downloads( $args = array() );
⋮----
public function update_download_id( $product_id, $old_id, $new_id );
⋮----
public function get_downloads_for_customer( $customer_id );
⋮----
public function update_user_by_order_id( $order_id, $customer_id, $email );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-customer-download-log-data-store-interface.php">
interface WC_Customer_Download_Log_Data_Store_Interface {
⋮----
public function get_download_logs( $args = array() );
⋮----
public function get_download_logs_for_permission( $permission_id );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-importer-interface.php">
interface WC_Importer_Interface {
⋮----
public function import();
⋮----
public function get_raw_keys();
⋮----
public function get_mapped_keys();
⋮----
public function get_raw_data();
⋮----
public function get_parsed_data();
⋮----
public function get_file_position();
⋮----
public function get_percent_complete();
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-log-handler-interface.php">
interface WC_Log_Handler_Interface {
⋮----
public function handle( $timestamp, $level, $message, $context );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-logger-interface.php">
interface WC_Logger_Interface {
⋮----
public function add( $handle, $message, $level = WC_Log_Levels::NOTICE );
⋮----
public function log( $level, $message, $context = array() );
⋮----
public function emergency( $message, $context = array() );
⋮----
public function alert( $message, $context = array() );
⋮----
public function critical( $message, $context = array() );
⋮----
public function error( $message, $context = array() );
⋮----
public function warning( $message, $context = array() );
⋮----
public function notice( $message, $context = array() );
⋮----
public function info( $message, $context = array() );
⋮----
public function debug( $message, $context = array() );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-object-data-store-interface.php">
interface WC_Object_Data_Store_Interface {
⋮----
public function create( &$data );
⋮----
public function read( &$data );
⋮----
public function update( &$data );
⋮----
public function delete( &$data, $args = array() );
⋮----
public function read_meta( &$data );
⋮----
public function delete_meta( &$data, $meta );
⋮----
public function add_meta( &$data, $meta );
⋮----
public function update_meta( &$data, $meta );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-order-data-store-interface.php">
interface WC_Order_Data_Store_Interface {
⋮----
public function get_total_refunded( $order );
⋮----
public function get_total_tax_refunded( $order );
⋮----
public function get_total_shipping_refunded( $order );
⋮----
public function get_order_id_by_order_key( $order_key );
⋮----
public function get_order_count( $status );
⋮----
public function get_orders( $args = array() );
⋮----
public function get_unpaid_orders( $date );
⋮----
public function search_orders( $term );
⋮----
public function get_download_permissions_granted( $order );
⋮----
public function set_download_permissions_granted( $order, $set );
⋮----
public function get_recorded_sales( $order );
⋮----
public function set_recorded_sales( $order, $set );
⋮----
public function get_recorded_coupon_usage_counts( $order );
⋮----
public function set_recorded_coupon_usage_counts( $order, $set );
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-order-item-data-store-interface.php">
interface WC_Order_Item_Data_Store_Interface {
⋮----
public function add_order_item( $order_id, $item );
⋮----
public function update_order_item( $item_id, $item );
⋮----
public function delete_order_item( $item_id );
⋮----
public function update_metadata( $item_id, $meta_key, $meta_value, $prev_value = '' );
⋮----
/**
	 * Add term meta.
	 *
	 * @param  int    $item_id Item ID.
	 * @param  string $meta_key Meta key.
	 * @param  mixed  $meta_value Meta value.
	 * @param  bool   $unique Unique? (default: false).
	 * @return int    New row ID or 0
	 */
public function add_metadata( $item_id, $meta_key, $meta_value, $unique = false );
⋮----
/**
	 * Delete term meta.
	 *
	 * @param  int    $item_id Item ID.
	 * @param  string $meta_key Meta key.
	 * @param  mixed  $meta_value Meta value (default: '').
	 * @param  bool   $delete_all Delete all matching entries? (default: false).
	 * @return bool
	 */
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-order-item-product-data-store-interface.php">
interface WC_Order_Item_Product_Data_Store_Interface {
⋮----
public function get_download_ids( $item, $order );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-order-item-type-data-store-interface.php">
interface WC_Order_Item_Type_Data_Store_Interface {
⋮----
public function save_item_data( &$item );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-order-refund-data-store-interface.php">
interface WC_Order_Refund_Data_Store_Interface {
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-payment-token-data-store-interface.php">
interface WC_Payment_Token_Data_Store_Interface {
⋮----
public function get_tokens( $args );
⋮----
public function get_users_default_token( $user_id );
⋮----
public function get_token_by_id( $token_id );
⋮----
public function get_metadata( $token_id );
⋮----
public function get_token_type_by_id( $token_id );
⋮----
public function set_default_status( $token_id, $status = true );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-product-data-store-interface.php">
interface WC_Product_Data_Store_Interface {
⋮----
public function get_on_sale_products();
⋮----
public function get_featured_product_ids();
⋮----
public function is_existing_sku( $product_id, $sku );
⋮----
public function get_product_id_by_sku( $sku );
⋮----
public function get_starting_sales();
⋮----
public function get_ending_sales();
⋮----
public function find_matching_product_variation( $product, $match_attributes = array() );
⋮----
public function sort_all_product_variations( $parent_id );
⋮----
public function get_related_products( $cats_array, $tags_array, $exclude_ids, $limit, $product_id );
⋮----
public function update_product_stock( $product_id_with_stock, $stock_quantity = null, $operation = 'set' );
⋮----
public function update_product_sales( $product_id, $quantity = null, $operation = 'set' );
⋮----
public function get_shipping_class_id_by_slug( $slug );
⋮----
public function get_products( $args = array() );
⋮----
public function get_product_type( $product_id );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-product-variable-data-store-interface.php">
interface WC_Product_Variable_Data_Store_Interface {
⋮----
public function child_has_weight( $product );
⋮----
public function child_has_dimensions( $product );
⋮----
public function child_is_in_stock( $product );
⋮----
public function sync_variation_names( &$product, $previous_name = '', $new_name = '' );
⋮----
public function sync_managed_variation_stock_status( &$product );
⋮----
public function sync_price( &$product );
⋮----
public function delete_variations( $product_id, $force_delete = false );
⋮----
public function untrash_variations( $product_id );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-queue-interface.php">
interface WC_Queue_Interface {
⋮----
public function add( $hook, $args = array(), $group = '' );
⋮----
/**
	 * Schedule an action to run once at some time in the future
	 *
	 * @param int    $timestamp When the job will run.
	 * @param string $hook The hook to trigger.
	 * @param array  $args Arguments to pass when the hook triggers.
	 * @param string $group The group to assign this job to.
	 * @return int The action ID
	 */
public function schedule_single( $timestamp, $hook, $args = array(), $group = '' );
⋮----
/**
	 * Schedule a recurring action
	 *
	 * @param int    $timestamp When the first instance of the job will run.
	 * @param int    $interval_in_seconds How long to wait between runs.
	 * @param string $hook The hook to trigger.
	 * @param array  $args Arguments to pass when the hook triggers.
	 * @param string $group The group to assign this job to.
	 * @return int The action ID
	 */
public function schedule_recurring( $timestamp, $interval_in_seconds, $hook, $args = array(), $group = '' );
⋮----
/**
	 * Schedule an action that recurs on a cron-like schedule.
	 *
... (72 lines truncated)
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-shipping-zone-data-store-interface.php">
interface WC_Shipping_Zone_Data_Store_Interface {
⋮----
public function get_methods( $zone_id, $enabled_only );
⋮----
public function get_method_count( $zone_id );
⋮----
public function add_method( $zone_id, $type, $order );
⋮----
public function delete_method( $instance_id );
⋮----
public function get_method( $instance_id );
⋮----
public function get_zone_id_from_package( $package );
⋮----
public function get_zones();
⋮----
public function get_zone_id_by_instance_id( $id );
</file>

<file path="plugins/woocommerce/includes/interfaces/class-wc-webhooks-data-store-interface.php">
interface WC_Webhook_Data_Store_Interface {
⋮----
public function get_api_version_number( $api_version );
⋮----
public function get_webhooks_ids( $status = '' );
</file>

<file path="plugins/woocommerce/includes/legacy/abstract-wc-legacy-order.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
⋮----
abstract class WC_Abstract_Legacy_Order extends WC_Data {
⋮----
public function add_coupon( $code = array(), $discount = 0, $discount_tax = 0 ) {
⋮----
$item->set_props( array(
⋮----
'order_id'     => $this->get_id(),
⋮----
$item->save();
$this->add_item( $item );
wc_do_deprecated_action( 'woocommerce_order_add_coupon', array( $this->get_id(), $item->get_id(), $code, $discount, $discount_tax ), '3.0', 'woocommerce_new_order_item action instead.' );
return $item->get_id();
⋮----
public function add_tax( $tax_rate_id, $tax_amount = 0, $shipping_tax_amount = 0 ) {
⋮----
$item->set_rate( $tax_rate_id );
$item->set_order_id( $this->get_id() );
⋮----
wc_do_deprecated_action( 'woocommerce_order_add_tax', array( $this->get_id(), $item->get_id(), $tax_rate_id, $tax_amount, $shipping_tax_amount ), '3.0', 'woocommerce_new_order_item action instead.' );
⋮----
public function add_shipping( $shipping_rate ) {
⋮----
foreach ( $shipping_rate->get_meta_data() as $key => $value ) {
$item->add_meta_data( $key, $value, true );
⋮----
wc_do_deprecated_action( 'woocommerce_order_add_shipping', array( $this->get_id(), $item->get_id(), $shipping_rate ), '3.0', 'woocommerce_new_order_item action instead.' );
⋮----
... (209 lines truncated)
</file>

<file path="plugins/woocommerce/includes/legacy/abstract-wc-legacy-payment-token.php">
abstract class WC_Legacy_Payment_Token extends WC_Data {
⋮----
public function set_type( $type ) {
⋮----
public function read( $token_id ) {
⋮----
$this->set_id( $token_id );
$data_store = WC_Data_Store::load( 'payment-token' );
$data_store->read( $this );
⋮----
public function update() {
⋮----
$data_store->update( $this );
⋮----
public function create() {
⋮----
$data_store->create( $this );
</file>

<file path="plugins/woocommerce/includes/legacy/abstract-wc-legacy-product.php">
use Automattic\WooCommerce\Enums\ProductType;
⋮----
abstract class WC_Abstract_Legacy_Product extends WC_Data {
⋮----
public function __isset( $key ) {
⋮----
if ( $this->is_type( ProductType::VARIATION ) ) {
⋮----
return in_array( $key, array_merge( $valid, array_keys( $this->data ) ) ) || metadata_exists( 'post', $this->get_id(), '_' . $key ) || metadata_exists( 'post', $this->get_parent_id(), '_' . $key );
⋮----
public function __get( $key ) {
⋮----
$value = $this->is_type( ProductType::VARIATION ) ? $this->get_parent_id() : $this->get_id();
⋮----
$value = $this->get_type();
⋮----
$value = $this->get_catalog_visibility();
⋮----
return $this->get_date_on_sale_from() ? $this->get_date_on_sale_from()->getTimestamp() : '';
⋮----
return $this->get_date_on_sale_to() ? $this->get_date_on_sale_to()->getTimestamp() : '';
⋮----
$value = get_post( $this->get_id() );
⋮----
$value = $this->get_gallery_image_ids();
⋮----
$value = $this->get_shipping_class();
⋮----
$value = $this->get_total_stock();
⋮----
... (154 lines truncated)
</file>

<file path="plugins/woocommerce/includes/legacy/class-wc-legacy-cart.php">
abstract class WC_Legacy_Cart {
⋮----
public $cart_session_data = array(
⋮----
public $coupon_applied_count = array();
⋮----
public function __isset( $name ) {
⋮----
public function &__get( $name ) {
⋮----
$value = $this->get_cart_contents_total();
⋮----
$value = $this->get_total( 'edit' );
⋮----
$value = $this->get_subtotal() + $this->get_subtotal_tax();
⋮----
$value = $this->get_subtotal();
⋮----
$value = $this->get_fee_tax() + $this->get_cart_contents_tax();
⋮----
$value = $this->get_fee_total();
⋮----
$value = $this->get_discount_total();
⋮----
$value = $this->get_discount_tax();
⋮----
$value = $this->get_shipping_total();
⋮----
$value = $this->get_shipping_tax();
⋮----
... (100 lines truncated)
</file>

<file path="plugins/woocommerce/includes/legacy/class-wc-legacy-coupon.php">
abstract class WC_Legacy_Coupon extends WC_Data {
⋮----
public function __isset( $key ) {
⋮----
public function __get( $key ) {
⋮----
$value = $this->get_id();
⋮----
$value = $this->get_id() > 0;
⋮----
$custom_fields = $this->get_id() ? $this->get_meta_data() : array();
⋮----
$value = $this->get_discount_type();
⋮----
$value = $this->get_amount();
⋮----
$value = $this->get_code();
⋮----
$value = ( true === $this->get_individual_use() ) ? 'yes' : 'no';
⋮----
$value = $this->get_product_ids();
⋮----
$value = $this->get_excluded_product_ids();
⋮----
$value = $this->get_usage_limit();
⋮----
$value = $this->get_usage_limit_per_user();
⋮----
$value = $this->get_limit_usage_to_x_items();
⋮----
... (42 lines truncated)
</file>

<file path="plugins/woocommerce/includes/legacy/class-wc-legacy-customer.php">
abstract class WC_Legacy_Customer extends WC_Data {
⋮----
public function __isset( $key ) {
⋮----
$key = $this->filter_legacy_key( $key );
⋮----
public function __get( $key ) {
⋮----
/**
	 * __set function.
	 *
	 * @param string $key
	 * @param mixed $value
	 */
public function __set( $key, $value ) {
⋮----
private function filter_legacy_key( $key ) {
⋮----
public function set_location( $country, $state, $postcode = '', $city = '' ) {
$this->set_billing_location( $country, $state, $postcode, $city );
$this->set_shipping_location( $country, $state, $postcode, $city );
⋮----
/**
	 * Get default country for a customer.
	 * @return string
	 */
public function get_default_country() {
⋮----
public function get_default_state() {
⋮----
... (67 lines truncated)
</file>

<file path="plugins/woocommerce/includes/legacy/class-wc-legacy-shipping-zone.php">
abstract class WC_Legacy_Shipping_Zone extends WC_Data {
⋮----
public function get_zone_id() {
⋮----
return $this->get_id();
⋮----
public function read( $zone_id ) {
⋮----
$this->set_id( $zone_id );
$data_store = WC_Data_Store::load( 'shipping-zone' );
$data_store->read( $this );
⋮----
public function update() {
⋮----
$data_store->update( $this );
⋮----
public function create() {
⋮----
$data_store->create( $this );
</file>

<file path="plugins/woocommerce/includes/legacy/class-wc-legacy-webhook.php">
abstract class WC_Legacy_Webhook extends WC_Data {
⋮----
public function __isset( $key ) {
⋮----
public function __get( $key ) {
⋮----
$value = $this->get_id();
⋮----
$value = $this->get_status();
⋮----
$value = $this->get_delivery_url();
⋮----
$value = $this->get_secret();
⋮----
$value = $this->get_topic();
⋮----
$value = $this->get_hooks();
⋮----
$value = $this->get_resource();
⋮----
$value = $this->get_event();
⋮----
$value = $this->get_failure_count();
⋮----
$value = $this->get_api_version();
⋮----
} // End switch().
⋮----
/**
	 * Get the post data for the webhook.
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/includes/libraries/class-wc-eval-math.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Eval_Math {
⋮----
public static $last_error = null;
⋮----
public static $v = array( 'e' => 2.71, 'pi' => 3.14 );
⋮----
public static $f = array();
⋮----
public static $vb = array( 'e', 'pi' );
⋮----
public static $fb = array();
⋮----
public static function evaluate( $expr ) {
⋮----
return self::trigger( "cannot assign to constant '$matches[1]'" );
⋮----
if ( ( $tmp = self::pfx( self::nfx( $matches[2] ) ) ) === false ) {
⋮----
return self::trigger( "cannot redefine built-in function '$matches[1]()'" );
⋮----
$args = explode( ",", preg_replace( "/\s+/", "", $matches[2] ) ); // get the arguments
if ( ( $stack = self::nfx( $matches[3] ) ) === false ) {
return false; // see if it can be converted to postfix
⋮----
for ( $i = 0; $i < $stack_size; $i++ ) { // freeze the state of the non-argument variables
⋮----
return self::trigger( "undefined variable '$token' in function definition" );
⋮----
... (105 lines truncated)
</file>

<file path="plugins/woocommerce/includes/libraries/wp-async-request.php">
abstract class WP_Async_Request {
⋮----
protected $prefix = 'wp';
⋮----
protected $action = 'async_request';
⋮----
protected $identifier;
⋮----
protected $data = array();
⋮----
public function __construct() {
⋮----
public function data( $data ) {
⋮----
public function dispatch() {
$url  = add_query_arg( $this->get_query_args(), $this->get_query_url() );
$args = $this->get_post_args();
⋮----
protected function get_query_args() {
⋮----
protected function get_query_url() {
⋮----
protected function get_post_args() {
⋮----
public function maybe_handle() {
⋮----
$this->handle();
⋮----
abstract protected function handle();
</file>

<file path="plugins/woocommerce/includes/libraries/wp-background-process.php">
abstract class WP_Background_Process extends WP_Async_Request {
⋮----
protected $action = 'background_process';
⋮----
protected $start_time = 0;
⋮----
protected $cron_hook_identifier;
⋮----
protected $cron_interval_identifier;
⋮----
public function __construct() {
parent::__construct();
⋮----
public function dispatch() {
⋮----
$this->schedule_event();
⋮----
return parent::dispatch();
⋮----
public function push_to_queue( $data ) {
⋮----
public function save() {
$key = $this->generate_key();
⋮----
public function update( $key, $data ) {
⋮----
public function delete( $key ) {
⋮----
protected function generate_key( $length = 64 ) {
⋮----
... (67 lines truncated)
</file>

<file path="plugins/woocommerce/includes/log-handlers/class-wc-log-handler-db.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Log_Handler_DB extends WC_Log_Handler {
⋮----
public function handle( $timestamp, $level, $message, $context ) {
⋮----
$source = $this->get_log_source();
⋮----
return $this->add( $timestamp, $level, $message, $source, $context );
⋮----
protected static function add( $timestamp, $level, $message, $source, $context ) {
⋮----
'level'     => WC_Log_Levels::get_level_severity( $level ),
⋮----
$context['backtrace'] = self::get_backtrace();
⋮----
return false !== $wpdb->insert( "{$wpdb->prefix}woocommerce_log", $insert, $format );
⋮----
public static function flush() {
⋮----
return $wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}woocommerce_log" );
⋮----
public function clear( $source ) {
⋮----
return $wpdb->query(
$wpdb->prepare(
⋮----
public static function delete( $log_ids ) {
⋮----
$result = $wpdb->query(
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/includes/log-handlers/class-wc-log-handler-email.php">
class WC_Log_Handler_Email extends WC_Log_Handler {
⋮----
protected $threshold;
⋮----
protected $recipients = array();
⋮----
protected $logs = array();
⋮----
protected $max_severity = null;
⋮----
public function __construct( $recipients = null, $threshold = 'alert' ) {
⋮----
$this->add_email( $recipient );
⋮----
$this->add_email( $recipients );
⋮----
$this->set_threshold( $threshold );
⋮----
public function set_threshold( $level ) {
$this->threshold = WC_Log_Levels::get_level_severity( $level );
⋮----
protected function should_handle( $level ) {
return $this->threshold <= WC_Log_Levels::get_level_severity( $level );
⋮----
public function handle( $timestamp, $level, $message, $context ) {
⋮----
if ( $this->should_handle( $level ) ) {
$this->add_log( $timestamp, $level, $message, $context );
⋮----
public function send_log_email() {
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/includes/log-handlers/class-wc-log-handler-file.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Utilities\LoggingUtil;
⋮----
class WC_Log_Handler_File extends WC_Log_Handler {
⋮----
protected $handles = array();
⋮----
protected $log_size_limit;
⋮----
protected $cached_logs = array();
⋮----
public function __construct( $log_size_limit = null ) {
⋮----
public function __destruct() {
⋮----
public function handle( $timestamp, $level, $message, $context ) {
⋮----
$entry = self::format_entry( $timestamp, $level, $message, $context );
⋮----
return $this->add( $entry, $handle );
⋮----
protected static function format_entry( $timestamp, $level, $message, $context ) {
⋮----
$entry = parent::format_entry( $timestamp, $level, $message, $context );
⋮----
protected function open( $handle, $mode = 'a' ) {
if ( $this->is_open( $handle ) ) {
⋮----
$file = self::get_log_file_path( $handle );
⋮----
... (62 lines truncated)
</file>

<file path="plugins/woocommerce/includes/payment-tokens/class-wc-payment-token-cc.php">
class WC_Payment_Token_CC extends WC_Payment_Token {
⋮----
protected $type = 'CC';
⋮----
protected $extra_data = array(
⋮----
/**
	 * Get type to display to user.
	 *
	 * @since  2.6.0
	 * @param  string $deprecated Deprecated since WooCommerce 3.0.
	 * @return string
	 */
public function get_display_name( $deprecated = '' ) {
⋮----
/* translators: 1: credit card type 2: last 4 digits 3: expiry month 4: expiry year */
⋮----
wc_get_credit_card_type_label( $this->get_card_type() ),
$this->get_last4(),
$this->get_expiry_month(),
substr( $this->get_expiry_year(), 2 )
⋮----
protected function get_hook_prefix() {
⋮----
public function validate() {
if ( false === parent::validate() ) {
⋮----
if ( ! $this->get_last4( 'edit' ) ) {
⋮----
if ( ! $this->get_expiry_year( 'edit' ) ) {
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/includes/payment-tokens/class-wc-payment-token-echeck.php">
class WC_Payment_Token_ECheck extends WC_Payment_Token {
⋮----
protected $type = 'eCheck';
⋮----
protected $extra_data = array(
⋮----
/**
	 * Get type to display to user.
	 *
	 * @since  2.6.0
	 * @param  string $deprecated Deprecated since WooCommerce 3.0.
	 * @return string
	 */
public function get_display_name( $deprecated = '' ) {
⋮----
/* translators: 1: last 4 digits */
⋮----
$this->get_last4()
⋮----
protected function get_hook_prefix() {
⋮----
public function validate() {
if ( false === parent::validate() ) {
⋮----
if ( ! $this->get_last4( 'edit' ) ) {
⋮----
public function get_last4( $context = 'view' ) {
return $this->get_prop( 'last4', $context );
⋮----
public function set_last4( $last4 ) {
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/includes/product-usage/class-wc-product-usage-rule-set.php">
class WC_Product_Usage_Rule_Set {
⋮----
protected $rules;
⋮----
public function __construct( $rules ) {
⋮----
public function get_rule( string $rule_name ) {
</file>

<file path="plugins/woocommerce/includes/product-usage/class-wc-product-usage.php">
class WC_Product_Usage {
⋮----
public static function load() {
self::includes();
⋮----
protected static function includes() {
⋮----
public static function get_rules_for_product( int $product_id ): ?WC_Product_Usage_Rule_Set {
$rules = self::get_product_usage_restriction_rule( $product_id );
⋮----
if ( ! WC_Helper::has_product_subscription( $product_id ) ) {
⋮----
$subscriptions = wp_list_filter( WC_Helper::get_installed_subscriptions(), array( 'product_id' => $product_id ) );
⋮----
private static function get_product_usage_restriction_rule( int $product_id ): ?array {
⋮----
$rules = WC_Helper::get_product_usage_notice_rules();
⋮----
WC_Product_Usage::load();
</file>

<file path="plugins/woocommerce/includes/queue/class-wc-action-queue.php">
class WC_Action_Queue implements WC_Queue_Interface {
⋮----
public function add( $hook, $args = array(), $group = '' ) {
return $this->schedule_single( time(), $hook, $args, $group );
⋮----
/**
	 * Schedule an action to run once at some time in the future
	 *
	 * @param int    $timestamp When the job will run.
	 * @param string $hook The hook to trigger.
	 * @param array  $args Arguments to pass when the hook triggers.
	 * @param string $group The group to assign this job to.
	 * @return int The action ID.
	 */
public function schedule_single( $timestamp, $hook, $args = array(), $group = '' ) {
⋮----
/**
	 * Schedule a recurring action
	 *
	 * @param int    $timestamp When the first instance of the job will run.
	 * @param int    $interval_in_seconds How long to wait between runs.
	 * @param string $hook The hook to trigger.
	 * @param array  $args Arguments to pass when the hook triggers.
	 * @param string $group The group to assign this job to.
	 * @return int The action ID.
	 */
public function schedule_recurring( $timestamp, $interval_in_seconds, $hook, $args = array(), $group = '' ) {
⋮----
/**
	 * Schedule an action that recurs on a cron-like schedule.
... (60 lines truncated)
</file>

<file path="plugins/woocommerce/includes/queue/class-wc-queue.php">
class WC_Queue {
⋮----
protected static $instance = null;
⋮----
protected static $default_cass = 'WC_Action_Queue';
⋮----
final public static function instance() {
⋮----
$class          = self::get_class();
self::$instance = new $class();
self::$instance = self::validate_instance( self::$instance );
⋮----
protected static function get_class() {
⋮----
protected static function validate_instance( $instance ) {
⋮----
$instance = new $default_class();
</file>

<file path="plugins/woocommerce/includes/react-admin/emails/html-admin-report-export-download.php">

</file>

<file path="plugins/woocommerce/includes/react-admin/emails/plain-admin-report-export-download.php">

</file>

<file path="plugins/woocommerce/includes/react-admin/class-experimental-abtest.php">
namespace WooCommerce\Admin;
⋮----
use Automattic\Jetpack\Connection\Manager as Jetpack_Connection_Manager;
use Automattic\Jetpack\Connection\Client as Jetpack_Connection_client;
use Automattic\WooCommerce\Admin\WCAdminHelper;
⋮----
final class Experimental_Abtest {
⋮----
private $tests = array();
⋮----
private $anon_id = null;
⋮----
private $platform = 'woocommerce';
⋮----
private $consent = false;
⋮----
private $as_auth_wpcom_user = false;
⋮----
public function __construct( string $anon_id, string $platform, bool $consent, bool $as_auth_wpcom_user = false ) {
⋮----
public static function in_treatment( string $experiment_name, bool $as_auth_wpcom_user = false ) {
⋮----
return $abtest->get_variation( $experiment_name ) === 'treatment';
⋮----
public function get_variation( $test_name ) {
⋮----
$variation = $this->fetch_variation( $test_name );
⋮----
throw new \Exception( $variation->get_error_message() );
⋮----
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/includes/react-admin/connect-existing-pages.php">
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
function wc_admin_get_core_pages_to_connect() {
$all_reports = WC_Admin_Reports::get_reports();
⋮----
function wc_admin_filter_core_page_breadcrumbs( $breadcrumbs ) {
$screen_id              = PageController::get_instance()->get_current_screen_id();
⋮----
function wc_admin_connect_core_pages( $is_connected, $current_page ) {
⋮----
$screen_id        = PageController::get_instance()->get_current_screen_id();
⋮----
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
</file>

<file path="plugins/woocommerce/includes/react-admin/core-functions.php">
use Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
function wc_admin_number_format( $number ) {
$currency_settings = Settings::get_currency_settings();
⋮----
function wc_admin_url( $path = null, $query = array() ) {
⋮----
function wc_admin_record_tracks_event( $event_name, $properties = array() ) {
⋮----
WC_Tracks::record_event( $event_name, $properties );
</file>

<file path="plugins/woocommerce/includes/react-admin/page-controller-functions.php">
use Automattic\WooCommerce\Admin\PageController;
⋮----
function wc_admin_connect_page( $options ) {
$controller = PageController::get_instance();
$controller->connect_page( $options );
⋮----
function wc_admin_register_page( $options ) {
⋮----
$controller->register_page( $options );
⋮----
function wc_admin_is_connected_page() {
⋮----
return $controller->is_connected_page();
⋮----
function wc_admin_is_registered_page() {
⋮----
return $controller->is_registered_page();
⋮----
function wc_admin_get_breadcrumbs() {
⋮----
return $controller->get_breadcrumbs();
</file>

<file path="plugins/woocommerce/includes/react-admin/wc-admin-update-functions.php">
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskLists;
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Internal\Admin\Notes\UnsecuredReportFiles;
use Automattic\WooCommerce\Admin\ReportExporter;
use Automattic\WooCommerce\Internal\Admin\OrderTaxLookupMigrator;
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessingController;
⋮----
function wc_admin_update_0201_order_status_index() {
⋮----
$index = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->prefix}wc_order_stats WHERE key_name = 'status'" );
⋮----
$wpdb->query( "DROP INDEX `status` ON {$wpdb->prefix}wc_order_stats" );
⋮----
$wpdb->query( $wpdb->prepare( "ALTER TABLE {$wpdb->prefix}wc_order_stats ADD INDEX status (status(%d))", $max_index_length ) );
⋮----
function wc_admin_update_0230_rename_gross_total() {
⋮----
$wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_order_stats DROP COLUMN `total_sales`" );
⋮----
$wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_order_stats CHANGE COLUMN `gross_total` `total_sales` double DEFAULT 0 NOT NULL" );
⋮----
function wc_admin_update_0251_remove_unsnooze_action() {
⋮----
function wc_admin_update_110_remove_facebook_note() {
Notes::delete_notes_with_name( 'wc-admin-facebook-extension' );
⋮----
function wc_admin_update_130_remove_dismiss_action_from_tracking_opt_in_note() {
⋮----
$wpdb->query( "DELETE actions FROM {$wpdb->prefix}wc_admin_note_actions actions INNER JOIN {$wpdb->prefix}wc_admin_notes notes USING (note_id) WHERE actions.name = 'tracking-dismiss' AND notes.name = 'wc-admin-usage-tracking-opt-in'" );
⋮----
... (56 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Telemetry/class-wc-rest-telemetry-controller.php">
class WC_REST_Telemetry_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc-telemetry';
⋮----
protected $rest_base = 'tracker';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function telemetry_permissions_check( $request ) {
⋮----
public function record_usage_data( $request ) {
$new = $this->get_usage_data( $request );
⋮----
public function get_usage_data( $request ) {
$platform = strtolower( $request->get_param( 'platform' ) );
⋮----
$version = $request->get_param( 'version' );
⋮----
$installation_date = $request->get_param( 'installation_date' );
⋮----
public function get_collection_params() {
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-coupons-v1-controller.php">
use Automattic\WooCommerce\Utilities\StringUtil;
⋮----
class WC_REST_Coupons_V1_Controller extends WC_REST_Posts_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'coupons';
⋮----
protected $post_type = 'shop_coupon';
⋮----
public function __construct() {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array(
⋮----
'context'         => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
'args'            => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function query_args( $args, $request ) {
⋮----
if ( ! StringUtil::is_null_or_whitespace( $coupon_code ) ) {
⋮----
public function prepare_item_for_response( $post, $request ) {
⋮----
... (58 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-customer-downloads-v1-controller.php">
use Automattic\WooCommerce\Internal\Utilities\Users;
⋮----
class WC_REST_Customer_Downloads_V1_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'customers/(?P<customer_id>[\d]+)/downloads';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function get_items_permissions_check( $request ) {
$user = Users::get_user_in_current_site( $request['customer_id'] );
⋮----
$user->add_data( array( 'status' => 404 ) );
⋮----
public function get_items( $request ) {
⋮----
$download = $this->prepare_item_for_response( (object) $download_data, $request );
$download = $this->prepare_response_for_collection( $download );
⋮----
public function prepare_item_for_response( $download, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $download, $request ) );
⋮----
protected function prepare_links( $download, $request ) {
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-customers-v1-controller.php">
use Automattic\WooCommerce\Internal\Utilities\Users;
⋮----
class WC_REST_Customers_V1_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'customers';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array(
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
private function allowed_roles(): array {
⋮----
public function create_item_permissions_check( $request ) {
⋮----
public function get_item_permissions_check( $request ) {
return $this->permissions_check(
⋮----
public function update_item_permissions_check( $request ) {
$permission_result = $this->permissions_check(
⋮----
... (129 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-order-notes-v1-controller.php">
class WC_REST_Order_Notes_V1_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'orders/(?P<order_id>[\d]+)/notes';
⋮----
protected $post_type = 'shop_order';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array(
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function create_item_permissions_check( $request ) {
⋮----
public function get_item_permissions_check( $request ) {
⋮----
if ( $order && ! wc_rest_check_post_permissions( $this->post_type, 'read', $order->get_id() ) ) {
⋮----
public function delete_item_permissions_check( $request ) {
⋮----
if ( $order && ! wc_rest_check_post_permissions( $this->post_type, 'delete', $order->get_id() ) ) {
⋮----
public function get_items( $request ) {
⋮----
... (40 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-order-refunds-v1-controller.php">
class WC_REST_Order_Refunds_V1_Controller extends WC_REST_Orders_V1_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'orders/(?P<order_id>[\d]+)/refunds';
⋮----
protected $post_type = 'shop_order_refund';
⋮----
public function __construct() {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
public function prepare_item_for_response( $post, $request ) {
⋮----
if ( ! $refund || $refund->get_parent_id() !== $order->get_id() ) {
⋮----
'id'           => $refund->get_id(),
'date_created' => wc_rest_prepare_date_response( $refund->get_date_created() ),
'amount'       => wc_format_decimal( $refund->get_amount(), $dp ),
'reason'       => $refund->get_reason(),
⋮----
foreach ( $refund->get_items() as $item_id => $item ) {
$product      = $item->get_product();
⋮----
... (43 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-orders-v1-controller.php">
use Automattic\WooCommerce\Internal\Utilities\Users;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Utilities\{ ArrayUtil, NumberUtil, StringUtil };
⋮----
class WC_REST_Orders_V1_Controller extends WC_REST_Posts_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'orders';
⋮----
protected $post_type = 'shop_order';
⋮----
public function __construct() {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function prepare_item_for_response( $post, $request ) {
⋮----
'id'                   => $order->get_id(),
'parent_id'            => $order->get_parent_id(),
'status'               => $order->get_status(),
... (243 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-product-attribute-terms-v1-controller.php">
class WC_REST_Product_Attribute_Terms_V1_Controller extends WC_REST_Terms_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'products/attributes/(?P<attribute_id>[\d]+)/terms';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array(
⋮----
'context'         => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function prepare_item_for_response( $item, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $item, $request ) );
⋮----
protected function update_term_meta_fields( $term, $request ) {
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-product-attributes-v1-controller.php">
class WC_REST_Product_Attributes_V1_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'products/attributes';
⋮----
protected $attribute = '';
⋮----
/**
	 * Cached taxonomies by attribute id.
	 *
	 * @var array
	 */
protected $taxonomies_by_id = array();
⋮----
/**
	 * Register the routes for product attributes.
	 */
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
$this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
... (72 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-product-categories-v1-controller.php">
class WC_REST_Product_Categories_V1_Controller extends WC_REST_Terms_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'products/categories';
⋮----
protected $taxonomy = 'product_cat';
⋮----
public function prepare_item_for_response( $item, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $item, $request ) );
⋮----
protected function update_term_meta_fields( $term, $request ) {
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-product-reviews-v1-controller.php">
class WC_REST_Product_Reviews_V1_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'products/(?P<product_id>[\d]+)/reviews';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => array_merge( $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array(
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_item_permissions_check( $request ) {
$review = $this->get_review( (int) $request['id'], (int) $request['product_id'] );
⋮----
public function create_item_permissions_check( $request ) {
⋮----
public function update_item_permissions_check( $request ) {
⋮----
public function delete_item_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
⋮----
$review = $this->prepare_item_for_response( $review_data, $request );
... (48 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-product-shipping-classes-v1-controller.php">
class WC_REST_Product_Shipping_Classes_V1_Controller extends WC_REST_Terms_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'products/shipping_classes';
⋮----
protected $taxonomy = 'product_shipping_class';
⋮----
public function prepare_item_for_response( $item, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $item, $request ) );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-product-tags-v1-controller.php">
class WC_REST_Product_Tags_V1_Controller extends WC_REST_Terms_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'products/tags';
⋮----
protected $taxonomy = 'product_tag';
⋮----
public function prepare_item_for_response( $item, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $item, $request ) );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-products-v1-controller.php">
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\CatalogVisibility;
use Automattic\WooCommerce\Utilities\I18nUtil;
⋮----
class WC_REST_Products_V1_Controller extends WC_REST_Posts_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'products';
⋮----
protected $post_type = 'product';
⋮----
public function __construct() {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
protected function get_post_types() {
⋮----
public function query_args( $args, $request ) {
... (513 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-report-sales-v1-controller.php">
class WC_REST_Report_Sales_V1_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'reports/sales';
⋮----
protected $report;
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
⋮----
$item   = $this->prepare_item_for_response( null, $request );
$data[] = $this->prepare_response_for_collection( $item );
⋮----
public function prepare_item_for_response( $_, $request ) {
⋮----
$this->setup_report( $filter );
⋮----
$customers = $users_query->get_results();
⋮----
$report_data     = $this->report->get_report_data();
⋮----
$data    = $this->add_additional_fields_to_object( $sales_data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-report-top-sellers-v1-controller.php">
class WC_REST_Report_Top_Sellers_V1_Controller extends WC_REST_Report_Sales_V1_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'reports/top_sellers';
⋮----
public function get_items( $request ) {
⋮----
$this->setup_report( $filter );
⋮----
$report_data = $this->report->get_order_report_data( array(
⋮----
'name'      => $product->get_name(),
⋮----
$item   = $this->prepare_item_for_response( (object) $top_seller, $request );
$data[] = $this->prepare_response_for_collection( $item );
⋮----
public function prepare_item_for_response( $top_seller, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( array(
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-reports-v1-controller.php">
class WC_REST_Reports_V1_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'reports';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
protected function get_reports() {
⋮----
public function get_items( $request ) {
⋮----
$reports = $this->get_reports();
⋮----
$item   = $this->prepare_item_for_response( (object) $report, $request );
$data[] = $this->prepare_response_for_collection( $item );
⋮----
public function prepare_item_for_response( $report, $request ) {
⋮----
$data = $this->add_additional_fields_to_object( $data, $request );
$data = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( array(
⋮----
public function get_item_schema() {
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-tax-classes-v1-controller.php">
class WC_REST_Tax_Classes_V1_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'taxes/classes';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function create_item_permissions_check( $request ) {
⋮----
public function delete_item_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
⋮----
$classes = WC_Tax::get_tax_classes();
⋮----
$class  = $this->prepare_item_for_response( $tax_class, $request );
$class  = $this->prepare_response_for_collection( $class );
⋮----
$response->header( 'X-WP-Total', (int) $total );
$response->header( 'X-WP-TotalPages', $total ? 1 : 0 );
⋮----
public function create_item( $request ) {
$tax_class = WC_Tax::create_tax_class( $request['name'] );
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-taxes-v1-controller.php">
use Automattic\WooCommerce\Internal\Traits\RestApiCache;
⋮----
class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'taxes';
⋮----
public function __construct() {
$this->initialize_rest_api_cache();
⋮----
public function register_routes() {
⋮----
'callback'            => $this->with_cache(
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
'callback'            => $this->with_cache( array( $this, 'get_item' ) ),
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function create_item_permissions_check( $request ) {
⋮----
public function get_item_permissions_check( $request ) {
... (111 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-webhook-deliveries-v1-controller.php">
class WC_REST_Webhook_Deliveries_V1_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'webhooks/(?P<webhook_id>[\d]+)/deliveries';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_item_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
⋮----
$delivery = $this->prepare_item_for_response( (object) $log, $request );
$delivery = $this->prepare_response_for_collection( $delivery );
⋮----
public function get_item( $request ) {
⋮----
public function prepare_item_for_response( $log, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $log ) );
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version1/class-wc-rest-webhooks-v1-controller.php">
class WC_REST_Webhooks_V1_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = 'webhooks';
⋮----
protected $post_type = 'shop_webhook';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
$this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function create_item_permissions_check( $request ) {
⋮----
public function get_item_permissions_check( $request ) {
⋮----
public function update_item_permissions_check( $request ) {
⋮----
public function delete_item_permissions_check( $request ) {
⋮----
public function batch_items_permissions_check( $request ) {
⋮----
... (89 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-coupons-v2-controller.php">
use Automattic\WooCommerce\Utilities\MetaDataUtil;
use Automattic\WooCommerce\Utilities\StringUtil;
⋮----
class WC_REST_Coupons_V2_Controller extends WC_REST_CRUD_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $rest_base = 'coupons';
⋮----
protected $post_type = 'shop_coupon';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
$this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
protected function get_object( $id ) {
⋮----
protected function get_formatted_item_data( $object ) {
$data = $object->get_data();
⋮----
'id'                          => $object->get_id(),
⋮----
public function prepare_object_for_response( $object, $request ) {
$data     = $this->get_formatted_item_data( $object );
... (38 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-customer-downloads-v2-controller.php">
class WC_REST_Customer_Downloads_V2_Controller extends WC_REST_Customer_Downloads_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
public function prepare_item_for_response( $download, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $download, $request ) );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-customers-v2-controller.php">
use Automattic\WooCommerce\Utilities\MetaDataUtil;
⋮----
class WC_REST_Customers_V2_Controller extends WC_REST_Customers_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected function get_formatted_item_data( $object ) {
$formatted_data                 = $this->get_formatted_item_data_core( $object );
$formatted_data['orders_count'] = $object->get_order_count();
$formatted_data['total_spent']  = $object->get_total_spent();
⋮----
protected function get_formatted_item_data_core( $object ) {
$data        = $object->get_data();
⋮----
$datetime              = 'date_created' === $key && is_subclass_of( $data[ $key ], 'DateTime' ) ? get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $data[ $key ]->getTimestamp() ) ) : $data[ $key ];
⋮----
'id'                 => $object->get_id(),
⋮----
'avatar_url'         => $object->get_avatar_url(),
⋮----
public function prepare_item_for_response( $user_data, $request ) {
⋮----
$data     = $this->get_formatted_item_data( $customer );
⋮----
$data     = $this->add_additional_fields_to_object( $data, $request );
$data     = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $user_data ) );
⋮----
protected function update_customer_meta_fields( $customer, $request ) {
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-network-orders-v2-controller.php">
use Automattic\WooCommerce\Enums\OrderInternalStatus;
⋮----
class WC_REST_Network_Orders_V2_Controller extends WC_REST_Orders_V2_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function get_public_item_schema() {
$schema = parent::get_public_item_schema();
⋮----
public function network_orders_permissions_check( $request ) {
$blog_id = $request->get_param( 'blog_id' );
⋮----
$permission = $this->get_items_permissions_check( $request );
⋮----
public function network_orders( $request ) {
⋮----
$items = $this->get_items( $request );
⋮----
$current_order['edit_url'] = get_admin_url( $blog_id, 'post.php?post=' . absint( $order->get_id() ) . '&action=edit' );
⋮----
$current_order['customer']        = trim( sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ), $order->get_billing_first_name(), $order->get_billing_last_name() ) );
$current_order['status_name']     = wc_get_order_status_name( $order->get_status() );
$current_order['formatted_total'] = $order->get_formatted_order_total();
⋮----
public function network_orders_filter_args( $args ) {
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-order-notes-v2-controller.php">
class WC_REST_Order_Notes_V2_Controller extends WC_REST_Order_Notes_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
public function get_items( $request ) {
⋮----
if ( ! $order || $this->post_type !== $order->get_type() ) {
⋮----
'post_id' => $order->get_id(),
⋮----
$order_note = $this->prepare_item_for_response( $note, $request );
$order_note = $this->prepare_response_for_collection( $order_note );
⋮----
public function prepare_item_for_response( $note, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $note ) );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
⋮----
public function get_collection_params() {
⋮----
$params['context'] = $this->get_context_param( array( 'default' => 'view' ) );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-order-refunds-v2-controller.php">
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Internal\Utilities\Types;
use Automattic\WooCommerce\Utilities\MetaDataUtil;
⋮----
class WC_REST_Order_Refunds_V2_Controller extends WC_REST_Orders_V2_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $rest_base = 'orders/(?P<order_id>[\d]+)/refunds';
⋮----
protected $post_type = 'shop_order_refund';
⋮----
protected $request = array();
⋮----
public function __construct() {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
protected function get_object( $id ) {
⋮----
protected function get_formatted_item_data( $object ) {
$data              = $object->get_data();
⋮----
'id'               => $object->get_id(),
... (50 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\OrderLineMetaValidator;
use Automattic\WooCommerce\Internal\Utilities\Users;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Utilities\ArrayUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Utilities\MetaDataUtil;
use Automattic\WooCommerce\Utilities\StringUtil;
⋮----
class WC_REST_Orders_V2_Controller extends WC_REST_CRUD_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $rest_base = 'orders';
⋮----
protected $post_type = 'shop_order';
⋮----
protected $hierarchical = true;
⋮----
protected $request = array();
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
... (297 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-payment-gateways-v2-controller.php">
class WC_REST_Payment_Gateways_V2_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $rest_base = 'payment_gateways';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_item_permissions_check( $request ) {
⋮----
public function update_items_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
$payment_gateways = WC()->payment_gateways->payment_gateways();
⋮----
$gateway             = $this->prepare_item_for_response( $payment_gateway, $request );
$gateway             = $this->prepare_response_for_collection( $gateway );
⋮----
$response->header( 'X-WP-Total', (int) $total );
$response->header( 'X-WP-TotalPages', $total ? 1 : 0 );
⋮----
public function get_item( $request ) {
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-product-attribute-terms-v2-controller.php">
class WC_REST_Product_Attribute_Terms_V2_Controller extends WC_REST_Product_Attribute_Terms_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-product-attributes-v2-controller.php">
class WC_REST_Product_Attributes_V2_Controller extends WC_REST_Product_Attributes_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-product-brands-v2-controller.php">
class WC_REST_Product_Brands_V2_Controller extends WC_REST_Product_Categories_V2_Controller {
⋮----
protected $rest_base = 'products/brands';
⋮----
protected $taxonomy = 'product_brand';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-product-categories-v2-controller.php">
class WC_REST_Product_Categories_V2_Controller extends WC_REST_Product_Categories_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
public function prepare_item_for_response( $item, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $item, $request ) );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-product-reviews-v2-controller.php">
class WC_REST_Product_Reviews_V2_Controller extends WC_REST_Product_Reviews_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $rest_base = 'products/(?P<product_id>[\d]+)/reviews';
⋮----
public function register_routes() {
parent::register_routes();
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function batch_items_permissions_check( $request ) {
⋮----
public function prepare_item_for_response( $review, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $review, $request ) );
⋮----
public function batch_items( $request ) {
$items       = array_filter( $request->get_params() );
$params      = $request->get_url_params();
⋮----
$request = new WP_REST_Request( $request->get_method() );
$request->set_body_params( $body_params );
⋮----
return parent::batch_items( $request );
⋮----
public function get_item_schema() {
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-product-shipping-classes-v2-controller.php">
class WC_REST_Product_Shipping_Classes_V2_Controller extends WC_REST_Product_Shipping_Classes_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-product-tags-v2-controller.php">
class WC_REST_Product_Tags_V2_Controller extends WC_REST_Product_Tags_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-product-variations-v2-controller.php">
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Internal\Caches\ProductTransientsDeferrer;
use Automattic\WooCommerce\Utilities\I18nUtil;
use Automattic\WooCommerce\Utilities\MetaDataUtil;
⋮----
class WC_REST_Product_Variations_V2_Controller extends WC_REST_Products_V2_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $rest_base = 'products/(?P<product_id>[\d]+)/variations';
⋮----
protected $post_type = 'product_variation';
⋮----
protected function get_default_response_entity_type(): ?string {
⋮----
protected function get_hooks_relevant_to_caching( WP_REST_Request $request, ?string $endpoint_id = null ): array {
⋮----
protected function get_version_strings_relevant_to_caching( WP_REST_Request $request, ?string $endpoint_id = null ): array {
⋮----
$product_id = $request->get_param( 'product_id' );
⋮----
public function register_routes() {
⋮----
'callback'            => $this->with_cache(
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
... (218 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-products-v2-controller.php">
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\CatalogVisibility;
use Automattic\WooCommerce\Internal\RestApi\ProductRequestPreparationTrait;
use Automattic\WooCommerce\Internal\Traits\RestApiCache;
use Automattic\WooCommerce\Utilities\I18nUtil;
use Automattic\WooCommerce\Utilities\MetaDataUtil;
⋮----
class WC_REST_Products_V2_Controller extends WC_REST_CRUD_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $rest_base = 'products';
⋮----
protected $post_type = 'product';
⋮----
protected $hierarchical = true;
⋮----
public function __construct() {
⋮----
$this->initialize_rest_api_cache();
⋮----
protected function get_default_response_entity_type(): ?string {
⋮----
protected function get_hooks_relevant_to_caching( WP_REST_Request $request, ?string $endpoint_id = null ): array {
⋮----
protected function get_data_for_etag( array $data, WP_REST_Request $request, ?string $endpoint_id = null ): array {
return $this->remove_related_ids_from_response_data( $data );
... (497 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-report-sales-v2-controller.php">
class WC_REST_Report_Sales_V2_Controller extends WC_REST_Report_Sales_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-report-top-sellers-v2-controller.php">
class WC_REST_Report_Top_Sellers_V2_Controller extends WC_REST_Report_Top_Sellers_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-reports-v2-controller.php">
class WC_REST_Reports_V2_Controller extends WC_REST_Reports_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-setting-options-v2-controller.php">
class WC_REST_Setting_Options_V2_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $rest_base = 'settings/(?P<group_id>[\w-]+)';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_item( $request ) {
$setting = $this->get_setting( $request['group_id'], $request['id'] );
⋮----
$response = $this->prepare_item_for_response( $setting, $request );
⋮----
public function get_items( $request ) {
$settings = $this->get_group_settings( $request['group_id'] );
⋮----
$setting = $this->prepare_item_for_response( $setting_obj, $request );
$setting = $this->prepare_response_for_collection( $setting );
if ( $this->is_setting_type_valid( $setting['type'] ) ) {
⋮----
public function get_group_settings( $group_id ) {
⋮----
$this->prime_options_cache_for_settings( $settings );
⋮----
$setting    = $this->filter_setting( $setting );
⋮----
$admin_setting_value = WC_Admin_Settings::get_option( $option_key, $default );
⋮----
... (65 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-settings-v2-controller.php">
class WC_REST_Settings_V2_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $rest_base = 'settings';
⋮----
public function register_routes() {
⋮----
public function get_items( $request ) {
⋮----
$defaults        = $this->group_defaults();
⋮----
$group_obj  = $this->filter_group( $group );
$group_data = $this->prepare_item_for_response( $group_obj, $request );
$group_data = $this->prepare_response_for_collection( $group_data );
⋮----
protected function prepare_links( $group_id ) {
⋮----
public function prepare_item_for_response( $item, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $item, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $item['id'] ) );
⋮----
public function filter_group( $group ) {
⋮----
public function allowed_group_keys( $key ) {
⋮----
protected function group_defaults() {
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-shipping-methods-v2-controller.php">
class WC_REST_Shipping_Methods_V2_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $rest_base = 'shipping_methods';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_item_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
$wc_shipping = WC_Shipping::instance();
⋮----
foreach ( $wc_shipping->get_shipping_methods() as $id => $shipping_method ) {
$method = $this->prepare_item_for_response( $shipping_method, $request );
$method = $this->prepare_response_for_collection( $method );
⋮----
$response->header( 'X-WP-Total', (int) $total );
$response->header( 'X-WP-TotalPages', $total ? 1 : 0 );
⋮----
public function get_item( $request ) {
⋮----
$methods     = $wc_shipping->get_shipping_methods();
⋮----
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-shipping-zone-locations-v2-controller.php">
class WC_REST_Shipping_Zone_Locations_V2_Controller extends WC_REST_Shipping_Zones_Controller_Base {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_items( $request ) {
$zone = $this->get_zone( (int) $request['id'] );
⋮----
$locations = $zone->get_zone_locations();
⋮----
$location = $this->prepare_item_for_response( $location_obj, $request );
$location = $this->prepare_response_for_collection( $location );
⋮----
$response->header( 'X-WP-Total', $total );
$response->header( 'X-WP-TotalPages', $total ? 1 : 0 );
⋮----
public function update_items( $request ) {
⋮----
if ( 0 === $zone->get_id() ) {
⋮----
$raw_locations = $request->get_json_params();
⋮----
$zone->set_locations( $locations );
$zone->save();
⋮----
return $this->get_items( $request );
⋮----
public function prepare_item_for_response( $item, $request ) {
⋮----
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-shipping-zone-methods-v2-controller.php">
class WC_REST_Shipping_Zone_Methods_V2_Controller extends WC_REST_Shipping_Zones_Controller_Base {
⋮----
public function register_routes() {
⋮----
$this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array(
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_item( $request ) {
$zone = $this->get_zone( $request['zone_id'] );
⋮----
$methods     = $zone->get_shipping_methods();
⋮----
$data = $this->prepare_item_for_response( $method, $request );
⋮----
public function get_items( $request ) {
⋮----
$methods = $zone->get_shipping_methods();
⋮----
$method = $this->prepare_item_for_response( $method_obj, $request );
⋮----
$response->header( 'X-WP-Total', $total );
$response->header( 'X-WP-TotalPages', $total ? 1 : 0 );
⋮----
public function create_item( $request ) {
⋮----
$zone      = $this->get_zone( $request['zone_id'] );
⋮----
$instance_id = $zone->add_shipping_method( $method_id );
⋮----
... (47 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-shipping-zones-v2-controller.php">
class WC_REST_Shipping_Zones_V2_Controller extends WC_REST_Shipping_Zones_Controller_Base {
⋮----
public function register_routes() {
⋮----
$this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array(
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_item( $request ) {
$zone = $this->get_zone( $request->get_param( 'id' ) );
⋮----
$data = $zone->get_data();
$data = $this->prepare_item_for_response( $data, $request );
$data = $this->prepare_response_for_collection( $data );
⋮----
public function get_items( $request ) {
$rest_of_the_world = WC_Shipping_Zones::get_zone_by( 'zone_id', 0 );
⋮----
$zones = WC_Shipping_Zones::get_zones();
array_unshift( $zones, $rest_of_the_world->get_data() );
⋮----
$zone   = $this->prepare_item_for_response( $zone_obj, $request );
$zone   = $this->prepare_response_for_collection( $zone );
⋮----
$response->header( 'X-WP-Total', $total );
$response->header( 'X-WP-TotalPages', 1 );
⋮----
public function create_item( $request ) {
⋮----
if ( ! is_null( $request->get_param( 'name' ) ) ) {
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-tools-v2-controller.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Automattic\WooCommerce\Internal\ProductFilters\CacheController;
⋮----
class WC_REST_System_Status_Tools_V2_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $rest_base = 'system_status/tools';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_item_permissions_check( $request ) {
⋮----
public function update_item_permissions_check( $request ) {
⋮----
public function get_tools() {
⋮----
if ( ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'photon' ) ) || ! apply_filters( 'woocommerce_background_image_regeneration', true ) ) {
⋮----
if ( Constants::is_true( 'DISABLE_WP_CRON' ) ) {
⋮----
$tools['regenerate_product_lookup_tables']['status_text'] = $this->get_regenerating_lookup_table_status_text();
⋮----
... (88 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-system-status-v2-controller.php">
use Automattic\WooCommerce\Internal\WCCom\ConnectionHelper;
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register as Download_Directories;
use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer as Order_DataSynchronizer;
use Automattic\WooCommerce\Utilities\{ LoggingUtil, OrderUtil, PluginUtil };
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Enums\DefaultCustomerAddress;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
⋮----
class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $rest_base = 'system_status';
⋮----
public static function register_cache_clean() {
⋮----
\WC_REST_System_Status_V2_Controller::clean_theme_cache();
\WC_REST_System_Status_V2_Controller::clean_plugin_cache();
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
$fields   = $this->get_fields_for_response( $request );
$mappings = $this->get_item_mappings_per_fields( $fields );
$response = $this->prepare_item_for_response( $mappings, $request );
⋮----
... (154 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-tax-classes-v2-controller.php">
class WC_REST_Tax_Classes_V2_Controller extends WC_REST_Tax_Classes_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
public function get_item( $request ) {
⋮----
$tax_class = WC_Tax::get_tax_class_by( 'slug', sanitize_title( $request['slug'] ) );
⋮----
$class  = $this->prepare_item_for_response( $tax_class, $request );
$class  = $this->prepare_response_for_collection( $class );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-taxes-v2-controller.php">
class WC_REST_Taxes_V2_Controller extends WC_REST_Taxes_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-webhook-deliveries-v2-controller.php">
class WC_REST_Webhook_Deliveries_V2_Controller extends WC_REST_Webhook_Deliveries_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
public function prepare_item_for_response( $log, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $log ) );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-webhooks-v2-controller.php">
class WC_REST_Webhooks_V2_Controller extends WC_REST_Webhooks_V1_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
public function prepare_item_for_response( $id, $request ) {
⋮----
'id'                => $webhook->get_id(),
'name'              => $webhook->get_name(),
'status'            => $webhook->get_status(),
'topic'             => $webhook->get_topic(),
'resource'          => $webhook->get_resource(),
'event'             => $webhook->get_event(),
'hooks'             => $webhook->get_hooks(),
'delivery_url'      => $webhook->get_delivery_url(),
'date_created'      => wc_rest_prepare_date_response( $webhook->get_date_created(), false ),
'date_created_gmt'  => wc_rest_prepare_date_response( $webhook->get_date_created() ),
'date_modified'     => wc_rest_prepare_date_response( $webhook->get_date_modified(), false ),
'date_modified_gmt' => wc_rest_prepare_date_response( $webhook->get_date_modified() ),
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $webhook->get_id(), $request ) );
⋮----
protected function get_default_api_version() {
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-controller.php">
abstract class WC_REST_Controller extends WP_REST_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = '';
⋮----
/**
	 * Used to cache computed return fields.
	 *
	 * @var null|array
	 */
private $_fields = null;
⋮----
/**
	 * Used to verify if cached fields are for correct request object.
	 *
	 * @var null|WP_REST_Request
	 */
private $_request = null;
⋮----
/**
	 * Add the schema from additional fields to an schema array.
	 *
	 * The type of object is inferred from the passed schema.
	 *
	 * @param array $schema Schema array.
	 *
	 * @return array
	 */
protected function add_additional_fields_schema( $schema ) {
... (131 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-coupons-controller.php">
class WC_REST_Coupons_Controller extends WC_REST_Coupons_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected function prepare_objects_query( $request ) {
$args = parent::prepare_objects_query( $request );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-crud-controller.php">
abstract class WC_REST_CRUD_Controller extends WC_REST_Posts_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $hierarchical = false;
⋮----
protected function get_object( $id ) {
⋮----
public function get_item_permissions_check( $request ) {
$object = $this->get_object( (int) $request['id'] );
⋮----
if ( $object && 0 !== $object->get_id() && ! wc_rest_check_post_permissions( $this->post_type, 'read', $object->get_id() ) ) {
⋮----
public function update_item_permissions_check( $request ) {
⋮----
if ( $object && 0 !== $object->get_id() && ! wc_rest_check_post_permissions( $this->post_type, 'edit', $object->get_id() ) ) {
⋮----
public function delete_item_permissions_check( $request ) {
⋮----
if ( $object && 0 !== $object->get_id() && ! wc_rest_check_post_permissions( $this->post_type, 'delete', $object->get_id() ) ) {
⋮----
protected function get_permalink( $object ) {
⋮----
/**
	 * Prepares the object for the REST response.
	 *
	 * @since  3.0.0
	 * @param  WC_Data         $object  Object data.
	 * @param  WP_REST_Request $request Request object.
	 * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
... (101 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-customer-downloads-controller.php">
class WC_REST_Customer_Downloads_Controller extends WC_REST_Customer_Downloads_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-customers-controller.php">
class WC_REST_Customers_Controller extends WC_REST_Customers_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected function get_formatted_item_data( $object ) {
return $this->get_formatted_item_data_core( $object );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-data-continents-controller.php">
use Automattic\WooCommerce\Internal\Traits\RestApiCache;
⋮----
class WC_REST_Data_Continents_Controller extends WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'data/continents';
⋮----
public function __construct() {
$this->initialize_rest_api_cache();
⋮----
public function register_routes() {
⋮----
'callback'            => $this->with_cache( array( $this, 'get_items' ) ),
⋮----
'callback'            => $this->with_cache( array( $this, 'get_item' ) ),
⋮----
public function get_continent( $continent_code, $request ) {
$continents  = WC()->countries->get_continents();
$countries   = WC()->countries->get_countries();
$states      = WC()->countries->get_states();
$locale_info = include WC()->plugin_path() . '/i18n/locale-info.php';
⋮----
public function get_items( $request ) {
$continents = WC()->countries->get_continents();
⋮----
$continent = $this->get_continent( $continent_code, $request );
$response  = $this->prepare_item_for_response( $continent, $request );
$data[]    = $this->prepare_response_for_collection( $response );
⋮----
... (27 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-data-controller.php">
class WC_REST_Data_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'data';
⋮----
public function register_routes() {
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_item_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
⋮----
$item   = $this->prepare_item_for_response( (object) $resource, $request );
$data[] = $this->prepare_response_for_collection( $item );
⋮----
public function prepare_item_for_response( $resource, $request ) {
⋮----
$data = $this->add_additional_fields_to_object( $data, $request );
$data = $this->filter_response_by_context( $data, 'view' );
⋮----
$response->add_links( $this->prepare_links( $resource ) );
⋮----
protected function prepare_links( $item ) {
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-data-countries-controller.php">
use Automattic\WooCommerce\Internal\Traits\RestApiCache;
⋮----
class WC_REST_Data_Countries_Controller extends WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'data/countries';
⋮----
public function __construct() {
$this->initialize_rest_api_cache();
⋮----
public function register_routes() {
⋮----
'callback'            => $this->with_cache( array( $this, 'get_items' ) ),
⋮----
'callback'            => $this->with_cache( array( $this, 'get_item' ) ),
⋮----
public function get_country( $country_code, $request ) {
$countries = WC()->countries->get_countries();
$states    = WC()->countries->get_states();
⋮----
public function get_items( $request ) {
⋮----
$country  = $this->get_country( $country_code, $request );
$response = $this->prepare_item_for_response( $country, $request );
$data[]   = $this->prepare_response_for_collection( $response );
⋮----
public function get_item( $request ) {
$data = $this->get_country( strtoupper( $request['location'] ), $request );
⋮----
... (24 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-data-currencies-controller.php">
use Automattic\WooCommerce\Internal\Traits\RestApiCache;
⋮----
class WC_REST_Data_Currencies_Controller extends WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'data/currencies';
⋮----
public function __construct() {
$this->initialize_rest_api_cache();
⋮----
public function register_routes() {
⋮----
'callback'            => $this->with_cache( array( $this, 'get_items' ) ),
⋮----
'callback'            => $this->with_cache( array( $this, 'get_item' ) ),
⋮----
public function get_currency( $code, $request ) {
⋮----
public function get_items( $request ) {
⋮----
$currency = $this->get_currency( $code, $request );
$response = $this->prepare_item_for_response( $currency, $request );
$data[]   = $this->prepare_response_for_collection( $response );
⋮----
public function get_item( $request ) {
$data = $this->get_currency( strtoupper( $request['currency'] ), $request );
⋮----
return $this->prepare_item_for_response( $data, $request );
⋮----
... (26 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-layout-templates-controller.php">
class WC_REST_Layout_Templates_Controller {
⋮----
public function register_routes(): void {}
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-network-orders-controller.php">
class WC_REST_Network_Orders_Controller extends WC_REST_Network_Orders_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-order-notes-controller.php">
class WC_REST_Order_Notes_Controller extends WC_REST_Order_Notes_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
public function prepare_item_for_response( $note, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $note ) );
⋮----
public function create_item( $request ) {
⋮----
if ( ! $order || $this->post_type !== $order->get_type() ) {
⋮----
$note_id = $order->add_order_note( $request['note'], $request['customer_note'], $request['added_by_user'] );
⋮----
$this->update_additional_fields_for_object( $note, $request );
⋮----
$request->set_param( 'context', 'edit' );
$response = $this->prepare_item_for_response( $note, $request );
⋮----
$response->set_status( 201 );
$response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, str_replace( '(?P<order_id>[\d]+)', $order->get_id(), $this->rest_base ), $note_id ) ) );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-order-refunds-controller.php">
use Automattic\WooCommerce\Internal\RestApiParameterUtil;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Refunds\DataUtils;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Refunds\Schema\RefundPreviewSchema;
use Automattic\WooCommerce\Utilities\MetaDataUtil;
⋮----
class WC_REST_Order_Refunds_Controller extends WC_REST_Order_Refunds_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
public function register_routes() {
parent::register_routes();
⋮----
'line_items' => $this->get_preview_line_items_arg_schema(),
⋮----
public function preview_refund( $request ) {
⋮----
$preview = $this->get_data_utils()->compute_refund_preview_or_error( $order, $request['line_items'], 'wc-rest-refunds' );
⋮----
return $this->prefix_error_code( $preview );
⋮----
$preview = $this->add_preview_additional_fields( $preview, $request );
⋮----
private function add_preview_additional_fields( array $preview, $request ): array {
$additional_fields = $this->get_additional_fields( 'order_refund_preview' );
⋮----
$fields_for_response = $this->get_preview_fields_for_response( $request );
⋮----
private function get_preview_fields_for_response( $request ): array {
$schema     = $this->get_public_preview_schema();
... (67 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
use Automattic\WooCommerce\Internal\Utilities\Users;
use Automattic\WooCommerce\Utilities\ArrayUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Utilities\MetaDataUtil;
use Automattic\WooCommerce\Utilities\StringUtil;
⋮----
class WC_REST_Orders_Controller extends WC_REST_Orders_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected function calculate_coupons( $request, $order ) {
⋮----
$current_order_coupons      = array_values( $order->get_coupons() );
⋮----
return wc_strtolower( $coupon->get_code() );
⋮----
$coupon_code = ArrayUtil::get_value_or_default( $item, 'code' );
if ( StringUtil::is_null_or_whitespace( $coupon_code ) ) {
⋮----
$check_result = $discounts->is_coupon_valid( $coupon );
⋮----
throw new WC_REST_Exception( 'woocommerce_rest_' . $check_result->get_error_code(), $check_result->get_error_message(), 400 );
⋮----
foreach ( $order->get_items( 'coupon' ) as $existing_coupon ) {
$order->remove_coupon( $existing_coupon->get_code() );
⋮----
$results = $order->apply_coupon( $new_coupon );
⋮----
... (91 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-payment-gateways-controller.php">
class WC_REST_Payment_Gateways_Controller extends WC_REST_Payment_Gateways_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
public function prepare_item_for_response( $gateway, $request ) {
⋮----
'method_title'       => $gateway->get_method_title(),
'method_description' => $gateway->get_method_description(),
⋮----
'settings'           => $this->get_settings( $gateway ),
⋮----
$data    = $this->add_additional_fields_to_object( $item, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $gateway, $request ) );
⋮----
public function get_settings( $gateway ) {
⋮----
$gateway->init_form_fields();
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
⋮----
public function validate_setting_multiselect_field( $values, $setting ) {
⋮----
$valid_keys = $this->flatten_options_keys( $setting['options'] );
⋮----
private function flatten_options_keys( array $options ): array {
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-paypal-buttons-controller.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Gateways\PayPal\Constants as PayPalConstants;
use Automattic\WooCommerce\Gateways\PayPal\Request as PayPalRequest;
⋮----
class WC_REST_Paypal_Buttons_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'paypal-buttons';
⋮----
public function register_routes() {
⋮----
public function validate_create_order_request( WP_REST_Request $request ) {
if ( $request->get_header( 'Nonce' ) ) {
$nonce = $request->get_header( 'Nonce' );
⋮----
public function validate_cancel_payment_request( WP_REST_Request $request ) {
⋮----
public function create_order( WP_REST_Request $request ) {
$data = $request->get_json_params();
⋮----
if ( ! $order_key || ! hash_equals( $order->get_order_key(), $order_key ) ) {
⋮----
if ( ! in_array( $order->get_status(), array( OrderStatus::CHECKOUT_DRAFT, OrderStatus::PENDING ), true ) ) {
⋮----
$gateway = WC_Gateway_Paypal::get_instance();
⋮----
$order->set_payment_method( $gateway->id );
$order->save();
⋮----
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-paypal-standard-controller.php">
use Automattic\WooCommerce\Gateways\PayPal\Helper as PayPalHelper;
use Automattic\WooCommerce\Gateways\PayPal\Request as PayPalRequest;
use Automattic\WooCommerce\Gateways\PayPal\Constants as PayPalConstants;
use Automattic\WooCommerce\Enums\OrderStatus;
⋮----
class WC_REST_Paypal_Standard_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'paypal-standard';
⋮----
public function register_routes() {
⋮----
public function validate_shipping_callback_request( WP_REST_Request $request ) {
$purchase_units = $request->get_param( 'purchase_units' );
⋮----
$order = PayPalHelper::get_wc_order_from_paypal_custom_id( $purchase_units[0]['custom_id'] );
⋮----
if ( ! $order->meta_exists( PayPalConstants::PAYPAL_ORDER_META_SHIPPING_CALLBACK_TOKEN ) ) {
⋮----
$token = $request->get_param( 'token' );
⋮----
$shipping_callback_token = $order->get_meta( PayPalConstants::PAYPAL_ORDER_META_SHIPPING_CALLBACK_TOKEN, true );
⋮----
public function process_shipping_callback( WP_REST_Request $request ) {
$paypal_order_id  = $request->get_param( 'id' );
$shipping_address = $request->get_param( 'shipping_address' );
$shipping_option  = $request->get_param( 'shipping_option' );
$purchase_units   = $request->get_param( 'purchase_units' );
⋮----
... (120 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-paypal-webhooks-controller.php">
use Automattic\WooCommerce\Gateways\PayPal\WebhookHandler as PayPalWebhookHandler;
⋮----
class WC_REST_Paypal_Webhooks_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'paypal-webhooks';
⋮----
public function register_routes() {
⋮----
public function validate_webhook( WP_REST_Request $request ) {
⋮----
return \Automattic\Jetpack\Connection\REST_Authentication::is_signed_with_blog_token();
⋮----
WC_Gateway_Paypal::log( 'REST authentication method not available. Webhook data: ' . wc_print_r( $request->get_json_params(), true ), 'error' );
⋮----
public function process_webhook( WP_REST_Request $request ) {
⋮----
$webhook_handler->process_webhook( $request );
⋮----
WC_Gateway_Paypal::log( 'Error processing webhook: ' . $e->getMessage() );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-posts-controller.php">
abstract class WC_REST_Posts_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v1';
⋮----
protected $rest_base = '';
⋮----
/**
	 * Post type.
	 *
	 * @var string
	 */
protected $post_type = '';
⋮----
/**
	 * Controls visibility on frontend.
	 *
	 * @var string
	 */
protected $public = false;
⋮----
/**
	 * Check if a given request has access to read items.
	 *
	 * @param  WP_REST_Request $request Full details about the request.
	 * @return WP_Error|boolean
	 */
public function get_items_permissions_check( $request ) {
⋮----
public function create_item_permissions_check( $request ) {
⋮----
... (79 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-product-attribute-terms-controller.php">
class WC_REST_Product_Attribute_Terms_Controller extends WC_REST_Product_Attribute_Terms_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-product-attributes-controller.php">
class WC_REST_Product_Attributes_Controller extends WC_REST_Product_Attributes_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
private function generate_unique_slug( $attribute_name ) {
⋮----
$results = $wpdb->get_results(
$wpdb->prepare( "SELECT attribute_name FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_name LIKE %s ORDER BY attribute_id DESC LIMIT 1", $root_slug . '%' )
⋮----
public function create_item( $request ) {
⋮----
$slug = $this->generate_unique_slug( $request['name'] );
⋮----
return new WP_Error( 'woocommerce_rest_cannot_create', $id->get_error_message(), array( 'status' => 400 ) );
⋮----
$attribute = $this->get_attribute( $id );
⋮----
$this->update_additional_fields_for_object( $attribute, $request );
⋮----
$request->set_param( 'context', 'edit' );
$response = $this->prepare_item_for_response( $attribute, $request );
⋮----
$response->set_status( 201 );
$response->header( 'Location', rest_url( '/' . $this->namespace . '/' . $this->rest_base . '/' . $attribute->attribute_id ) );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-product-brands-controller.php">
class WC_REST_Product_Brands_Controller extends WC_REST_Product_Categories_Controller {
⋮----
protected $rest_base = 'products/brands';
⋮----
protected $taxonomy = 'product_brand';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-product-categories-controller.php">
class WC_REST_Product_Categories_Controller extends WC_REST_Product_Categories_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
public function prepare_item_for_response( $item, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $item, $request ) );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
⋮----
protected function update_term_meta_fields( $term, $request ) {
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-product-custom-fields-controller.php">
use Automattic\WooCommerce\Utilities\I18nUtil;
⋮----
class WC_REST_Product_Custom_Fields_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'products/custom-fields';
⋮----
protected $post_type = 'product';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function get_item_names( $request ) {
⋮----
$base_query = $wpdb->prepare(
⋮----
$wpdb->esc_like( '_' ) . '%',
'%' . $wpdb->esc_like( $search ) . '%'
⋮----
$query .= $wpdb->prepare( " ORDER BY post_metas.meta_key $order LIMIT %d, %d", $offset, $limit );
⋮----
$query_result = $wpdb->get_results( $query );
⋮----
$total_items = $wpdb->get_var( $total_query );
⋮----
$response->header( 'X-WP-Total', (int) $total_items );
⋮----
$response->header( 'X-WP-TotalPages', (int) $max_pages );
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-product-reviews-controller.php">
class WC_REST_Product_Reviews_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'products/reviews';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
$this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), array(
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_item_permissions_check( $request ) {
$review = $this->get_review( (int) $request['id'] );
⋮----
public function create_item_permissions_check( $request ) {
⋮----
public function update_item_permissions_check( $request ) {
⋮----
public function delete_item_permissions_check( $request ) {
⋮----
public function batch_items_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
... (99 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-product-shipping-classes-controller.php">
class WC_REST_Product_Shipping_Classes_Controller extends WC_REST_Product_Shipping_Classes_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
public function register_routes() {
parent::register_routes();
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function suggest_slug( $request ) {
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-product-tags-controller.php">
class WC_REST_Product_Tags_Controller extends WC_REST_Product_Tags_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-product-variations-controller.php">
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareRestControllerTrait;
use Automattic\WooCommerce\Internal\VariationGallery\LegacyVariationGalleryCompatibility;
use Automattic\WooCommerce\Internal\VariationGallery\Telemetry as VariationGalleryTelemetry;
use Automattic\WooCommerce\Utilities\I18nUtil;
use Automattic\WooCommerce\Utilities\MetaDataUtil;
⋮----
use Automattic\Jetpack\Constants;
⋮----
class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
private $exclude_status = array();
⋮----
public function register_routes() {
parent::register_routes();
⋮----
'properties'  => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
protected function get_downloads( $product, $context = 'view' ) {
⋮----
if ( $product->is_downloadable() || 'edit' === $context ) {
foreach ( $product->get_downloads() as $file_id => $file ) {
⋮----
public function prepare_object_for_response( $object, $request ) {
... (221 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-products-catalog-controller.php">
class WC_REST_Products_Catalog_Controller {
⋮----
public function register_routes(): void {}
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-products-controller.php">
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\CatalogVisibility;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareRestControllerTrait;
use Automattic\WooCommerce\Internal\RestApi\ProductRequestPreparationTrait;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use Automattic\WooCommerce\Utilities\I18nUtil;
use Automattic\WooCommerce\Utilities\MetaDataUtil;
⋮----
class WC_REST_Products_Controller extends WC_REST_Products_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
private $search_sku_arg_value = '';
⋮----
/**
	 * If the 'search_name_or_sku' argument is present this will be set
	 * to an array of the (space-separated) tokens that form the argument value.
	 *
	 * @var array|null
	 */
private $search_name_or_sku_tokens = null;
⋮----
private $search_fields_tokens = null;
⋮----
private $suggested_products_ids = array();
⋮----
private $exclude_status = array();
... (307 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-refunds-controller.php">
class WC_REST_Refunds_Controller extends WC_REST_Order_Refunds_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'refunds';
⋮----
protected $post_type = 'shop_order_refund';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
protected function prepare_objects_query( $request ) {
$args = parent::prepare_objects_query( $request );
⋮----
public function prepare_object_for_response( $refund, $request ) {
⋮----
$data    = $this->get_formatted_item_data( $refund );
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
$response->add_links( $this->prepare_links( $refund, $request ) );
⋮----
protected function get_formatted_item_data( $refund ) {
$data = parent::get_formatted_item_data( $refund );
⋮----
'parent_id' => $refund->get_parent_id(),
⋮----
protected function prepare_links( $refund, $request ) {
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-report-coupons-totals-controller.php">
class WC_REST_Report_Coupons_Totals_Controller extends WC_REST_Reports_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'reports/coupons/totals';
⋮----
protected function get_reports() {
⋮----
$results = $wpdb->get_results(
$wpdb->prepare( "
⋮----
public function prepare_item_for_response( $report, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-report-customers-totals-controller.php">
class WC_REST_Report_Customers_Totals_Controller extends WC_REST_Reports_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'reports/customers/totals';
⋮----
protected function get_reports() {
⋮----
$customers_query->prepare_query(
⋮----
$total_paying = $wpdb->get_var( "SELECT COUNT(*) {$customers_query->query_from} {$customers_query->query_where}" );
⋮----
public function prepare_item_for_response( $report, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-report-orders-totals-controller.php">
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class WC_REST_Report_Orders_Totals_Controller extends WC_REST_Reports_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'reports/orders/totals';
⋮----
protected function get_reports() {
$totals = OrderUtil::get_count_for_type( 'shop_order' );
⋮----
public function prepare_item_for_response( $report, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-report-products-totals-controller.php">
class WC_REST_Report_Products_Totals_Controller extends WC_REST_Reports_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'reports/products/totals';
⋮----
protected function get_reports() {
⋮----
public function prepare_item_for_response( $report, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-report-reviews-totals-controller.php">
class WC_REST_Report_Reviews_Totals_Controller extends WC_REST_Reports_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'reports/reviews/totals';
⋮----
protected function get_reports() {
⋮----
$comment_query->parse_query(
⋮----
// A callback that empties any of these would leave either invalid SQL or a total with no rating buckets.
⋮----
$rows = $wpdb->get_results( "SELECT {$fields} FROM {$wpdb->comments} {$join} WHERE {$where} GROUP BY {$groupby}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Every clause is either built above from literals and $wpdb table names or supplied by a comments_clauses callback, exactly as WP_Comment_Query assembles them.
⋮----
// Never cache a failed aggregate; a zeroed report would stick until the next comment changed.
⋮----
public function prepare_item_for_response( $report, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-report-sales-controller.php">
class WC_REST_Report_Sales_Controller extends WC_REST_Report_Sales_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
public function prepare_item_for_response( $_, $request ) {
$response = parent::prepare_item_for_response( $_, $request );
$data     = $response->get_data();
⋮----
$report_data = $report->get_report_data();
⋮----
$response->set_data( $data );
⋮----
public function get_item_schema() {
$schema = parent::get_item_schema();
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-report-top-sellers-controller.php">
class WC_REST_Report_Top_Sellers_Controller extends WC_REST_Report_Top_Sellers_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-reports-controller.php">
class WC_REST_Reports_Controller extends WC_REST_Reports_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected function get_reports() {
$reports = parent::get_reports();
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-setting-options-controller.php">
class WC_REST_Setting_Options_Controller extends WC_REST_Setting_Options_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
public function get_setting( $group_id, $setting_id ) {
$setting = parent::get_setting( $group_id, $setting_id );
⋮----
public function allowed_setting_keys( $key ) {
⋮----
public function get_group_settings( $group_id ) {
⋮----
$this->prime_options_cache_for_settings( $settings );
⋮----
$setting    = $this->filter_setting( $setting );
⋮----
$admin_setting_value = WC_Admin_Settings::get_option( $option_key, $default );
⋮----
$setting['options'] = WC()->countries->get_countries();
⋮----
$setting['options'] = $this->get_countries_and_states();
⋮----
private function get_countries_and_states() {
$countries = WC()->countries->get_countries();
⋮----
$states = WC()->countries->get_states( $key );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-settings-controller.php">
class WC_REST_Settings_Controller extends WC_REST_Settings_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
public function register_routes() {
parent::register_routes();
⋮----
public function update_items_permissions_check( $request ) {
⋮----
public function update_item( $request ) {
⋮----
$response           = $options_controller->update_item( $request );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-shipping-methods-controller.php">
class WC_REST_Shipping_Methods_Controller extends WC_REST_Shipping_Methods_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-shipping-zone-locations-controller.php">
class WC_REST_Shipping_Zone_Locations_Controller extends WC_REST_Shipping_Zone_Locations_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-shipping-zone-methods-controller.php">
class WC_REST_Shipping_Zone_Methods_Controller extends WC_REST_Shipping_Zone_Methods_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
public function get_item_schema() {
⋮----
$schema = parent::get_item_schema();
⋮----
return $this->add_additional_fields_schema( $schema );
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-shipping-zones-controller-base.php">
abstract class WC_REST_Shipping_Zones_Controller_Base extends WC_REST_Controller {
⋮----
protected $namespace = 'wc/v2';
⋮----
protected $rest_base = 'shipping/zones';
⋮----
protected function get_zone( $zone_id ) {
$zone = WC_Shipping_Zones::get_zone_by( 'zone_id', $zone_id );
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function create_item_permissions_check( $request ) {
⋮----
public function update_items_permissions_check( $request ) {
⋮----
public function delete_items_permissions_check( $request ) {
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-shipping-zones-controller.php">
class WC_REST_Shipping_Zones_Controller extends WC_REST_Shipping_Zones_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-system-status-controller.php">
class WC_REST_System_Status_Controller extends WC_REST_System_Status_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-system-status-tools-controller.php">
class WC_REST_System_Status_Tools_Controller extends WC_REST_System_Status_Tools_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-tax-classes-controller.php">
class WC_REST_Tax_Classes_Controller extends WC_REST_Tax_Classes_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-taxes-controller.php">
class WC_REST_Taxes_Controller extends WC_REST_Taxes_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected function add_tax_rate_locales( $data, $tax ) {
⋮----
$data              = parent::add_tax_rate_locales( $data, $tax );
⋮----
$locales = $wpdb->get_results(
$wpdb->prepare(
⋮----
public function get_item_schema() {
$schema = parent::get_item_schema();
⋮----
public function create_item( $request ) {
$this->adjust_cities_and_postcodes( $request );
⋮----
return parent::create_item( $request );
⋮----
public function update_item( $request ) {
⋮----
return parent::update_item( $request );
⋮----
private function adjust_cities_and_postcodes( &$request ) {
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-terms-controller.php">
use Automattic\WooCommerce\Internal\AssignDefaultCategory;
⋮----
abstract class WC_REST_Terms_Controller extends WC_REST_Controller {
⋮----
protected $rest_base = '';
⋮----
/**
	 * Taxonomy.
	 *
	 * @var string
	 */
protected $taxonomy = '';
⋮----
/**
	 * Cached taxonomies by attribute id.
	 *
	 * @var array
	 */
protected $taxonomies_by_id = array();
⋮----
/**
	 * Register the routes for terms.
	 */
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
$this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
... (86 lines truncated)
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-variations-controller.php">
class WC_REST_Variations_Controller extends WC_REST_Product_Variations_Controller {
⋮----
protected $rest_base = 'variations';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
protected function prepare_objects_query( $request ) {
$args = parent::prepare_objects_query( $request );
⋮----
if ( "/{$this->namespace}/variations" === $request->get_route() ) {
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-webhooks-controller.php">
class WC_REST_Webhooks_Controller extends WC_REST_Webhooks_V2_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected function get_default_api_version() {
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version4/class-wc-rest-settings-v4-controller.php">
class WC_REST_Settings_V4_Controller extends WC_REST_Setting_Options_Controller {
⋮----
protected $namespace = 'wc/v4';
</file>

<file path="plugins/woocommerce/includes/rest-api/Controllers/Version4/class-wc-rest-v4-controller.php">
abstract class WC_REST_V4_Controller extends WP_REST_Controller {
⋮----
protected $namespace = 'wc/v4';
⋮----
protected $rest_base = '';
⋮----
/**
	 * Check permissions for a given request.
	 *
	 * @param WP_REST_Request $request Full details about the request.
	 * @param string          $permission The permission to check for.
	 * @return bool|WP_Error
	 */
protected function check_permissions( $request, $permission = 'read' ) {
⋮----
protected function get_api_version() {
⋮----
public function prepare_response_for_collection( $response ) {
⋮----
$data   = (array) $response->get_data();
⋮----
$links  = $server->get_compact_response_links( $response );
⋮----
protected function get_base_schema() {
</file>

<file path="plugins/woocommerce/includes/rest-api/Utilities/ImageAttachment.php">
namespace Automattic\WooCommerce\RestApi\Utilities;
⋮----
class ImageAttachment {
⋮----
public $id = 0;
⋮----
public $object_id = 0;
⋮----
public function __construct( $id = 0, $object_id = 0 ) {
⋮----
public function upload_image_from_src( $src ) {
⋮----
throw new \WC_REST_Exception( 'woocommerce_product_image_upload_error', $upload->get_error_message(), 400 );
⋮----
throw new \WC_REST_Exception( 'woocommerce_product_invalid_image_id', sprintf( __( '#%s is an invalid image ID.', 'woocommerce' ), $this->id ), 400 );
⋮----
public function update_alt_text( $text ) {
⋮----
public function update_name( $text ) {
</file>

<file path="plugins/woocommerce/includes/rest-api/Utilities/SingletonTrait.php">
namespace Automattic\WooCommerce\RestApi\Utilities;
⋮----
trait SingletonTrait {
⋮----
protected static $instance = null;
⋮----
protected function __construct() {}
⋮----
final public static function instance() {
⋮----
private function __clone() {}
⋮----
final public function __wakeup() {
</file>

<file path="plugins/woocommerce/includes/rest-api/Package.php">
namespace Automattic\WooCommerce\RestApi;
⋮----
class Package {
⋮----
public static function init() {
⋮----
\Automattic\WooCommerce\RestApi\Server::instance()->init();
⋮----
public static function get_version() {
⋮----
public static function get_path() {
⋮----
return \Automattic\WooCommerce\RestApi\Server::get_path();
</file>

<file path="plugins/woocommerce/includes/rest-api/Server.php">
namespace Automattic\WooCommerce\RestApi;
⋮----
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\RestApi\Utilities\SingletonTrait;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\OrderNotes\Controller as OrderNotesController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\ShippingZones\Controller as ShippingZonesController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\ShippingZoneMethod\Controller as ShippingZoneMethodController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Controller as OrdersController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Refunds\Controller as RefundsController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Products\Controller as SettingsProductsController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Products\Controller as ProductsController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\PaymentGateways\Controller as PaymentGatewaysController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\OfflinePaymentMethods\Controller as OfflinePaymentMethodsController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Customers\Controller as CustomersController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\General\Controller as GeneralSettingsController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Email\Controller as EmailSettingsController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Tax\Controller as TaxSettingsController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Emails\Controller as EmailsSettingsController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Fulfillments\Controller as FulfillmentsController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Account\Controller as AccountSettingsController;
⋮----
class Server {
⋮----
protected $controllers = array();
⋮----
public function init() {
⋮----
\WC_REST_System_Status_V2_Controller::register_cache_clean();
⋮----
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/includes/shipping/flat-rate/includes/settings-flat-rate.php">
use Automattic\WooCommerce\Enums\ProductTaxStatus;
⋮----
$shipping_classes = WC()->shipping()->get_shipping_classes();
⋮----
/* translators: %s: URL for link */
⋮----
'default'           => $this->get_option( 'class_cost_' . $shipping_class->slug ),
</file>

<file path="plugins/woocommerce/includes/shipping/flat-rate/class-wc-shipping-flat-rate.php">
class WC_Shipping_Flat_Rate extends WC_Shipping_Method {
⋮----
protected $fee_cost = '';
⋮----
/**
	 * Shipping method cost.
	 *
	 * @var string
	 */
public $cost;
⋮----
/**
	 * Shipping method type.
	 *
	 * @var string
	 */
public $type;
⋮----
/**
	 * Constructor.
	 *
	 * @param int $instance_id Shipping method instance ID.
	 */
public function __construct( $instance_id = 0 ) {
⋮----
$this->init();
⋮----
public function init() {
⋮----
$this->title                = $this->get_option( 'title' );
... (62 lines truncated)
</file>

<file path="plugins/woocommerce/includes/shipping/free-shipping/class-wc-shipping-free-shipping.php">
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
class WC_Shipping_Free_Shipping extends WC_Shipping_Method {
⋮----
public $min_amount = 0;
⋮----
public $requires = '';
⋮----
/**
	 * Ignore discounts.
	 *
	 * If set, free shipping would be available based on pre-discount order amount.
	 *
	 * @var string
	 */
public $ignore_discounts;
⋮----
/**
	 * Constructor.
	 *
	 * @param int $instance_id Shipping method instance.
	 */
public function __construct( $instance_id = 0 ) {
⋮----
$this->init();
⋮----
public function init() {
⋮----
$this->init_form_fields();
$this->init_settings();
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/includes/shipping/legacy-flat-rate/includes/settings-flat-rate.php">
use Automattic\WooCommerce\Enums\ProductTaxStatus;
⋮----
'options'           => WC()->countries->get_shipping_countries(),
⋮----
$shipping_classes = WC()->shipping()->get_shipping_classes();
⋮----
/* translators: %s: Admin shipping settings URL */
⋮----
'default'     => $this->get_option( 'class_cost_' . $shipping_class->slug ),
⋮----
if ( apply_filters( 'woocommerce_enable_deprecated_additional_flat_rates', $this->get_option( 'options', false ) ) ) {
</file>

<file path="plugins/woocommerce/includes/shipping/legacy-flat-rate/class-wc-shipping-legacy-flat-rate.php">
class WC_Shipping_Legacy_Flat_Rate extends WC_Shipping_Method {
⋮----
protected $fee_cost = '';
⋮----
/**
	 * Shipping method cost.
	 *
	 * @var string
	 */
public $cost;
⋮----
/**
	 * Shipping method type.
	 *
	 * @var string
	 */
public $type;
⋮----
/**
	 * Shipping method options.
	 *
	 * @deprecated 2.4.0
	 * @var string
	 */
public $options;
⋮----
/**
	 * Constructor.
	 */
public function __construct() {
... (86 lines truncated)
</file>

<file path="plugins/woocommerce/includes/shipping/legacy-free-shipping/class-wc-shipping-legacy-free-shipping.php">
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
class WC_Shipping_Legacy_Free_Shipping extends WC_Shipping_Method {
⋮----
public $min_amount;
⋮----
public $requires;
⋮----
public function __construct() {
⋮----
$this->init();
⋮----
public function process_admin_options() {
parent::process_admin_options();
⋮----
public function get_option_key() {
⋮----
public function init() {
⋮----
$this->init_form_fields();
$this->init_settings();
⋮----
$this->enabled      = $this->get_option( 'enabled' );
$this->title        = $this->get_option( 'title' );
$this->min_amount   = $this->get_option( 'min_amount', 0 );
$this->availability = $this->get_option( 'availability' );
$this->countries    = $this->get_option( 'countries' );
$this->requires     = $this->get_option( 'requires' );
⋮----
public function init_form_fields() {
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/includes/shipping/legacy-international-delivery/class-wc-shipping-legacy-international-delivery.php">
class WC_Shipping_Legacy_International_Delivery extends WC_Shipping_Legacy_Flat_Rate {
⋮----
public function __construct() {
⋮----
$this->init();
⋮----
public function get_option_key() {
⋮----
public function init_form_fields() {
parent::init_form_fields();
⋮----
public function is_available( $package ) {
</file>

<file path="plugins/woocommerce/includes/shipping/legacy-local-delivery/class-wc-shipping-legacy-local-delivery.php">
class WC_Shipping_Legacy_Local_Delivery extends WC_Shipping_Local_Pickup {
⋮----
public $type;
⋮----
public $codes;
⋮----
public function __construct() {
⋮----
$this->init();
⋮----
public function process_admin_options() {
parent::process_admin_options();
⋮----
public function get_option_key() {
⋮----
public function init() {
⋮----
$this->init_form_fields();
$this->init_settings();
⋮----
$this->title        = $this->get_option( 'title' );
$this->type         = $this->get_option( 'type' );
$this->fee          = $this->get_option( 'fee' );
$this->codes        = $this->get_option( 'codes' );
$this->availability = $this->get_option( 'availability' );
$this->countries    = $this->get_option( 'countries' );
⋮----
public function calculate_shipping( $package = array() ) {
⋮----
if ( $values['quantity'] > 0 && $values['data']->needs_shipping() ) {
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/includes/shipping/legacy-local-pickup/class-wc-shipping-legacy-local-pickup.php">
class WC_Shipping_Legacy_Local_Pickup extends WC_Shipping_Method {
⋮----
public $codes;
⋮----
public function __construct() {
⋮----
$this->init();
⋮----
public function process_admin_options() {
parent::process_admin_options();
⋮----
public function get_option_key() {
⋮----
public function init() {
⋮----
$this->init_form_fields();
$this->init_settings();
⋮----
$this->enabled      = $this->get_option( 'enabled' );
$this->title        = $this->get_option( 'title' );
$this->codes        = $this->get_option( 'codes' );
$this->availability = $this->get_option( 'availability' );
$this->countries    = $this->get_option( 'countries' );
⋮----
public function calculate_shipping( $package = array() ) {
⋮----
$this->add_rate( $rate );
⋮----
public function init_form_fields() {
⋮----
... (26 lines truncated)
</file>

<file path="plugins/woocommerce/includes/shipping/local-pickup/class-wc-shipping-local-pickup.php">
use Automattic\WooCommerce\Enums\ProductTaxStatus;
⋮----
class WC_Shipping_Local_Pickup extends WC_Shipping_Method {
⋮----
public $cost;
⋮----
public function __construct( $instance_id = 0 ) {
⋮----
$this->init();
⋮----
public function init() {
⋮----
$this->init_form_fields();
$this->init_settings();
⋮----
$this->title      = $this->get_option( 'title' );
$this->tax_status = $this->get_option( 'tax_status' );
$this->cost       = $this->get_option( 'cost' );
⋮----
public function calculate_shipping( $package = array() ) {
$this->add_rate(
⋮----
public function sanitize_cost( $value ) {
return \Automattic\WooCommerce\Utilities\NumberUtil::sanitize_cost_in_current_locale( $value );
⋮----
public function init_form_fields() {
</file>

<file path="plugins/woocommerce/includes/shortcodes/class-wc-shortcode-cart.php">
class WC_Shortcode_Cart {
⋮----
public static function calculate_shipping() {
⋮----
WC()->shipping()->reset_shipping();
⋮----
$address['country']  = isset( $_POST['calc_shipping_country'] ) ? wc_clean( wp_unslash( $_POST['calc_shipping_country'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Shipping/cart nonce is verified; address fields are sanitized and validated.
$address['state']    = isset( $_POST['calc_shipping_state'] ) ? wc_clean( wp_unslash( $_POST['calc_shipping_state'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Shipping/cart nonce is verified; address fields are sanitized and validated.
$address['postcode'] = isset( $_POST['calc_shipping_postcode'] ) ? wc_clean( wp_unslash( $_POST['calc_shipping_postcode'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Shipping/cart nonce is verified; address fields are sanitized and validated.
$address['city']     = isset( $_POST['calc_shipping_city'] ) ? wc_clean( wp_unslash( $_POST['calc_shipping_city'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Shipping/cart nonce is verified; address fields are sanitized and validated.
⋮----
if ( $address['postcode'] && ! WC_Validation::is_postcode( $address['postcode'], $address['country'] ) ) {
⋮----
if ( ! WC()->customer->get_billing_first_name() ) {
WC()->customer->set_billing_location( $address['country'], $address['state'], $address['postcode'], $address['city'] );
⋮----
WC()->customer->set_shipping_location( $address['country'], $address['state'], $address['postcode'], $address['city'] );
⋮----
WC()->customer->set_billing_address_to_base();
WC()->customer->set_shipping_address_to_base();
⋮----
WC()->customer->set_calculated_shipping( true );
WC()->customer->save();
⋮----
wc_add_notice( $e->getMessage(), 'error' );
⋮----
public static function output( $atts ) {
⋮----
$nonce_value = wc_get_var( $_REQUEST['woocommerce-shipping-calculator-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/includes/shortcodes/class-wc-shortcode-checkout.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\Utilities\Users;
⋮----
class WC_Shortcode_Checkout {
⋮----
public static function get( $atts ) {
return WC_Shortcodes::shortcode_wrapper( array( __CLASS__, 'output' ), $atts );
⋮----
public static function output( $atts ) {
⋮----
if ( $order && $order->has_status( OrderStatus::PENDING ) ) {
⋮----
self::order_pay( $wp->query_vars['order-pay'] );
⋮----
self::order_received( $wp->query_vars['order-received'] );
⋮----
self::checkout();
⋮----
private static function order_pay( $order_id ) {
⋮----
$order_key = isset( $_GET['key'] ) && is_string( $_GET['key'] ) ? wc_clean( wp_unslash( $_GET['key'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only flow selectors are cleaned; order access verifies key/ownership.
⋮----
// Order or payment link is invalid.
if ( ! $order || $order->get_id() !== $order_id || ! hash_equals( $order->get_order_key(), $order_key ) ) {
⋮----
'redirect' => $order->get_checkout_payment_url(),
⋮----
if ( ! $order->get_user_id() && is_user_logged_in() ) {
⋮----
if ( $order->get_billing_email() !== wp_get_current_user()->user_email ) {
... (81 lines truncated)
</file>

<file path="plugins/woocommerce/includes/shortcodes/class-wc-shortcode-my-account.php">
use Automattic\WooCommerce\Internal\OrderWithdrawal\OrderWithdrawalController;
⋮----
class WC_Shortcode_My_Account {
⋮----
public static function get( $atts ) {
return WC_Shortcodes::shortcode_wrapper( array( __CLASS__, 'output' ), $atts );
⋮----
public static function output( $atts ) {
⋮----
self::my_account_add_notices();
⋮----
self::lost_password();
⋮----
if ( wc_get_container()->get( OrderWithdrawalController::class )->is_endpoint_request() ) {
⋮----
wc_get_container()->get( OrderWithdrawalController::class )->render_view();
⋮----
self::my_account( $atts );
⋮----
private static function my_account_add_notices() {
⋮----
// After password reset, add confirmation message.
⋮----
private static function my_account( $atts ) {
⋮----
public static function view_order( $order_id ) {
⋮----
$status->name = wc_get_order_status_name( $order->get_status() );
⋮----
'order_id' => $order->get_id(),
... (131 lines truncated)
</file>

<file path="plugins/woocommerce/includes/shortcodes/class-wc-shortcode-order-tracking.php">
class WC_Shortcode_Order_Tracking {
⋮----
public static function get( $atts ) {
return WC_Shortcodes::shortcode_wrapper( array( __CLASS__, 'output' ), $atts );
⋮----
public static function output( $atts ) {
⋮----
$nonce_value = wc_get_var( $_REQUEST['woocommerce-order-tracking-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
⋮----
if ( $order && $order->get_id() && is_a( $order, 'WC_Order' ) && strtolower( $order->get_billing_email() ) === strtolower( $order_email ) ) {
do_action( 'woocommerce_track_order', $order->get_id() );
</file>

<file path="plugins/woocommerce/includes/shortcodes/class-wc-shortcode-products.php">
use Automattic\WooCommerce\Enums\CatalogVisibility;
⋮----
class WC_Shortcode_Products {
⋮----
protected $type = 'products';
⋮----
protected $attributes = array();
⋮----
protected $query_args = array();
⋮----
protected $custom_visibility = false;
⋮----
public function __construct( $attributes = array(), $type = 'products' ) {
⋮----
$this->attributes = $this->parse_attributes( $attributes );
$this->query_args = $this->parse_query_args();
⋮----
public function get_attributes() {
⋮----
public function get_query_args() {
⋮----
public function get_type() {
⋮----
public function get_content() {
return $this->product_loop();
⋮----
protected function parse_attributes( $attributes ) {
$attributes = $this->parse_legacy_attributes( $attributes );
⋮----
'columns'        => '',        // Number of columns.
... (85 lines truncated)
</file>

<file path="plugins/woocommerce/includes/theme-support/class-wc-twenty-eleven.php">
class WC_Twenty_Eleven {
⋮----
public static function init() {
⋮----
public static function output_content_wrapper() {
⋮----
public static function output_content_wrapper_end() {
⋮----
WC_Twenty_Eleven::init();
</file>

<file path="plugins/woocommerce/includes/theme-support/class-wc-twenty-fifteen.php">
class WC_Twenty_Fifteen {
⋮----
public static function init() {
⋮----
public static function output_content_wrapper() {
⋮----
public static function output_content_wrapper_end() {
⋮----
WC_Twenty_Fifteen::init();
</file>

<file path="plugins/woocommerce/includes/theme-support/class-wc-twenty-fourteen.php">
class WC_Twenty_Fourteen {
⋮----
public static function init() {
⋮----
public static function output_content_wrapper() {
⋮----
public static function output_content_wrapper_end() {
⋮----
WC_Twenty_Fourteen::init();
</file>

<file path="plugins/woocommerce/includes/theme-support/class-wc-twenty-nineteen.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Twenty_Nineteen {
⋮----
public static function init() {
⋮----
public static function output_content_wrapper() {
⋮----
public static function output_content_wrapper_end() {
⋮----
public static function enqueue_styles( $styles ) {
⋮----
'src'     => str_replace( array( 'http:', 'https:' ), '', WC()->plugin_url() ) . '/assets/css/twenty-nineteen.css',
⋮----
'version' => Constants::get_constant( 'WC_VERSION' ),
⋮----
public static function tweak_theme_features() {
⋮----
public static function custom_colors_css( $css, $primary_color, $saturation ) {
⋮----
WC_Twenty_Nineteen::init();
</file>

<file path="plugins/woocommerce/includes/theme-support/class-wc-twenty-seventeen.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Twenty_Seventeen {
⋮----
public static function init() {
⋮----
public static function enqueue_styles( $styles ) {
⋮----
'src'     => str_replace( array( 'http:', 'https:' ), '', WC()->plugin_url() ) . '/assets/css/twenty-seventeen.css',
⋮----
'version' => Constants::get_constant( 'WC_VERSION' ),
⋮----
public static function output_content_wrapper() {
⋮----
public static function output_content_wrapper_end() {
⋮----
public static function custom_colors_css( $css, $hue, $saturation ) {
⋮----
WC_Twenty_Seventeen::init();
</file>

<file path="plugins/woocommerce/includes/theme-support/class-wc-twenty-sixteen.php">
class WC_Twenty_Sixteen {
⋮----
public static function init() {
⋮----
public static function output_content_wrapper() {
⋮----
public static function output_content_wrapper_end() {
⋮----
WC_Twenty_Sixteen::init();
</file>

<file path="plugins/woocommerce/includes/theme-support/class-wc-twenty-ten.php">
class WC_Twenty_Ten {
⋮----
public static function init() {
⋮----
public static function output_content_wrapper() {
⋮----
public static function output_content_wrapper_end() {
⋮----
WC_Twenty_Ten::init();
</file>

<file path="plugins/woocommerce/includes/theme-support/class-wc-twenty-thirteen.php">
class WC_Twenty_Thirteen {
⋮----
public static function init() {
⋮----
public static function output_content_wrapper() {
⋮----
public static function output_content_wrapper_end() {
⋮----
WC_Twenty_Thirteen::init();
</file>

<file path="plugins/woocommerce/includes/theme-support/class-wc-twenty-twelve.php">
class WC_Twenty_Twelve {
⋮----
public static function init() {
⋮----
public static function output_content_wrapper() {
⋮----
public static function output_content_wrapper_end() {
⋮----
public static function enqueue_styles() {
⋮----
WC_Twenty_Twelve::init();
</file>

<file path="plugins/woocommerce/includes/theme-support/class-wc-twenty-twenty-one.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Twenty_Twenty_One {
⋮----
public static function init() {
⋮----
public static function enqueue_styles( $styles ) {
⋮----
'src'     => str_replace( array( 'http:', 'https:' ), '', WC()->plugin_url() ) . '/assets/css/twenty-twenty-one.css',
⋮----
'version' => Constants::get_constant( 'WC_VERSION' ),
⋮----
public static function enqueue_admin_styles() {
⋮----
str_replace( array( 'http:', 'https:' ), '', WC()->plugin_url() ) . '/assets/css/twenty-twenty-one-admin.css',
⋮----
Constants::get_constant( 'WC_VERSION' ),
⋮----
WC_Twenty_Twenty_One::init();
</file>

<file path="plugins/woocommerce/includes/theme-support/class-wc-twenty-twenty-three.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Twenty_Twenty_Three {
⋮----
public static function init() {
⋮----
public static function enqueue_styles( $styles ) {
⋮----
'src'     => str_replace( array( 'http:', 'https:' ), '', WC()->plugin_url() ) . '/assets/css/twenty-twenty-three.css',
⋮----
'version' => Constants::get_constant( 'WC_VERSION' ),
⋮----
public static function before_order_review() {
⋮----
public static function after_order_review() {
⋮----
WC_Twenty_Twenty_Three::init();
</file>

<file path="plugins/woocommerce/includes/theme-support/class-wc-twenty-twenty-two.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Twenty_Twenty_Two {
⋮----
public static function init() {
⋮----
public static function enqueue_styles( $styles ) {
⋮----
'src'     => str_replace( array( 'http:', 'https:' ), '', WC()->plugin_url() ) . '/assets/css/twenty-twenty-two.css',
⋮----
'version' => Constants::get_constant( 'WC_VERSION' ),
⋮----
public static function before_order_review() {
⋮----
public static function after_order_review() {
⋮----
WC_Twenty_Twenty_Two::init();
</file>

<file path="plugins/woocommerce/includes/theme-support/class-wc-twenty-twenty.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Twenty_Twenty {
⋮----
public static function init() {
⋮----
public static function output_content_wrapper() {
⋮----
public static function output_content_wrapper_end() {
⋮----
public static function set_white_background() {
⋮----
public static function enqueue_styles( $styles ) {
⋮----
'src'     => str_replace( array( 'http:', 'https:' ), '', WC()->plugin_url() ) . '/assets/css/twenty-twenty.css',
⋮----
'version' => Constants::get_constant( 'WC_VERSION' ),
⋮----
WC_Twenty_Twenty::init();
</file>

<file path="plugins/woocommerce/includes/tracks/events/class-wc-admin-setup-wizard-tracking.php">
class WC_Admin_Setup_Wizard_Tracking {
⋮----
private $steps = array();
⋮----
public function init() {
⋮----
public function get_current_step() {
⋮----
return isset( $_GET['step'] ) ? sanitize_key( $_GET['step'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
⋮----
/**
	 * Add footer scripts to OBW via woocommerce_setup_footer
	 *
	 * @deprecated 4.6.0
	 */
public function add_footer_scripts() {
⋮----
public function dequeue_non_allowed_scripts() {
⋮----
public function track_start( $option, $value ) {
⋮----
public function track_ready_next_steps() {
⋮----
public function add_step_save_events() {
⋮----
public function track_store_setup() {
⋮----
public function track_payments() {
⋮----
public function track_shipping() {
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/includes/tracks/events/class-wc-coupon-tracking.php">
class WC_Coupon_Tracking {
⋮----
public function init() {
⋮----
public function track_coupon_updated( $coupon, $updated_props ) {
⋮----
'discount_code'        => $coupon->get_code(),
'free_shipping'        => $coupon->get_free_shipping(),
'individual_use'       => $coupon->get_individual_use(),
'exclude_sale_items'   => $coupon->get_exclude_sale_items(),
'usage_limits_applied' => 0 < intval( $coupon->get_usage_limit() )
|| 0 < intval( $coupon->get_usage_limit_per_user() )
|| 0 < intval( $coupon->get_limit_usage_to_x_items() ),
⋮----
WC_Tracks::record_event( 'coupon_updated', $properties );
</file>

<file path="plugins/woocommerce/includes/tracks/events/class-wc-coupons-tracking.php">
class WC_Coupons_Tracking {
⋮----
public function init() {
⋮----
public function tracks_coupons_bulk_actions() {
⋮----
public function tracks_coupons_events() {
⋮----
$this->tracks_coupons_bulk_actions();
⋮----
WC_Tracks::record_event(
⋮----
WC_Tracks::record_event( 'coupons_search' );
</file>

<file path="plugins/woocommerce/includes/tracks/events/class-wc-extensions-tracking.php">
class WC_Extensions_Tracking {
⋮----
public function init() {
⋮----
public function track_extensions_page() {
⋮----
WC_Tracks::record_event( $event, $properties );
⋮----
public function track_extensions_page_connection_error( string $error = '' ) {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
⋮----
WC_Tracks::record_event( 'extensions_view_connection_error', $properties );
⋮----
public function track_helper_connection_start() {
WC_Tracks::record_event( 'extensions_subscriptions_connect' );
⋮----
public function track_helper_connection_cancelled() {
WC_Tracks::record_event( 'extensions_subscriptions_cancelled' );
⋮----
public function track_helper_connection_complete() {
⋮----
WC_Tracks::record_event( 'extensions_subscriptions_connected', $properties );
⋮----
public function track_helper_disconnected() {
WC_Tracks::record_event( 'extensions_subscriptions_disconnect' );
⋮----
public function track_helper_subscriptions_refresh() {
WC_Tracks::record_event( 'extensions_subscriptions_update' );
⋮----
public function track_addon_install( $addon_id, $section ) {
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/includes/tracks/events/class-wc-importer-tracking.php">
class WC_Importer_Tracking {
⋮----
public function init() {
⋮----
public function track_product_importer() {
⋮----
return $this->track_product_importer_start();
⋮----
return $this->track_product_importer_complete();
⋮----
public function track_product_importer_start() {
⋮----
WC_Tracks::record_event( 'product_import_start', $properties );
⋮----
public function track_product_importer_complete() {
⋮----
WC_Tracks::record_event( 'product_import_complete', $properties );
</file>

<file path="plugins/woocommerce/includes/tracks/events/class-wc-order-tracking.php">
class WC_Order_Tracking {
⋮----
public function init() {
⋮----
public function track_order_viewed( $order ) {
if ( ! $order instanceof WC_Order || ! $order->get_id() ) {
⋮----
'current_status' => $order->get_status(),
'date_created'   => $order->get_date_created() ? $order->get_date_created()->format( DateTime::ATOM ) : '',
'payment_method' => $order->get_payment_method(),
⋮----
WC_Tracks::record_event( 'single_order_view', $properties );
</file>

<file path="plugins/woocommerce/includes/tracks/events/class-wc-orders-tracking.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
⋮----
class WC_Orders_Tracking {
⋮----
public function init() {
⋮----
public function track_order_search( $order_ids, $term, $search_fields ) {
⋮----
WC_Tracks::record_event( 'orders_view_search' );
⋮----
public function track_search_in_orders_list() {
if ( ! OrderUtil::is_order_list_table_screen() || empty( $_REQUEST['s'] ) ) {
⋮----
public function track_orders_view() {
if ( ! OrderUtil::is_order_list_table_screen() ) {
⋮----
WC_Tracks::record_event( 'orders_view', $properties );
⋮----
public function track_order_status_change( $id, $previous_status, $next_status ) {
⋮----
'date_created'    => $order->get_date_created() ? $order->get_date_created()->date( 'Y-m-d' ) : '',
'payment_method'  => $order->get_payment_method(),
'order_total'     => $order->get_total(),
⋮----
WC_Tracks::record_event( 'orders_edit_status_change', $properties );
⋮----
public function track_created_date_change( $id ) {
if ( ! OrderUtil::is_order( $id ) ) {
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/includes/tracks/events/class-wc-product-collection-block-tracking.php">
use Automattic\WooCommerce\Blocks\Templates\SingleProductTemplate;
use Automattic\WooCommerce\Blocks\Templates\CartTemplate;
use Automattic\WooCommerce\Blocks\Templates\MiniCartTemplate;
use Automattic\WooCommerce\Blocks\Templates\CheckoutTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductCatalogTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductAttributeTemplate;
use Automattic\WooCommerce\Blocks\Templates\OrderConfirmationTemplate;
use Automattic\WooCommerce\Enums\ProductStockStatus;
⋮----
class WC_Product_Collection_Block_Tracking {
⋮----
public function init() {
⋮----
public function track_collection_instances( $post_id, $post ) {
⋮----
$instances = $this->parse_blocks_track_data( $blocks );
⋮----
'editor_context' => $this->parse_editor_location_context( $post ),
⋮----
\WC_Tracks::record_event(
⋮----
private function parse_blocks_track_data( $blocks, $is_in_single_product = false, $is_in_template_part = false, $is_in_synced_pattern = false ) {
⋮----
'filters'           => wp_json_encode( $this->get_query_filters_usage_data( $block ), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ),
⋮----
$instances = array_merge( $instances, $this->parse_blocks_track_data( parse_blocks( $synced_pattern->post_content ), $local_is_in_single_product, $is_in_template_part, true ) );
⋮----
$instances = array_merge( $instances, $this->parse_blocks_track_data( $block['innerBlocks'], $local_is_in_single_product, $is_in_template_part, $is_in_synced_pattern ) );
⋮----
private function parse_editor_location_context( $post ) {
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/includes/tracks/events/class-wc-products-tracking.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
⋮----
class WC_Products_Tracking {
⋮----
public function init() {
⋮----
public function track_products_view() {
⋮----
WC_Tracks::record_event( 'products_view' );
⋮----
WC_Tracks::record_event( 'products_sorting_view' );
⋮----
WC_Tracks::record_event( 'products_search' );
⋮----
public function track_categories_and_tags_view() {
⋮----
WC_Tracks::record_event( 'categories_view' );
⋮----
WC_Tracks::record_event( 'tags_view' );
⋮----
WC_Tracks::record_event( 'categories_search' );
⋮----
WC_Tracks::record_event( 'tags_search' );
⋮----
public function track_product_updated( $product_id, $post ) {
⋮----
$source     = apply_filters( 'woocommerce_product_source', self::is_importing() ? 'import' : self::TRACKS_SOURCE );
⋮----
WC_Tracks::record_event( 'product_edit', $properties );
... (82 lines truncated)
</file>

<file path="plugins/woocommerce/includes/tracks/events/class-wc-settings-tracking.php">
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
⋮----
class WC_Settings_Tracking {
⋮----
protected $allowed_options = array();
⋮----
protected $updated_options = array();
⋮----
protected $dropdown_menu_options = array();
⋮----
protected $modified_options = array();
⋮----
protected $deleted_options = array();
⋮----
protected $added_options = array();
⋮----
protected $toggled_options = array(
⋮----
public function init() {
⋮----
public function add_option_to_list_and_track_setting_change( $option ) {
⋮----
public function add_option_to_list( $option ) {
⋮----
public function track_setting_change( $option_name, $old_value, $new_value ) {
⋮----
public function send_settings_change_event() {
⋮----
WC_Tracks::record_event( 'settings_change', $properties );
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/includes/tracks/events/class-wc-status-tracking.php">
class WC_Status_Tracking {
⋮----
public function init() {
⋮----
public function track_status_view() {
⋮----
WC_Tracks::record_event(
</file>

<file path="plugins/woocommerce/includes/tracks/events/class-wc-theme-tracking.php">
class WC_Theme_Tracking {
⋮----
public function init() {
$this->track_initial_theme();
⋮----
public function track_initial_theme() {
⋮----
$this->track_activated_theme();
⋮----
public function track_activated_theme() {
⋮----
'theme_name'    => $theme_object->get( 'Name' ),
'theme_version' => $theme_object->get( 'Version' ),
⋮----
WC_Tracks::record_event( 'activated_theme', $properties );
</file>

<file path="plugins/woocommerce/includes/tracks/class-wc-site-tracking.php">
class WC_Site_Tracking {
⋮----
public static function is_tracking_enabled() {
⋮----
public static function register_scripts() {
⋮----
public static function enqueue_scripts() {
⋮----
public static function add_tracking_function() {
⋮----
$server_details  = WC_Tracks::get_server_details();
$blog_details    = WC_Tracks::get_blog_details( $user->ID );
$tracks_identity = WC_Tracks_Client::get_identity( $user->ID );
$role_details    = WC_Tracks::get_role_details( $user );
⋮----
window.wcTracks.isEnabled = <?php echo self::is_tracking_enabled() ? 'true' : 'false'; ?>;
⋮----
public static function add_enable_tracking_function() {
⋮----
public static function init() {
⋮----
self::register_scripts();
⋮----
if ( ! self::is_tracking_enabled() ) {
⋮----
self::enqueue_scripts();
⋮----
$tracker_instance    = new $tracking_class();
⋮----
public static function maybe_unschedule_deferred_tracks( $new_option_value ) {
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/includes/tracks/class-wc-tracks-client.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
class WC_Tracks_Client {
⋮----
private static $pixel_batch_queue = array();
⋮----
private static $shutdown_hook_registered = false;
⋮----
public static function init() {
⋮----
public static function maybe_set_identity_cookie() {
⋮----
if ( Constants::is_true( 'DOING_AJAX' ) ) {
⋮----
$anon_id = self::get_anon_id();
⋮----
if ( ! Constants::is_true( 'REST_REQUEST' ) && ! Constants::is_true( 'XMLRPC_REQUEST' ) ) {
WC_Site_Tracking::set_tracking_cookie( 'tk_ai', $anon_id );
⋮----
public static function record_event( $event ) {
⋮----
$pixel = $event->build_pixel_url( $event );
⋮----
return self::record_pixel( $pixel );
⋮----
public static function record_event_batched( $event ) {
⋮----
$pixel = $event->build_pixel_url();
⋮----
... (57 lines truncated)
</file>

<file path="plugins/woocommerce/includes/tracks/class-wc-tracks-event.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Tracks_Event {
⋮----
public $error;
⋮----
public function __construct( $event ) {
$_event = self::validate_and_sanitize( $event );
⋮----
public function record() {
if ( wp_doing_ajax() || Constants::is_true( 'REST_REQUEST' ) || Constants::is_true( 'WP_CLI' ) || wp_doing_cron() ) {
return WC_Tracks_Client::record_event( $this );
⋮----
return WC_Tracks_Footer_Pixel::record_event( $this );
⋮----
public static function validate_and_sanitize( $event ) {
⋮----
$_event->_ts = WC_Tracks_Client::build_timestamp();
⋮----
if ( ! self::event_name_is_valid( $_event->_en ) ) {
⋮----
if ( ! self::prop_name_is_valid( $key ) && '_en' !== $key ) {
⋮----
$_event = self::sanitize_property_values( $_event );
⋮----
public function build_pixel_url() {
⋮----
// Request Timestamp and URL Terminator must be added just before the HTTP request or not at all.
⋮----
$validated = self::validate_and_sanitize( $args );
... (45 lines truncated)
</file>

<file path="plugins/woocommerce/includes/tracks/class-wc-tracks-footer-pixel.php">
class WC_Tracks_Footer_Pixel {
⋮----
protected static $instance = null;
⋮----
protected $events = array();
⋮----
public static function instance() {
⋮----
public function __construct() {
⋮----
public static function record_event( $event ) {
⋮----
self::instance()->add_event( $event );
⋮----
public function add_event( $event ) {
⋮----
public function render_tracking_pixels() {
⋮----
$pixel = $event->build_pixel_url();
⋮----
$pixel = WC_Tracks_Client::add_request_timestamp_and_nocache( $pixel );
⋮----
public function send_tracks_requests() {
⋮----
WC_Tracks_Client::record_event( $event );
⋮----
public static function get_events() {
return self::instance()->events;
⋮----
public static function clear_events() {
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/includes/tracks/class-wc-tracks.php">
class WC_Tracks {
⋮----
public static function get_products_count() {
$product_counts = WC_Tracker::get_product_counts();
⋮----
public static function get_blog_details( $user_id ) {
⋮----
\WC_Install::maybe_set_store_id();
⋮----
'blog_id'        => class_exists( 'Jetpack_Options' ) ? Jetpack_Options::get_option( 'id' ) : null,
⋮----
'products_count' => self::get_products_count(),
'wc_version'     => WC()->stable_version(),
⋮----
public static function get_server_details() {
⋮----
/**
	 * Get role-related details.
	 *
	 * @param WP_User $user The user object.
	 * @return array The role details.
	 */
public static function get_role_details( $user ) {
⋮----
'can_install_plugins'    => $user->has_cap( 'install_plugins' ),
'can_activate_plugins'   => $user->has_cap( 'activate_plugins' ),
'can_manage_woocommerce' => $user->has_cap( 'manage_woocommerce' ),
⋮----
public static function record_event( $event_name, $event_properties = array() ) {
⋮----
... (20 lines truncated)
</file>

<file path="plugins/woocommerce/includes/traits/trait-wc-item-totals.php">
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
trait WC_Item_Totals {
⋮----
abstract protected function get_values_for_total( $field );
⋮----
public static function get_rounded_items_total( $values ) {
⋮----
public static function round_item_subtotal( $value ) {
if ( ! self::round_at_subtotal() ) {
$value = NumberUtil::round( $value );
⋮----
protected static function round_at_subtotal() {
⋮----
protected static function round_line_tax( $value, $in_cents = true ) {
</file>

<file path="plugins/woocommerce/includes/walkers/class-product-cat-dropdown-walker.php">

</file>

<file path="plugins/woocommerce/includes/walkers/class-product-cat-list-walker.php">

</file>

<file path="plugins/woocommerce/includes/walkers/class-wc-product-cat-dropdown-walker.php">
class WC_Product_Cat_Dropdown_Walker extends Walker {
⋮----
public $tree_type = 'category';
⋮----
public $db_fields = array(
⋮----
public function start_el( &$output, $cat, $depth = 0, $args = array(), $current_object_id = 0 ) {
⋮----
public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
⋮----
parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
</file>

<file path="plugins/woocommerce/includes/walkers/class-wc-product-cat-list-walker.php">
class WC_Product_Cat_List_Walker extends Walker {
⋮----
public $tree_type = 'product_cat';
⋮----
public $db_fields = array(
⋮----
public function start_lvl( &$output, $depth = 0, $args = array() ) {
⋮----
public function end_lvl( &$output, $depth = 0, $args = array() ) {
⋮----
public function start_el( &$output, $cat, $depth = 0, $args = array(), $current_object_id = 0 ) {
⋮----
public function end_el( &$output, $cat, $depth = 0, $args = array() ) {
⋮----
public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
⋮----
parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
</file>

<file path="plugins/woocommerce/includes/wccom-site/installation/installation-steps/class-wc-wccom-site-installation-step-activate-product.php">
use WC_REST_WCCOM_Site_Installer_Error_Codes as Installer_Error_Codes;
use WC_REST_WCCOM_Site_Installer_Error as Installer_Error;
⋮----
class WC_WCCOM_Site_Installation_Step_Activate_Product implements WC_WCCOM_Site_Installation_Step {
⋮----
protected $state;
⋮----
public function __construct( $state ) {
⋮----
public function run() {
$product_id = $this->state->get_product_id();
⋮----
if ( 'plugin' === $this->state->get_product_type() ) {
$this->activate_plugin( $product_id );
⋮----
$this->activate_theme( $product_id );
⋮----
private function activate_plugin( $product_id ) {
⋮----
$dir_name = $this->get_wporg_product_dir_name();
⋮----
$filename = \WC_WCCOM_Site_Installer::get_wporg_plugin_main_file( $dir_name );
⋮----
WC_Helper::get_local_woo_plugins(),
⋮----
// Fallback: use installed_path from the move_product step.
if ( empty( $filename ) && ! empty( $this->state->get_installed_path() ) ) {
$filename = \WC_WCCOM_Site_Installer::get_wporg_plugin_main_file(
basename( $this->state->get_installed_path() )
⋮----
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wccom-site/installation/installation-steps/class-wc-wccom-site-installation-step-download-product.php">
use WC_REST_WCCOM_Site_Installer_Error_Codes as Installer_Error_Codes;
use WC_REST_WCCOM_Site_Installer_Error as Installer_Error;
⋮----
class WC_WCCOM_Site_Installation_Step_Download_Product implements WC_WCCOM_Site_Installation_Step {
⋮----
protected $state;
⋮----
public function __construct( $state ) {
⋮----
public function run() {
$upgrader = WC_WCCOM_Site_Installer::get_wp_upgrader();
⋮----
$download_path = $upgrader->download_package( $this->state->get_download_url() );
⋮----
$this->state->set_download_path( $download_path );
</file>

<file path="plugins/woocommerce/includes/wccom-site/installation/installation-steps/class-wc-wccom-site-installation-step-get-product-info.php">
use WC_REST_WCCOM_Site_Installer_Error_Codes as Installer_Error_Codes;
use WC_REST_WCCOM_Site_Installer_Error as Installer_Error;
⋮----
class WC_WCCOM_Site_Installation_Step_Get_Product_Info implements WC_WCCOM_Site_Installation_Step {
⋮----
protected $state;
⋮----
public function __construct( $state ) {
⋮----
public function run() {
$product_id = $this->state->get_product_id();
⋮----
$request = WC_Helper_API::get(
⋮----
$download_url = $this->get_wporg_download_url( $result );
⋮----
$download_url = $this->get_wccom_download_url( $product_id );
⋮----
$this->state->set_product_type( $result['_product_type'] );
$this->state->set_product_name( $result['name'] );
$this->state->set_download_url( $download_url );
⋮----
protected function get_wporg_download_url( $data ) {
⋮----
protected function get_wccom_download_url( $product_id ) {
⋮----
WC_Helper_API_Backoff::clear_all();
⋮----
WC_Helper::_flush_subscriptions_cache();
⋮----
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wccom-site/installation/installation-steps/class-wc-wccom-site-installation-step-move-product.php">
use WC_REST_WCCOM_Site_Installer_Error_Codes as Installer_Error_Codes;
use WC_REST_WCCOM_Site_Installer_Error as Installer_Error;
⋮----
class WC_WCCOM_Site_Installation_Step_Move_Product implements WC_WCCOM_Site_Installation_Step {
⋮----
protected $state;
⋮----
public function __construct( $state ) {
⋮----
public function run() {
$upgrader = WC_WCCOM_Site_Installer::get_wp_upgrader();
⋮----
$destination = 'plugin' === $this->state->get_product_type()
⋮----
'source'        => $this->state->get_unpacked_path(),
⋮----
'type'   => $this->state->get_product_type(),
⋮----
$result = $upgrader->install_package( $package );
⋮----
$plugin_info          = WC_WCCOM_Site_Installer::get_plugin_info( $existing_folder_path );
⋮----
$this->state->set_installed_path( $existing_folder_path );
$this->state->set_already_installed_plugin_info( $plugin_info );
$this->maybe_connect_theme();
⋮----
throw new Installer_Error( Installer_Error_Codes::INSTALLATION_FAILED, esc_html( $result->get_error_message() ) );
⋮----
$this->state->set_installed_path( $result['destination'] );
⋮----
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wccom-site/installation/installation-steps/class-wc-wccom-site-installation-step-unpack-product.php">
use WC_REST_WCCOM_Site_Installer_Error_Codes as Installer_Error_Codes;
use WC_REST_WCCOM_Site_Installer_Error as Installer_Error;
⋮----
class WC_WCCOM_Site_Installation_Step_Unpack_Product implements WC_WCCOM_Site_Installation_Step {
⋮----
protected $state;
⋮----
public function __construct( $state ) {
⋮----
public function run() {
$upgrader      = WC_WCCOM_Site_Installer::get_wp_upgrader();
$unpacked_path = $upgrader->unpack_package( $this->state->get_download_path(), true );
⋮----
$this->state->set_unpacked_path( $unpacked_path );
</file>

<file path="plugins/woocommerce/includes/wccom-site/installation/installation-steps/interface-installaton-step.php">
interface WC_WCCOM_Site_Installation_Step {
⋮----
public function __construct( $state );
⋮----
public function run();
</file>

<file path="plugins/woocommerce/includes/wccom-site/installation/class-wc-wccom-site-installation-manager.php">
use WC_REST_WCCOM_Site_Installer_Error_Codes as Installer_Error_Codes;
use WC_REST_WCCOM_Site_Installer_Error as Installer_Error;
⋮----
class WC_WCCOM_Site_Installation_Manager {
⋮----
protected $product_id;
⋮----
protected $idempotency_key;
⋮----
public function __construct( int $product_id, string $idempotency_key = '' ) {
⋮----
public function get_installation_status(): WC_WCCOM_Site_Installation_State {
$state = WC_WCCOM_Site_Installation_State_Storage::get_state( $this->product_id );
⋮----
public function run_installation( string $run_until_step ): bool {
⋮----
if ( $state && $state->get_idempotency_key() !== $this->idempotency_key ) {
⋮----
$state = WC_WCCOM_Site_Installation_State::initiate_new( $this->product_id, $this->idempotency_key );
⋮----
$this->can_run_installation( $run_until_step, $state );
⋮----
$next_step          = $this->get_next_step( $state );
$installation_steps = $this->get_installation_steps( $next_step, $run_until_step );
⋮----
$this->run_step( $step_name, $state );
⋮----
public function reset_installation(): bool {
⋮----
if ( $state->get_idempotency_key() !== $this->idempotency_key ) {
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wccom-site/installation/class-wc-wccom-site-installation-state-storage.php">
class WC_WCCOM_Site_Installation_State_Storage {
⋮----
public static function get_state( $product_id ) : ?WC_WCCOM_Site_Installation_State {
$storage_key = self::get_storage_key( $product_id );
⋮----
$installation_state = WC_WCCOM_Site_Installation_State::initiate_existing(
⋮----
$installation_state->set_product_type( $data['product_type'] ?? null );
$installation_state->set_product_name( $data['product_name'] ?? null );
$installation_state->set_download_url( $data['download_url'] ?? null );
$installation_state->set_download_path( $data['download_path'] ?? null );
$installation_state->set_unpacked_path( $data['unpacked_path'] ?? null );
$installation_state->set_installed_path( $data['installed_path'] ?? null );
$installation_state->set_already_installed_plugin_info( $data['already_installed_plugin_info'] ?? null );
⋮----
public static function save_state( WC_WCCOM_Site_Installation_State $state ) : bool {
$storage_key = self::get_storage_key( $state->get_product_id() );
⋮----
'product_id'                    => $state->get_product_id(),
'idempotency_key'               => $state->get_idempotency_key(),
'last_step_name'                => $state->get_last_step_name(),
'last_step_status'              => $state->get_last_step_status(),
'last_step_error'               => $state->get_last_step_error(),
'product_type'                  => $state->get_product_type(),
'product_name'                  => $state->get_product_name(),
'download_url'                  => $state->get_download_url(),
'download_path'                 => $state->get_download_path(),
'unpacked_path'                 => $state->get_unpacked_path(),
'installed_path'                => $state->get_installed_path(),
'already_installed_plugin_info' => $state->get_already_installed_plugin_info(),
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wccom-site/installation/class-wc-wccom-site-installation-state.php">
class WC_WCCOM_Site_Installation_State {
⋮----
protected $product_id;
⋮----
protected $idempotency_key;
⋮----
protected $last_step_name;
⋮----
protected $last_step_status;
⋮----
protected $last_step_error;
⋮----
protected $product_type;
⋮----
protected $product_name;
⋮----
protected $download_url;
⋮----
protected $download_path;
⋮----
protected $unpacked_path;
⋮----
protected $installed_path;
⋮----
protected $already_installed_plugin_info;
⋮----
protected $started_date;
⋮----
protected function __construct( $product_id ) {
⋮----
... (50 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wccom-site/rest-api/endpoints/abstract-wc-rest-wccom-site-controller.php">
use WC_REST_WCCOM_Site_Installer_Error_Codes as Installer_Error_Codes;
use WC_REST_WCCOM_Site_Installer_Error as Installer_Error;
⋮----
abstract class WC_REST_WCCOM_Site_Controller extends WC_REST_Controller {
⋮----
protected $namespace = 'wccom-site/v3';
⋮----
abstract protected function user_has_permission( $user ): bool;
⋮----
public function check_permission() {
⋮----
if ( empty( $current_user ) || ( $current_user instanceof WP_User && ! $current_user->exists() ) ) {
⋮----
$error->get_error_code(),
$error->get_error_message(),
array( 'status' => $error->get_http_code() )
⋮----
if ( ! $this->user_has_permission( $current_user ) ) {
⋮----
protected function get_response( array $data, int $status = 200 ) {
⋮----
$response->set_status( $status );
</file>

<file path="plugins/woocommerce/includes/wccom-site/rest-api/endpoints/class-wc-rest-wccom-site-connection-controller.php">
class WC_REST_WCCOM_Site_Connection_Controller extends WC_REST_WCCOM_Site_Controller {
⋮----
protected $rest_base = 'connection';
⋮----
public function register_routes() {
⋮----
public function user_has_permission( $user ): bool {
⋮----
public function handle_disconnect_request( $request ) {
⋮----
if ( empty( $request_hash ) || ! WC_Helper::verify_request_hash( $request_hash ) ) {
return $this->get_response(
⋮----
if ( WC_Helper::is_site_connected() ) {
WC_Helper::disconnect();
⋮----
public function handle_status_request() {
$auth = WC_Helper_Options::get( 'auth' );
⋮----
$connection_data = WC_Helper::fetch_helper_connection_info();
</file>

<file path="plugins/woocommerce/includes/wccom-site/rest-api/endpoints/class-wc-rest-wccom-site-installer-controller.php">
use WC_REST_WCCOM_Site_Installer_Error as Installer_Error;
⋮----
class WC_REST_WCCOM_Site_Installer_Controller extends WC_REST_WCCOM_Site_Controller {
⋮----
protected $rest_base = 'installer';
⋮----
public function register_routes() {
⋮----
public function user_has_permission( $user ): bool {
⋮----
public function get_product_install_state( $request ) {
$product_id = (int) $request->get_param( 'product_id' );
⋮----
$state = $installation_manager->get_installation_status();
return $this->success_response( $product_id, $state );
⋮----
return $this->failure_response( $product_id, $exception );
⋮----
public function install( $request ) {
⋮----
$installation_manager->run_installation( $run_until_step );
⋮----
$response = $this->success_response( $product_id );
⋮----
$response = $this->failure_response( $product_id, $exception );
⋮----
public function reset_install( $request ) {
⋮----
$installation_manager->reset_installation();
⋮----
... (28 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wccom-site/rest-api/endpoints/class-wc-rest-wccom-site-ssr-controller.php">
class WC_REST_WCCOM_Site_SSR_Controller extends WC_REST_WCCOM_Site_Controller {
⋮----
protected $rest_base = 'ssr';
⋮----
public function register_routes() {
⋮----
public function user_has_permission( $user ) : bool {
⋮----
public function handle_ssr_request( $request ) {
⋮----
$data           = $ssr_controller->get_items( $request );
$data           = $data->get_data();
⋮----
$request = WC_Helper_API::post(
</file>

<file path="plugins/woocommerce/includes/wccom-site/rest-api/endpoints/class-wc-rest-wccom-site-status-controller.php">
class WC_REST_WCCOM_Site_Status_Controller extends WC_REST_WCCOM_Site_Controller {
⋮----
protected $rest_base = 'status';
⋮----
public function register_routes() {
⋮----
public function user_has_permission( $user ): bool {
⋮----
public function handle_status_request( $request ) {
⋮----
'woo_update_manager_installed' => WC_Woo_Update_Manager_Plugin::is_plugin_installed(),
'woo_update_manager_active'    => WC_Woo_Update_Manager_Plugin::is_plugin_active(),
</file>

<file path="plugins/woocommerce/includes/wccom-site/rest-api/class-wc-rest-wccom-site-installer-error-codes.php">
class WC_REST_WCCOM_Site_Installer_Error_Codes {
</file>

<file path="plugins/woocommerce/includes/wccom-site/rest-api/class-wc-rest-wccom-site-installer-error.php">
class WC_REST_WCCOM_Site_Installer_Error extends Exception {
⋮----
public function __construct( $error_code, $error_message = null, $http_code = null ) {
⋮----
parent::__construct( $error_code );
⋮----
public function get_error_code() {
⋮----
public function get_error_message() {
⋮----
public function get_http_code() {
</file>

<file path="plugins/woocommerce/includes/wccom-site/class-wc-wccom-site-installer.php">
class WC_WCCOM_Site_Installer {
⋮----
private static $wp_upgrader;
⋮----
public static function get_wporg_plugin_main_file( $dir ) {
⋮----
public static function get_plugin_info( $dir ) {
⋮----
public static function get_wp_upgrader() {
⋮----
self::$wp_upgrader->init();
</file>

<file path="plugins/woocommerce/includes/wccom-site/class-wc-wccom-site.php">
use WC_REST_WCCOM_Site_Installer_Error_Codes as Installer_Error_Codes;
use WC_REST_WCCOM_Site_Installer_Error as Installer_Error;
⋮----
class WC_WCCOM_Site {
⋮----
public static function load() {
self::includes();
⋮----
protected static function includes() {
⋮----
public static function authenticate_wccom( $user_id ) {
if ( ! empty( $user_id ) || ! self::is_request_to_wccom_site_rest_api() ) {
⋮----
$auth_header = trim( self::get_authorization_header() );
⋮----
$site_auth = WC_Helper_Options::get( 'auth' );
⋮----
$body = WP_REST_Server::get_raw_data();
⋮----
if ( ! self::verify_wccom_request( $body, $signature, $site_auth['access_token_secret'] ) ) {
⋮----
protected static function get_authorization_header() {
⋮----
/**
	 * Check if this is a request to WCCOM Site REST API.
	 *
	 * @since 3.7.0
	 * @return bool
	 */
protected static function is_request_to_wccom_site_rest_api() {
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-brand-description.php">
class WC_Widget_Brand_Description extends WP_Widget {
⋮----
public $woo_widget_cssclass;
⋮----
public $woo_widget_description;
⋮----
public $woo_widget_idbase;
⋮----
public $woo_widget_name;
⋮----
public function __construct() {
⋮----
parent::__construct( $this->woo_widget_idbase, $this->woo_widget_name, $widget_ops );
⋮----
public function widget( $args, $instance ) {
⋮----
WC()->plugin_path() . '/templates/brands/'
⋮----
public function update( $new_instance, $old_instance ) {
⋮----
public function form( $instance ) {
⋮----
<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'woocommerce' ); ?></label>
<input type="text" class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" value="<?php echo isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : ''; ?>" />
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-brand-nav.php">
use Automattic\WooCommerce\Internal\ProductAttributesLookup\Filterer;
⋮----
class WC_Widget_Brand_Nav extends WC_Widget {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function filter_out_cats( $cat_args ) {
⋮----
/**
	 * Return the currently viewed taxonomy name.
	 *
	 * @return string
	 */
protected function get_current_taxonomy() {
⋮----
/**
	 * Return the currently viewed term ID.
	 *
	 * @return int
	 */
protected function get_current_term_id() {
⋮----
/**
	 * Return the currently viewed term slug.
	 *
	 * @return int
	 */
protected function get_current_term_slug() {
... (88 lines truncated)
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-brand-thumbnails.php">
class WC_Widget_Brand_Thumbnails extends WP_Widget {
⋮----
public $woo_widget_cssclass;
⋮----
public $woo_widget_description;
⋮----
public $woo_widget_idbase;
⋮----
public $woo_widget_name;
⋮----
public function __construct() {
⋮----
parent::__construct( $this->woo_widget_idbase, $this->woo_widget_name, $widget_ops );
⋮----
public function widget( $args, $instance ) {
⋮----
WC()->plugin_path() . '/templates/brands/'
⋮----
public function update( $new_instance, $old_instance ) {
⋮----
/**
	 * Outputs the settings update form.
	 *
	 * @param array $instance Current settings.
	 */
public function form( $instance ) {
⋮----
<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_html_e( 'Title:', 'woocommerce' ); ?></label>
<input type="text" class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" value="<?php echo isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : ''; ?>" />
⋮----
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-cart.php">
class WC_Widget_Cart extends WC_Widget {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function widget( $args, $instance ) {
⋮----
$this->widget_start( $args, $instance );
⋮----
$this->widget_end( $args );
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-layered-nav-filters.php">
class WC_Widget_Layered_Nav_Filters extends WC_Widget {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function widget( $args, $instance ) {
⋮----
$_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes();
⋮----
$base_link          = $this->get_current_page_url();
⋮----
$this->widget_start( $args, $instance );
⋮----
/**
						 * Allows the attribute term name to be modified before being output.
						 *
						 * @param string $term_name The name of the term.
						 * @param WP_Term $term The term object.
						 * @param string $taxonomy The taxonomy name.
						 *
						 * @since 8.8.0
						 */
⋮----
$this->widget_end( $args );
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-layered-nav.php">
use Automattic\WooCommerce\Internal\ProductAttributesLookup\Filterer;
⋮----
class WC_Widget_Layered_Nav extends WC_Widget {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function update( $new_instance, $old_instance ) {
$this->init_settings();
return parent::update( $new_instance, $old_instance );
⋮----
public function form( $instance ) {
⋮----
parent::form( $instance );
⋮----
public function init_settings() {
⋮----
protected function get_instance_taxonomy( $instance ) {
⋮----
/**
	 * Get this widgets query type.
	 *
	 * @param array $instance Array of instance options.
	 * @return string
	 */
protected function get_instance_query_type( $instance ) {
⋮----
protected function get_instance_display_type( $instance ) {
⋮----
... (78 lines truncated)
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-price-filter.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
⋮----
class WC_Widget_Price_Filter extends WC_Widget {
⋮----
public function __construct() {
⋮----
$suffix                   = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min';
$version                  = Constants::get_constant( 'WC_VERSION' );
wp_register_script( 'wc-accounting', WC()->plugin_url() . '/assets/js/accounting/accounting' . $suffix . '.js', array( 'jquery' ), '0.4.2', true );
⋮----
wp_register_script( 'wc-jquery-ui-touchpunch', WC()->plugin_url() . '/assets/js/jquery-ui-touch-punch/jquery-ui-touch-punch' . $suffix . '.js', array( 'jquery-ui-slider' ), $version, true );
wp_register_script( 'wc-price-slider', WC()->plugin_url() . '/assets/js/frontend/price-slider' . $suffix . '.js', array( 'jquery-ui-slider', 'wc-jquery-ui-touchpunch', 'wc-accounting' ), $version, true );
⋮----
parent::__construct();
⋮----
public function widget( $args, $instance ) {
⋮----
if ( ! WC()->query->get_main_query()->post_count && ! isset( $_GET['min_price'] ) && ! isset( $_GET['max_price'] ) ) {
⋮----
$prices    = $this->get_filtered_price();
⋮----
$tax_class = apply_filters( 'woocommerce_price_filter_widget_tax_class', '' ); // Uses standard tax class.
$tax_rates = WC_Tax::get_rates( $tax_class );
⋮----
$min_price += WC_Tax::get_tax_total( WC_Tax::calc_exclusive_tax( $min_price, $tax_rates ) );
$max_price += WC_Tax::get_tax_total( WC_Tax::calc_exclusive_tax( $max_price, $tax_rates ) );
⋮----
$this->widget_start( $args, $instance );
⋮----
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-product-categories.php">
class WC_Widget_Product_Categories extends WC_Widget {
⋮----
public $cat_ancestors;
⋮----
public $current_cat;
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function widget( $args, $instance ) {
⋮----
$this->widget_start( $args, $instance );
⋮----
include_once WC()->plugin_path() . '/includes/walkers/class-wc-product-cat-list-walker.php';
⋮----
$this->widget_end( $args );
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-product-search.php">
class WC_Widget_Product_Search extends WC_Widget {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function widget( $args, $instance ) {
$this->widget_start( $args, $instance );
⋮----
$this->widget_end( $args );
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-product-tag-cloud.php">
class WC_Widget_Product_Tag_Cloud extends WC_Widget {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function widget( $args, $instance ) {
$current_taxonomy = $this->get_current_taxonomy( $instance );
⋮----
$this->widget_start( $args, $instance );
⋮----
$this->widget_end( $args );
⋮----
public function get_current_taxonomy( $instance ) {
⋮----
public function topic_count_text( $count ) {
⋮----
public function _get_current_taxonomy( $instance ) {
⋮----
return $this->get_current_taxonomy( $instance );
⋮----
public function _topic_count_text( $count ) {
⋮----
return $this->topic_count_text( $count );
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-products.php">
use Automattic\WooCommerce\Enums\ProductStockStatus;
⋮----
class WC_Widget_Products extends WC_Widget {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function get_products( $args, $instance ) {
⋮----
return $this->query_products( $query_args );
⋮----
private function query_products( $query_args ) {
⋮----
$products->query( $query_args );
⋮----
public function widget( $args, $instance ) {
if ( $this->get_cached_widget( $args ) ) {
⋮----
$products = $this->get_products( $args, $instance );
if ( $products && $products->have_posts() ) {
$this->widget_start( $args, $instance );
⋮----
while ( $products->have_posts() ) {
$products->the_post();
⋮----
$this->widget_end( $args );
⋮----
echo $this->cache_widget( $args, ob_get_clean() );
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-rating-filter.php">
class WC_Widget_Rating_Filter extends WC_Widget {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
protected function get_filtered_product_count( $rating ) {
⋮----
$tax_query  = WC_Query::get_main_tax_query();
$meta_query = WC_Query::get_main_meta_query();
⋮----
$meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' );
$tax_query_sql  = $tax_query->get_sql( $wpdb->posts, 'ID' );
⋮----
$search = WC_Query::get_main_search_query_sql();
⋮----
return absint( $wpdb->get_var( $sql ) );
⋮----
public function widget( $args, $instance ) {
⋮----
if ( ! WC()->query->get_main_query()->post_count ) {
⋮----
$base_link     = remove_query_arg( 'paged', $this->get_current_page_url() );
⋮----
$this->widget_start( $args, $instance );
⋮----
$count = $this->get_filtered_product_count( $rating );
⋮----
$this->widget_end( $args );
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-recent-reviews.php">
class WC_Widget_Recent_Reviews extends WC_Widget {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function widget( $args, $instance ) {
⋮----
if ( $this->get_cached_widget( $args ) ) {
⋮----
$this->widget_start( $args, $instance );
⋮----
$this->widget_end( $args );
⋮----
$this->cache_widget( $args, $content );
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-recently-viewed.php">
use Automattic\WooCommerce\Enums\ProductStockStatus;
⋮----
class WC_Widget_Recently_Viewed extends WC_Widget {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function widget( $args, $instance ) {
⋮----
if ( $r->have_posts() ) {
⋮----
$this->widget_start( $args, $instance );
⋮----
while ( $r->have_posts() ) {
$r->the_post();
⋮----
$this->widget_end( $args );
</file>

<file path="plugins/woocommerce/includes/widgets/class-wc-widget-top-rated-products.php">
class WC_Widget_Top_Rated_Products extends WC_Widget {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function widget( $args, $instance ) {
⋮----
if ( $this->get_cached_widget( $args ) ) {
⋮----
'meta_query'     => WC()->query->get_meta_query(),
'tax_query'      => WC()->query->get_tax_query(),
⋮----
$r = $this->query_top_rated_products( $query_args );
⋮----
if ( $r->have_posts() ) {
⋮----
$this->widget_start( $args, $instance );
⋮----
while ( $r->have_posts() ) {
$r->the_post();
⋮----
$this->widget_end( $args );
⋮----
$this->cache_widget( $args, $content );
⋮----
private function query_top_rated_products( $query_args ) {
⋮----
return $query === $products ? WC()->query->order_by_rating_post_clauses( $clauses ) : $clauses;
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-ajax.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
use Automattic\WooCommerce\Internal\ProductAttributes\VisualAttributeTermMeta;
use Automattic\WooCommerce\Internal\Orders\CouponsController;
use Automattic\WooCommerce\Internal\Orders\TaxesController;
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
use Automattic\WooCommerce\Internal\Admin\Orders\ItemQuantityLimits;
use Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes\CustomMetaBox;
use Automattic\WooCommerce\Internal\Products\ProductsOrderingMoveService;
use Automattic\WooCommerce\Internal\Utilities\Users;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\ArrayUtil;
use Automattic\WooCommerce\Utilities\NumberUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Utilities\StringUtil;
⋮----
class WC_AJAX {
⋮----
public static function init() {
⋮----
self::add_ajax_events();
⋮----
public static function get_endpoint( $request = '' ) {
⋮----
private static function set_wc_ajax_argument_in_query() {
⋮----
if ( ! empty( $_GET['wc-ajax'] ) && empty( $wp_query->get( 'wc-ajax' ) ) ) {
... (818 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-auth.php">
class WC_Auth {
⋮----
public function __construct() {
⋮----
public function add_query_vars( $vars ) {
⋮----
public static function add_endpoint() {
⋮----
protected function get_i18n_scope( $scope ) {
⋮----
protected function get_permissions_in_scope( $scope ) {
⋮----
protected function build_url( $data, $endpoint ) {
⋮----
'return_url'   => rawurlencode( $this->get_formatted_url( $data['return_url'] ) ),
'callback_url' => rawurlencode( $this->get_formatted_url( $data['callback_url'] ) ),
⋮----
protected function get_formatted_url( $url ) {
⋮----
protected function make_validation() {
⋮----
$param = $this->get_formatted_url( $data[ $param ] );
⋮----
$callback_url = $this->get_formatted_url( $data['callback_url'] );
⋮----
protected function create_keys( $app_name, $app_user_id, $scope ) {
⋮----
$wpdb->insert(
⋮----
protected function post_consumer_data( $consumer_data, $url ) {
... (45 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-autoloader.php">
use Automattic\WooCommerce\Admin\Features\Features;
⋮----
class WC_Autoloader {
⋮----
private $include_path = '';
⋮----
/**
	 * The Constructor.
	 */
public function __construct() {
⋮----
private function get_file_name_from_class( $class ) {
⋮----
private function load_file( $path ) {
⋮----
public function autoload( $class ) {
⋮----
if ( \Automattic\WooCommerce\Packages::should_load_class( $class ) ) {
⋮----
$file = $this->get_file_name_from_class( $class );
⋮----
if ( Features::is_enabled( 'rest-api-v4' ) ) {
⋮----
if ( $this->load_file( $this->include_path . $rest_path . $file ) ) {
⋮----
$this->load_rest_v4_controller_recursively( $file );
⋮----
if ( empty( $path ) || ! $this->load_file( $path . $file ) ) {
$this->load_file( $this->include_path . $file );
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-background-emailer.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Background_Emailer extends WC_Background_Process {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
protected function schedule_event() {
⋮----
protected function task( $callback ) {
⋮----
WC_Emails::send_queued_transactional_email( $callback['filter'], $callback['args'] );
⋮----
if ( Constants::is_true( 'WP_DEBUG' ) ) {
⋮----
protected function close_http_connection() {
⋮----
public function dispatch_queue() {
⋮----
$this->close_http_connection();
$this->save()->dispatch();
⋮----
protected function get_post_args() {
⋮----
protected function handle() {
$this->lock_process();
⋮----
$batch = $this->get_batch();
⋮----
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-background-updater.php">
class WC_Background_Updater extends WC_Background_Process {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function dispatch() {
$dispatched = parent::dispatch();
⋮----
$logger->error(
sprintf( 'Unable to dispatch WooCommerce updater: %s', $dispatched->get_error_message() ),
⋮----
public function handle_cron_healthcheck() {
if ( $this->is_process_running() ) {
⋮----
if ( $this->is_queue_empty() ) {
⋮----
$this->clear_scheduled_event();
⋮----
$this->handle();
⋮----
protected function schedule_event() {
⋮----
public function is_updating() {
return false === $this->is_queue_empty();
⋮----
protected function task( $callback ) {
⋮----
$logger->info( sprintf( 'Running %s callback', $callback ), array( 'source' => 'wc_db_updates' ) );
⋮----
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-brands-brand-settings-manager.php">
class WC_Brands_Brand_Settings_Manager {
⋮----
private static $brand_settings = array();
⋮----
public static function set_brand_settings_on_coupon( $coupon ) {
$coupon_id = $coupon->get_id();
⋮----
public static function get_brand_settings_on_coupon( $coupon ) {
</file>

<file path="plugins/woocommerce/includes/class-wc-brands-coupons.php">
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class WC_Brands_Coupons {
⋮----
public function __construct() {
⋮----
public function is_coupon_valid( $valid, $coupon, $discounts = null ) {
$this->set_brand_settings_on_coupon( $coupon );
⋮----
$brand_coupon_settings = WC_Brands_Brand_Settings_Manager::get_brand_settings_on_coupon( $coupon );
⋮----
$items = $discounts->get_items();
⋮----
$product_brands = $this->get_product_brands( $this->get_product_id( $item->product ) );
⋮----
throw new Exception( $coupon->get_coupon_error( WC_Coupon::E_WC_COUPON_NOT_APPLICABLE ), WC_Coupon::E_WC_COUPON_NOT_APPLICABLE );
⋮----
if ( $coupon->is_type( 'fixed_cart' ) && $excluded_brands_matches > 0 ) {
⋮----
public function is_valid_for_product( $valid, $product, $coupon ) {
⋮----
$product_id     = $this->get_product_id( $product );
$product_brands = $this->get_product_brands( $product_id );
⋮----
public function brand_exclusion_error( $err, $err_code ) {
⋮----
private function get_product_brands( $product_id ) {
⋮----
private function set_brand_settings_on_coupon( $coupon ) {
⋮----
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-brands.php">
use Automattic\Jetpack\Constants;
⋮----
class WC_Brands {
⋮----
public $template_url;
⋮----
public function __construct() {
⋮----
$this->register_shortcodes();
⋮----
public function register_hooks() {
⋮----
public function recount_after_stock_change( $product_id ) {
⋮----
public function recount_all_brands() {
⋮----
public function update_product_query_tax_query( array $tax_query ) {
⋮----
public function post_type_link( $permalink, $post ) {
⋮----
public function body_class() {
⋮----
public function add_body_class( $classes ) {
⋮----
public function styles() {
if ( ! $this->should_load_brands_styles() ) {
⋮----
$version = Constants::get_constant( 'WC_VERSION' );
wp_enqueue_style( 'brands-styles', WC()->plugin_url() . '/assets/css/brands.css', array(), $version );
⋮----
... (109 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-breadcrumb.php">
class WC_Breadcrumb {
⋮----
protected $crumbs = array();
⋮----
public function add_crumb( $name, $link = '' ) {
⋮----
/**
	 * Reset crumbs.
	 *
	 * @return void
	 */
public function reset() {
⋮----
/**
	 * Get the breadcrumb.
	 *
	 * @return array
	 */
public function get_breadcrumb() {
⋮----
public function generate() {
⋮----
$this->search_trail();
$this->paged_trail();
⋮----
return $this->get_breadcrumb();
⋮----
protected function prepend_shop_page() {
⋮----
$this->add_crumb( get_the_title( $shop_page ), get_permalink( $shop_page ) );
... (140 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-cache-helper.php">
use Automattic\WooCommerce\Caching\CacheNameSpaceTrait;
use Automattic\WooCommerce\Enums\DefaultCustomerAddress;
⋮----
class WC_Cache_Helper {
⋮----
private static $delete_transients = array();
⋮----
public static function init() {
⋮----
public static function prevent_caching( $headers ) {
⋮----
self::set_nocache_constants();
⋮----
public static function queue_delete_transient( $keys ) {
⋮----
public static function delete_transients_on_shutdown() {
⋮----
public static function invalidate_attribute_count( $attribute_keys ) {
⋮----
self::queue_delete_transient( 'wc_layered_nav_counts_' . $attribute_key );
⋮----
public static function geolocation_ajax_get_location_hash() {
⋮----
$location['country']  = $customer->get_billing_country();
$location['state']    = $customer->get_billing_state();
$location['postcode'] = $customer->get_billing_postcode();
$location['city']     = $customer->get_billing_city();
⋮----
/**
		 * Controls the location hash used in geolocation-based caching.
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-cart-fees.php">
final class WC_Cart_Fees {
⋮----
private $fees = array();
⋮----
private $default_fee_props = array(
⋮----
public function __construct( $deprecated = null ) {
⋮----
public function init() {}
⋮----
public function add_fee( $args = array() ) {
⋮----
$fee_props->tax_class = in_array( $fee_props->tax_class, array_merge( WC_Tax::get_tax_classes(), WC_Tax::get_tax_class_slugs() ), true ) ? $fee_props->tax_class : '';
⋮----
$fee_props->id = $this->generate_id( $fee_props );
⋮----
public function get_fees() {
⋮----
public function set_fees( $raw_fees = array() ) {
⋮----
$this->add_fee( $raw_fee );
⋮----
public function remove_all_fees() {
$this->set_fees();
⋮----
protected function sort_fees_callback( $a, $b ) {
⋮----
private function generate_id( $fee ) {
</file>

<file path="plugins/woocommerce/includes/class-wc-cart-session.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
final class WC_Cart_Session {
⋮----
protected $cart;
⋮----
public function __construct( $cart ) {
⋮----
$this->set_cart( $cart );
⋮----
public function set_cart( WC_Cart $cart ) {
⋮----
public function init() {
⋮----
public function get_cart_from_session() {
⋮----
$this->cart->set_totals( WC()->session->get( 'cart_totals', null ) );
$this->cart->set_applied_coupons( WC()->session->get( 'applied_coupons', array() ) );
$this->cart->set_coupon_discount_totals( WC()->session->get( 'coupon_discount_totals', array() ) );
$this->cart->set_coupon_discount_tax_totals( WC()->session->get( 'coupon_discount_tax_totals', array() ) );
$this->cart->set_removed_cart_contents( WC()->session->get( 'removed_cart_contents', array() ) );
⋮----
$cart                = WC()->session->get( 'cart', null );
⋮----
$saved_cart          = $this->get_saved_cart();
⋮----
$cart                = $this->populate_cart_from_order( absint( $_GET['order_again'] ), $cart );
⋮----
if ( empty( $product ) || ! $product->exists() || 0 >= $values['quantity'] ) {
... (123 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-cart-totals.php">
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
final class WC_Cart_Totals {
⋮----
protected $cart;
⋮----
protected $items = array();
⋮----
protected $fees = array();
⋮----
protected $shipping = array();
⋮----
protected $coupons = array();
⋮----
private $coupon_application_positions = array();
⋮----
protected $coupon_discount_totals = array();
⋮----
protected $coupon_discount_tax_totals = array();
⋮----
protected $calculate_tax = true;
⋮----
protected $totals = array(
⋮----
protected $item_tax_rates;
⋮----
public function __construct( &$cart = null ) {
⋮----
$customer               = $cart->get_customer();
... (204 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-cart.php">
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
use Automattic\WooCommerce\Internal\ProductVariations\SelectedVariationName;
use Automattic\WooCommerce\Internal\Tax\TaxRateDataStore;
use Automattic\WooCommerce\StoreApi\Utilities\LocalPickupUtils;
use Automattic\WooCommerce\Utilities\DiscountsUtil;
use Automattic\WooCommerce\Utilities\NumberUtil;
use Automattic\WooCommerce\Utilities\ShippingUtil;
⋮----
class WC_Cart extends WC_Legacy_Cart {
⋮----
public $cart_context = 'shortcode';
⋮----
public $cart_contents = array();
⋮----
public $removed_cart_contents = array();
⋮----
public $applied_coupons = array();
⋮----
protected $shipping_methods;
⋮----
protected $has_calculated_shipping = false;
⋮----
protected $default_totals = array(
⋮----
protected $totals = array();
⋮----
protected $session;
... (624 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-checkout.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
use Automattic\WooCommerce\Internal\ProductVariations\SelectedVariationName;
use Automattic\WooCommerce\Internal\Tax\TaxRateDataStore;
⋮----
class WC_Checkout {
⋮----
protected static $instance = null;
⋮----
protected $fields = null;
⋮----
protected $legacy_posted_data = array();
⋮----
private $logged_in_customer = null;
⋮----
public static function instance() {
⋮----
public function __isset( $key ) {
⋮----
public function __set( $key, $value ) {
⋮----
if ( $bool_value !== $this->is_registration_enabled() ) {
⋮----
if ( $bool_value === $this->is_registration_required() ) {
⋮----
WC()->session->set( 'chosen_shipping_methods', $value );
⋮----
public function __get( $key ) {
... (348 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-cli.php">
use Automattic\WooCommerce\Database\Migrations\CustomOrderTable\CLIRunner as CustomOrdersTableCLIRunner;
use Automattic\WooCommerce\Internal\ProductAttributesLookup\CLIRunner as ProductAttributesLookupCLIRunner;
use Automattic\WooCommerce\Internal\Integrations\WPPostsImporter;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use Automattic\WooCommerce\Internal\CLI\Migrator\Runner;
⋮----
class WC_CLI {
⋮----
public function __construct() {
$this->includes();
$this->hooks();
⋮----
$wp_posts_importer = wc_get_container()->get( WPPostsImporter::class );
$wp_posts_importer->register();
⋮----
private function includes() {
⋮----
private function hooks() {
WP_CLI::add_hook( 'after_wp_load', 'WC_CLI_Runner::after_wp_load' );
WP_CLI::add_hook( 'after_wp_load', 'WC_CLI_Tool_Command::register_commands' );
WP_CLI::add_hook( 'after_wp_load', 'WC_CLI_Update_Command::register_commands' );
WP_CLI::add_hook( 'after_wp_load', 'WC_CLI_Tracker_Command::register_commands' );
WP_CLI::add_hook( 'after_wp_load', 'WC_CLI_COM_Command::register_commands' );
⋮----
WP_CLI::add_hook( 'after_wp_load', 'WC_CLI_COM_Extension_Command::register_commands' );
⋮----
WP_CLI::add_hook( 'after_wp_load', 'Automattic\WooCommerce\Internal\CLI\Migrator\Runner::register_commands' );
⋮----
$cli_runner = wc_get_container()->get( CustomOrdersTableCLIRunner::class );
WP_CLI::add_hook( 'after_wp_load', array( $cli_runner, 'register_commands' ) );
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-comments.php">
use Automattic\WooCommerce\Internal\Admin\ProductReviews\ReviewsUtil;
⋮----
class WC_Comments {
⋮----
public static function init() {
⋮----
public static function comments_open( $open, $post_id ) {
⋮----
public static function exclude_order_comments( $clauses ) {
⋮----
/**
	 * Exclude order comments from Akismet comments counting SQL queries for better performance.
	 *
	 * @since 10.6.0
	 *
	 * @param string[] $comment_types Excluded comments types.
	 * @return string[]
	 */
public static function akismet_excluded_comment_types( $comment_types ): array {
⋮----
/**
	 * Exclude order comments from feed.
	 *
	 * @deprecated 3.1
	 * @param mixed $join Deprecated.
	 */
public static function exclude_order_comments_from_feed_join( $join ) {
⋮----
/**
	 * Exclude order comments from queries and RSS.
... (296 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-countries.php">
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
⋮----
class WC_Countries {
⋮----
public $locale = array();
⋮----
public $address_formats = array();
⋮----
private $geo_cache = array();
⋮----
private $country_locale_built_for = null;
⋮----
private $country_locale_building = false;
⋮----
private $last_cache_locale = null;
⋮----
private $geo_cache_building = array();
⋮----
private static $locale_resolution_snapshots = null;
⋮----
private function get_cache_locale() {
⋮----
self::restore_locale_resolution_snapshots();
⋮----
private static function restore_locale_resolution_snapshots() {
⋮----
public function __get( $key ) {
⋮----
return $this->get_countries();
⋮----
... (175 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-coupon.php">
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Utilities\NumberUtil;
use Automattic\WooCommerce\Utilities\StringUtil;
⋮----
class WC_Coupon extends WC_Legacy_Coupon {
⋮----
protected $data = array(
⋮----
protected $cache_group = 'coupons';
⋮----
public $error_message;
⋮----
public $sort = 0;
⋮----
public function __construct( $data = '' ) {
parent::__construct( $data );
⋮----
// If we already have a coupon object, read it again.
⋮----
$this->set_id( absint( $data->get_id() ) );
$this->read_object_from_database();
⋮----
// This filter allows custom coupon objects to be created on the fly.
⋮----
$this->read_manual_coupon( $data, $coupon );
⋮----
$this->set_id( $data );
} elseif ( is_string( $data ) && ! StringUtil::is_null_or_whitespace( $data ) ) {
⋮----
$this->set_id( $id );
... (339 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-customer-download-log.php">
class WC_Customer_Download_Log extends WC_Data {
⋮----
protected $object_type = 'customer_download_log';
⋮----
protected $data = array(
⋮----
public function __construct( $download_log = 0 ) {
parent::__construct( $download_log );
⋮----
$this->set_id( $download_log );
⋮----
$this->set_id( $download_log->get_id() );
⋮----
$this->set_id( $download_log->download_log_id );
$this->set_props( (array) $download_log );
$this->set_object_read( true );
⋮----
$this->data_store = WC_Data_Store::load( 'customer-download-log' );
⋮----
if ( $this->get_id() > 0 ) {
$this->data_store->read( $this );
⋮----
public function get_timestamp( $context = 'view' ) {
return $this->get_prop( 'timestamp', $context );
⋮----
public function get_permission_id( $context = 'view' ) {
return $this->get_prop( 'permission_id', $context );
⋮----
public function get_user_id( $context = 'view' ) {
return $this->get_prop( 'user_id', $context );
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-customer-download.php">
class WC_Customer_Download extends WC_Data implements ArrayAccess {
⋮----
protected $object_type = 'customer_download';
⋮----
protected $data = array(
⋮----
public function __construct( $download = 0 ) {
parent::__construct( $download );
⋮----
$this->set_id( $download );
⋮----
$this->set_id( $download->get_id() );
⋮----
$this->set_id( $download->permission_id );
$this->set_props( (array) $download );
$this->set_object_read( true );
⋮----
$this->data_store = WC_Data_Store::load( 'customer-download' );
⋮----
if ( $this->get_id() > 0 ) {
$this->data_store->read( $this );
⋮----
public function get_download_id( $context = 'view' ) {
return $this->get_prop( 'download_id', $context );
⋮----
public function get_product_id( $context = 'view' ) {
return $this->get_prop( 'product_id', $context );
⋮----
public function get_user_id( $context = 'view' ) {
return $this->get_prop( 'user_id', $context );
... (111 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-customer.php">
use Automattic\WooCommerce\Enums\TaxBasedOn;
⋮----
class WC_Customer extends WC_Legacy_Customer {
⋮----
protected $data = array(
⋮----
protected $password = '';
⋮----
/**
	 * Stores if user is VAT exempt for this session.
	 *
	 * @var bool
	 */
protected $is_vat_exempt = false;
⋮----
/**
	 * Stores if user has calculated shipping in this session.
	 *
	 * @var bool
	 */
protected $calculated_shipping = false;
⋮----
/**
	 * This is the name of this object type.
	 *
	 * @since 5.6.0
	 * @var string
	 */
protected $object_type = 'customer';
⋮----
... (335 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-data-exception.php">
class WC_Data_Exception extends Exception {
⋮----
protected $error_code;
⋮----
protected $error_data;
⋮----
public function __construct( $code, $message, $http_status_code = 400, $data = array() ) {
⋮----
parent::__construct( $message, $http_status_code );
⋮----
public function getErrorCode() {
⋮----
public function getErrorData() {
</file>

<file path="plugins/woocommerce/includes/class-wc-data-store.php">
class WC_Data_Store {
⋮----
private $instance = null;
⋮----
private $stores = array(
⋮----
private $current_class_name = '';
⋮----
/**
	 * The object type this store works with.
	 *
	 * @var string
	 */
private $object_type = '';
⋮----
/**
	 * Tells WC_Data_Store which object (coupon, product, order, etc)
	 * store we want to work with.
	 *
	 * @throws Exception When validation fails.
	 * @param string $object_type Name of object.
	 */
public function __construct( $object_type ) {
⋮----
$this->instance           = new $store();
⋮----
public function __sleep() {
⋮----
public function __wakeup() {
$this->__construct( $this->object_type );
... (27 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-datetime.php">
class WC_DateTime extends DateTime {
⋮----
protected $utc_offset = 0;
⋮----
public function __toString() {
return $this->format( DATE_ATOM );
⋮----
public function set_utc_offset( $offset ) {
⋮----
public function getOffset() {
return $this->utc_offset ?: parent::getOffset();
⋮----
public function setTimezone( $timezone ) {
⋮----
return parent::setTimezone( $timezone );
⋮----
public function getTimestamp() {
return method_exists( 'DateTime', 'getTimestamp' ) ? parent::getTimestamp() : $this->format( 'U' );
⋮----
public function getOffsetTimestamp() {
return $this->getTimestamp() + $this->getOffset();
⋮----
public function date( $format ) {
return gmdate( $format, $this->getOffsetTimestamp() );
⋮----
public function date_i18n( $format = 'Y-m-d' ) {
return date_i18n( $format, $this->getOffsetTimestamp() );
</file>

<file path="plugins/woocommerce/includes/class-wc-deprecated-action-hooks.php">
class WC_Deprecated_Action_Hooks extends WC_Deprecated_Hooks {
⋮----
protected $deprecated_hooks = array(
⋮----
protected $deprecated_version = array(
⋮----
public function hook_in( $hook_name ) {
⋮----
public function handle_deprecated_hook( $new_hook, $old_hook, $new_callback_args, $return_value ) {
⋮----
$this->display_notice( $old_hook, $new_hook );
$return_value = $this->trigger_hook( $old_hook, $new_callback_args );
⋮----
protected function trigger_hook( $old_hook, $new_callback_args ) {
⋮----
do_action( $old_hook, $order_id, $item_id, $item->get_code(), $item->get_discount(), $item->get_discount_tax() );
⋮----
do_action( $old_hook, $order_id, $item_id, $item->get_rate_id(), $item->get_tax_total(), $item->get_shipping_tax_total() );
⋮----
do_action( $old_hook, $order_id, $item_id, $item, $item->get_product() );
</file>

<file path="plugins/woocommerce/includes/class-wc-deprecated-filter-hooks.php">
class WC_Deprecated_Filter_Hooks extends WC_Deprecated_Hooks {
⋮----
protected $deprecated_hooks = array(
⋮----
protected $deprecated_version = array(
⋮----
public function hook_in( $hook_name ) {
⋮----
public function handle_deprecated_hook( $new_hook, $old_hook, $new_callback_args, $return_value ) {
⋮----
$this->display_notice( $old_hook, $new_hook );
$return_value = $this->trigger_hook( $old_hook, $new_callback_args );
⋮----
protected function trigger_hook( $old_hook, $new_callback_args ) {
</file>

<file path="plugins/woocommerce/includes/class-wc-discounts.php">
use Automattic\WooCommerce\Enums\OrderInternalStatus;
use Automattic\WooCommerce\Utilities\DiscountsUtil;
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
class WC_Discounts {
⋮----
protected $object;
⋮----
protected $items = array();
⋮----
protected $discounts = array();
⋮----
public function __construct( $object = null ) {
⋮----
$this->set_items_from_cart( $object );
⋮----
$this->set_items_from_order( $object );
⋮----
public function set_items( $items ) {
⋮----
public function set_items_from_cart( $cart ) {
⋮----
foreach ( $cart->get_cart() as $key => $cart_item ) {
⋮----
$item->price         = wc_add_number_precision_deep( (float) $item->product->get_price() * (float) $item->quantity );
⋮----
public function set_items_from_order( $order ) {
⋮----
foreach ( $order->get_items() as $order_item ) {
⋮----
... (239 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-download-handler.php">
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
⋮----
class WC_Download_Handler {
⋮----
public static function init() {
⋮----
public static function download_product() {
⋮----
self::download_error( __( 'Invalid download link.', 'woocommerce' ) );
⋮----
$downloads  = $product ? $product->get_downloads() : array();
$data_store = WC_Data_Store::load( 'customer-download' );
⋮----
|| ! $downloads[ $key ]->get_enabled()
⋮----
$email_address = is_a( $order, 'WC_Order' ) ? $order->get_billing_email() : null;
⋮----
$download_ids = $data_store->get_downloads(
⋮----
$product->get_file_download_path( $download->get_download_id() ),
⋮----
$parsed_file_path = self::parse_file_path( $file_path );
$download_range   = self::get_download_range( @filesize( $parsed_file_path['file_path'] ) );
⋮----
self::check_order_is_valid( $download );
⋮----
self::check_downloads_remaining( $download );
⋮----
self::check_download_expiry( $download );
self::check_download_login_required( $download );
... (252 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-emails.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Email\DeferredEmailQueue;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Admin\Features\Fulfillments\Fulfillment;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WC_Emails {
⋮----
public $emails = array();
⋮----
protected static $instance = null;
⋮----
protected static $deferred_queue = null;
⋮----
public static function instance() {
⋮----
public function __clone() {
⋮----
public function __wakeup() {
⋮----
public static function init_transactional_emails() {
⋮----
$defer_default = FeaturesUtil::feature_is_enabled( 'deferred_transactional_emails' );
⋮----
self::$deferred_queue = wc_get_container()->get( DeferredEmailQueue::class );
⋮----
public static function queue_transactional_email( ...$args ) {
if ( self::$deferred_queue instanceof DeferredEmailQueue && self::$deferred_queue->push( current_filter(), $args ) ) {
... (191 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-embed.php">
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class WC_Embed {
⋮----
public static function init() {
⋮----
public static function remove_comments_button() {
if ( self::is_embedded_product() ) {
⋮----
public static function is_embedded_product() {
⋮----
public static function the_excerpt( $excerpt ) {
⋮----
echo '<p><span class="wc-embed-price">' . $_product->get_price_html() . '</span></p>';
⋮----
$excerpt .= self::product_buttons();
⋮----
public static function product_buttons() {
⋮----
if ( $_product->is_type( ProductType::SIMPLE ) && $_product->is_purchasable() && $_product->is_in_stock() ) {
⋮----
public static function get_ratings() {
⋮----
if ( ! self::is_embedded_product() ) {
⋮----
if ( $_product && $_product->get_average_rating() > 0 ) {
⋮----
esc_html( $_product->get_average_rating() )
⋮----
public static function print_embed_styles() {
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-form-handler.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\PaymentGatewayFeature;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class WC_Form_Handler {
⋮----
private static $handled_cancel_order_ids = array();
⋮----
private static $cancel_order_redirect_pending = false;
⋮----
public static function init() {
⋮----
public static function set_reset_password_bridge_headers( $headers ) {
⋮----
if ( ! WC_Shortcode_My_Account::is_password_reset_bridge_handle( $bridge_handle ) || ! is_account_page() ) {
⋮----
WC_Cache_Helper::set_nocache_constants();
⋮----
public static function redirect_reset_password_link() {
⋮----
$action        = isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
⋮----
$bridge_token   = WC_Shortcode_My_Account::create_password_reset_bridge_token( $validated_user );
⋮----
WC_Shortcode_My_Account::set_reset_password_cookie( $value );
⋮----
public static function resend_set_password(): void {
⋮----
WC()->mailer();
⋮----
... (235 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-frontend-scripts.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Enums\DefaultCustomerAddress;
use Automattic\WooCommerce\Internal\AddressProvider\AddressProviderController;
⋮----
class WC_Frontend_Scripts {
⋮----
private static $registered_scripts = array();
⋮----
private static $styles = array();
⋮----
private static $wp_localize_scripts = array();
⋮----
public static function init() {
⋮----
public static function get_styles() {
$version = Constants::get_constant( 'WC_VERSION' );
⋮----
'src'     => self::get_asset_url( 'assets/css/woocommerce-layout.css' ),
⋮----
'src'     => self::get_asset_url( 'assets/css/woocommerce-smallscreen.css' ),
⋮----
'src'     => self::get_asset_url( 'assets/css/woocommerce.css' ),
⋮----
public static function enqueue_block_assets() {
⋮----
self::get_asset_url( 'assets/css/woocommerce-blocktheme.css' ),
⋮----
private static function get_asset_url( $path ) {
⋮----
... (201 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-geo-ip.php">
class WC_Geo_IP {
⋮----
public $flags;
⋮----
public $filehandle;
⋮----
public $memory_buffer;
⋮----
public $databaseType;
⋮----
public $databaseSegments;
⋮----
public $record_length;
⋮----
public $shmid;
⋮----
public $GEOIP_COUNTRY_CODES = array(
⋮----
public $GEOIP_COUNTRY_CODES3 = array(
⋮----
public $GEOIP_COUNTRY_NAMES = array(
⋮----
public $GEOIP_CONTINENT_CODES = array(
⋮----
public static $log = false;
⋮----
public static function log( $message, $level = 'info' ) {
⋮----
self::$log->log( $level, $message, array( 'source' => 'geoip' ) );
⋮----
... (76 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-geolite-integration.php">
class WC_Geolite_Integration {
⋮----
private $database = '';
⋮----
/**
	 * Logger instance.
	 *
	 * @var WC_Logger
	 */
private $log = null;
⋮----
/**
	 * Constructor.
	 *
	 * @param string $database MaxMind GeoLite2 database path.
	 */
public function __construct( $database ) {
⋮----
/**
	 * Get country 2-letters ISO by IP address.
	 * Returns empty string when not able to find any ISO code.
	 *
	 * @param string $ip_address User IP address.
	 * @return string
	 * @deprecated 3.9.0
	 */
public function get_country_iso( $ip_address ) {
⋮----
$reader = new MaxMind\Db\Reader( $this->database ); // phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound
$data   = $reader->get( $ip_address );
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-geolocation.php">
use Automattic\WooCommerce\Enums\DefaultCustomerAddress;
⋮----
class WC_Geolocation {
⋮----
private static $ip_lookup_apis = array(
⋮----
private static $geoip_apis = array(
⋮----
private static function is_geolocation_enabled( $current_settings ) {
⋮----
public static function get_ip_address() {
⋮----
/**
	 * Get user IP Address using an external service.
	 * This can be used as a fallback for users on localhost where
	 * get_ip_address() will be a local IP and non-geolocatable.
	 *
	 * @return string
	 */
public static function get_external_ip_address() {
⋮----
if ( '' !== self::get_ip_address() ) {
$transient_name      = 'external_ip_address_' . self::get_ip_address();
⋮----
public static function geolocate_ip( $ip_address = '', $fallback = false, $api_fallback = true ) {
/**
		 * Filter to allow custom geolocation of the IP address.
		 *
		 * @since 3.9.0
		 * @param string $geolocation Country code.
... (51 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-https.php">
class WC_HTTPS {
⋮----
public static function init() {
⋮----
public static function force_https_url( $content ) {
⋮----
public static function force_https_page_link( $link, $page_id ) {
⋮----
public static function force_https_template_redirect() {
⋮----
public static function unforce_https_template_redirect() {
⋮----
public static function http_api_curl( $handle, $r, $url ) {
⋮----
WC_HTTPS::init();
</file>

<file path="plugins/woocommerce/includes/class-wc-install.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Admin\API\Reports\Orders\Stats\DataStore;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\Admin\EmailImprovements\EmailImprovements;
use Automattic\WooCommerce\Internal\Caches\ProductCacheController;
use Automattic\WooCommerce\Internal\TransientFiles\TransientFilesEngine;
use Automattic\WooCommerce\Internal\DataStores\Orders\{ CustomOrdersTableController, DataSynchronizer, OrdersTableDataStore };
use Automattic\WooCommerce\Internal\DataStores\StockNotifications\StockNotificationsDataStore;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\ProductAttributesLookup\DataRegenerator;
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Synchronize as Download_Directories_Sync;
use Automattic\WooCommerce\Admin\API\Reports\Orders\Stats\DataStore as OrdersStatsDataStore;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
use Automattic\WooCommerce\Internal\WCCom\ConnectionHelper as WCConnectionHelper;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use Automattic\WooCommerce\Utilities\{ OrderUtil, PluginUtil };
⋮----
class WC_Install {
⋮----
private static $db_updates = array(
⋮----
public static function init() {
⋮----
public static function newly_installed() {
⋮----
/**
	 * Check WooCommerce version and run the updater is required.
	 *
	 * This check is done on all requests and runs if the versions do not match.
... (407 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-integrations.php">
class WC_Integrations {
⋮----
public $integrations = array();
⋮----
public function __construct() {
⋮----
$load_integration = new $integration();
⋮----
public function get_integrations() {
⋮----
public function get_integration( $id ) {
</file>

<file path="plugins/woocommerce/includes/class-wc-log-levels.php">
abstract class WC_Log_Levels {
⋮----
protected static $level_to_severity = array(
⋮----
protected static $severity_to_level = array(
⋮----
public static function is_valid_level( $level ) {
⋮----
public static function get_level_severity( $level ) {
return self::is_valid_level( $level ) ? self::$level_to_severity[ strtolower( $level ) ] : 0;
⋮----
public static function get_all_level_severities() {
⋮----
public static function get_severity_level( $severity ) {
⋮----
public static function get_all_severity_levels() {
⋮----
public static function get_level_label( $level ) {
$labels = self::get_all_level_labels();
⋮----
/**
	 * Get the UI labels for all log levels.
	 *
	 * @return string[]
	 */
public static function get_all_level_labels() {
</file>

<file path="plugins/woocommerce/includes/class-wc-logger.php">
use Automattic\WooCommerce\Utilities\LoggingUtil;
⋮----
class WC_Logger implements WC_Logger_Interface {
⋮----
protected $handlers;
⋮----
protected $threshold;
⋮----
public function __construct( $handlers = null, $threshold = null ) {
⋮----
protected function get_handlers() {
⋮----
$default_handler  = LoggingUtil::get_default_handler();
$handler_instance = new $default_handler();
⋮----
protected function get_threshold() {
⋮----
if ( ! WC_Log_Levels::is_valid_level( $threshold ) ) {
$threshold = LoggingUtil::get_level_threshold();
⋮----
return WC_Log_Levels::get_level_severity( $threshold );
⋮----
protected function should_handle( $level ) {
if ( ! LoggingUtil::logging_is_enabled() ) {
⋮----
$threshold = $this->get_threshold();
⋮----
return $threshold <= WC_Log_Levels::get_level_severity( $level );
⋮----
public function add( $handle, $message, $level = WC_Log_Levels::NOTICE ) {
... (45 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-meta-data.php">
class WC_Meta_Data implements JsonSerializable {
⋮----
protected $current_data;
⋮----
protected $data;
⋮----
public function __construct( $meta = array() ) {
⋮----
$this->apply_changes();
⋮----
public function jsonSerialize() {
return $this->get_data();
⋮----
public function apply_changes() {
⋮----
public function __set( $key, $value ) {
⋮----
public function __isset( $key ) {
⋮----
public function __get( $key ) {
⋮----
public function get_changes() {
⋮----
public function get_data() {
</file>

<file path="plugins/woocommerce/includes/class-wc-order-factory.php">
use Automattic\WooCommerce\Caches\OrderCache;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class WC_Order_Factory {
⋮----
public static function get_order( $order_id = false ) {
$order_id = self::get_order_id( $order_id );
⋮----
$use_orders_cache = OrderUtil::orders_cache_usage_is_enabled();
⋮----
$order_cache = wc_get_container()->get( OrderCache::class );
$order       = $order_cache->get( $order_id );
⋮----
return 0 === $order->get_id() ? false : $order;
⋮----
$classname = self::get_class_name_for_order_id( $order_id );
⋮----
$order = new $classname( $order_id );
⋮----
$order_cache->set( $order, $order_id );
⋮----
wc_get_logger()->error(
⋮----
$e->getMessage()
⋮----
public static function get_orders( $order_ids = array(), $skip_invalid = false ) {
⋮----
$order_cache         = wc_get_container()->get( OrderCache::class );
⋮----
$use_orders_cache      = OrderUtil::orders_cache_usage_is_enabled();
... (50 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-order-item-coupon.php">
class WC_Order_Item_Coupon extends WC_Order_Item {
⋮----
protected $extra_data = array(
⋮----
public function set_name( $value ) {
return $this->set_code( $value );
⋮----
public function set_code( $value ) {
$this->set_prop( 'code', wc_format_coupon_code( $value ) );
⋮----
public function set_discount( $value ) {
$this->set_prop( 'discount', wc_format_decimal( $value ) );
⋮----
public function set_discount_tax( $value ) {
$this->set_prop( 'discount_tax', wc_format_decimal( $value ) );
⋮----
public function get_type() {
⋮----
public function get_name( $context = 'view' ) {
return $this->get_code( $context );
⋮----
public function get_code( $context = 'view' ) {
return $this->get_prop( 'code', $context );
⋮----
public function get_discount( $context = 'view' ) {
return $this->get_prop( 'discount', $context );
⋮----
public function get_discount_tax( $context = 'view' ) {
return $this->get_prop( 'discount_tax', $context );
⋮----
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-order-item-fee.php">
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
class WC_Order_Item_Fee extends WC_Order_Item {
⋮----
public $legacy_fee = '';
⋮----
/**
	 * Legacy fee key.
	 *
	 * @deprecated 4.4.0 For legacy actions.
	 * @var string
	 */
public $legacy_fee_key = '';
⋮----
/**
	 * Order Data array. This is the core order data exposed in APIs since 3.0.0.
	 *
	 * @since 3.0.0
	 * @var array
	 */
protected $extra_data = array(
⋮----
protected function get_tax_class_costs( $order ) {
$order_item_tax_classes = $order->get_items_tax_classes();
⋮----
foreach ( $order->get_items( array( 'line_item', 'fee', 'shipping' ) ) as $item ) {
if ( 0 > $item->get_total() ) {
⋮----
if ( ProductTaxStatus::TAXABLE !== $item->get_tax_status() ) {
... (100 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-order-item-meta.php">
class WC_Order_Item_Meta {
⋮----
private $legacy = false;
⋮----
private $item = null;
⋮----
public $meta = null;
⋮----
public $product = null;
⋮----
public function __construct( $item = array(), $product = null ) {
⋮----
public function display( $flat = false, $return = false, $hideprefix = '_', $delimiter = ", \n" ) {
⋮----
$formatted_meta = $this->get_formatted( $hideprefix );
⋮----
public function get_formatted( $hideprefix = '_' ) {
⋮----
return $this->get_formatted_legacy( $hideprefix );
⋮----
// If this is a term slug, get the term's nice name.
⋮----
public function get_formatted_legacy( $hideprefix = '_' ) {
</file>

<file path="plugins/woocommerce/includes/class-wc-order-item-product.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
class WC_Order_Item_Product extends WC_Order_Item {
⋮----
public $legacy_values;
⋮----
public $legacy_cart_item_key;
⋮----
protected $extra_data = array(
⋮----
public function set_quantity( $value ) {
$this->set_prop( 'quantity', wc_stock_amount( $value ) );
⋮----
public function set_tax_class( $value ) {
if ( $value && ! in_array( $value, WC_Tax::get_tax_class_slugs(), true ) ) {
$this->error( 'order_item_product_invalid_tax_class', __( 'Invalid tax class', 'woocommerce' ) );
⋮----
$this->set_prop( 'tax_class', $value );
⋮----
public function set_product_id( $value ) {
⋮----
$this->error( 'order_item_product_invalid_product_id', __( 'Invalid product ID', 'woocommerce' ) );
⋮----
$this->set_prop( 'product_id', absint( $value ) );
⋮----
public function set_variation_id( $value ) {
⋮----
... (176 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-order-item-shipping.php">
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
class WC_Order_Item_Shipping extends WC_Order_Item {
⋮----
protected $extra_data = array(
⋮----
public function calculate_taxes( $calculate_tax_for = array() ) {
⋮----
if ( wc_tax_enabled() && ProductTaxStatus::TAXABLE === $this->get_tax_status() ) {
$tax_rates = WC_Tax::find_shipping_rates( $calculate_tax_for );
$taxes     = WC_Tax::calc_tax( $this->get_total(), $tax_rates, false );
$this->set_taxes( array( 'total' => $taxes ) );
⋮----
$this->set_taxes( false );
⋮----
public function set_name( $value ) {
$this->set_method_title( $value );
⋮----
public function set_method_title( $value ) {
$this->set_prop( 'name', wc_clean( $value ) );
$this->set_prop( 'method_title', wc_clean( $value ) );
⋮----
public function set_method_id( $value ) {
$this->set_prop( 'method_id', wc_clean( $value ) );
⋮----
public function set_instance_id( $value ) {
$this->set_prop( 'instance_id', wc_clean( $value ) );
⋮----
public function set_total( $value ) {
... (73 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-order-item-tax.php">
class WC_Order_Item_Tax extends WC_Order_Item {
⋮----
protected $extra_data = array(
⋮----
public function set_name( $value ) {
$this->set_rate_code( $value );
⋮----
public function set_rate_code( $value ) {
$this->set_prop( 'rate_code', wc_clean( $value ) );
⋮----
public function set_label( $value ) {
$this->set_prop( 'label', wp_strip_all_tags( $value ) );
⋮----
public function set_rate_id( $value ) {
$this->set_prop( 'rate_id', absint( $value ) );
⋮----
public function set_tax_total( $value ) {
$this->set_prop( 'tax_total', $value ? wc_format_decimal( $value ) : 0 );
⋮----
public function set_shipping_tax_total( $value ) {
$this->set_prop( 'shipping_tax_total', $value ? wc_format_decimal( $value ) : 0 );
⋮----
public function set_compound( $value ) {
$this->set_prop( 'compound', (bool) $value );
⋮----
public function set_rate_percent( $value ) {
$this->set_prop( 'rate_percent', (float) $value );
⋮----
public function set_rate( $tax_rate_id ) {
$tax_rate = WC_Tax::_get_tax_rate( $tax_rate_id, OBJECT );
... (48 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-order-item.php">
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
⋮----
class WC_Order_Item extends WC_Data implements ArrayAccess {
⋮----
public $legacy_values;
⋮----
public $legacy_cart_item_key;
⋮----
protected $data = array(
⋮----
/**
	 * Stores meta in cache for future reads.
	 * A group must be set to to enable caching.
	 *
	 * @var string
	 */
protected $cache_group = 'order-items';
⋮----
protected $meta_type = 'order_item';
⋮----
protected $object_type = 'order_item';
⋮----
public $legacy_package_key;
⋮----
private $order;
⋮----
public function __construct( $item = 0 ) {
if ( $this->has_cogs() && $this->cogs_is_enabled() ) {
... (195 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-order-query.php">
class WC_Order_Query extends WC_Object_Query {
⋮----
protected function get_default_query_vars() {
⋮----
parent::get_default_query_vars(),
⋮----
/**
	 * Get orders matching the current query vars.
	 *
	 * @return array|object of WC_Order objects
	 *
	 * @throws Exception When WC_Data_Store validation fails.
	 */
public function get_orders() {
$args    = apply_filters( 'woocommerce_order_query_args', $this->get_query_vars() );
$results = WC_Data_Store::load( 'order' )->query( $args );
</file>

<file path="plugins/woocommerce/includes/class-wc-order-refund.php">
use Automattic\WooCommerce\Enums\OrderStatus;
⋮----
class WC_Order_Refund extends WC_Abstract_Order {
⋮----
protected $data_store_name = 'order-refund';
⋮----
protected $object_type = 'order_refund';
⋮----
protected $extra_data = array(
⋮----
protected $legacy_datastore_props = array(
⋮----
public function get_type() {
⋮----
public function get_status( $context = 'view' ) {
⋮----
public function get_post_title() {
⋮----
return sprintf( __( 'Refund &ndash; %s', 'woocommerce' ), (new DateTime('now'))->format( _x( 'M d, Y @ h:i A', 'Order date parsed by DateTime::format', 'woocommerce' ) ) );
⋮----
public function get_amount( $context = 'view' ) {
return $this->get_prop( 'amount', $context );
⋮----
public function get_reason( $context = 'view' ) {
return $this->get_prop( 'reason', $context );
⋮----
public function get_refunded_by( $context = 'view' ) {
return $this->get_prop( 'refunded_by', $context );
⋮----
public function get_refunded_payment( $context = 'view' ) {
... (35 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-order.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use Automattic\WooCommerce\StoreApi\Utilities\LocalPickupUtils;
use Automattic\WooCommerce\Utilities\NumberUtil;
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
⋮----
class WC_Order extends WC_Abstract_Order {
⋮----
protected $status_transition = false;
⋮----
protected $data = array(
⋮----
// Operational data.
⋮----
protected $legacy_datastore_props = array(
⋮----
public $refunds = array();
⋮----
public function payment_complete( $transaction_id = '' ) {
if ( ! $this->get_id() ) { // Order must exist.
⋮----
do_action( 'woocommerce_pre_payment_complete', $this->get_id(), $transaction_id );
⋮----
WC()->session->set( 'order_awaiting_payment', false );
⋮----
if ( $this->has_status( $valid_completed_statuses ) ) {
⋮----
$this->set_transaction_id( $transaction_id );
⋮----
... (662 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-payment-gateways.php">
use Automattic\WooCommerce\Enums\PaymentGatewayFeature;
use Automattic\WooCommerce\Internal\Admin\Settings\Payments as SettingsPaymentsService;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\ArrayUtil;
⋮----
class WC_Payment_Gateways {
⋮----
public $payment_gateways = array();
⋮----
protected static $_instance = null;
⋮----
public static function instance() {
⋮----
public function __clone() {
⋮----
public function __wakeup() {
⋮----
public function __construct() {
$this->init();
⋮----
public function init() {
⋮----
$gateway = new $gateway();
⋮----
WC_Gateway_Paypal::set_instance( $gateway );
if ( ! $this->should_load_paypal_standard() ) {
⋮----
public function on_payment_gateways_initialized( WC_Payment_Gateways $wc_payment_gateways ) {
... (89 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-payment-tokens.php">
class WC_Payment_Tokens {
⋮----
public static function get_tokens( $args ) {
⋮----
$data_store    = WC_Data_Store::load( 'payment-token' );
$token_results = $data_store->get_tokens( $args );
⋮----
$_token = self::get( $token_result->token_id, $token_result );
⋮----
public static function get_customer_tokens( $customer_id, $gateway_id = '' ) {
⋮----
$tokens = self::get_tokens(
⋮----
public static function get_customer_default_token( $customer_id ) {
⋮----
$data_store = WC_Data_Store::load( 'payment-token' );
$token      = $data_store->get_users_default_token( $customer_id );
⋮----
return self::get( $token->token_id, $token );
⋮----
public static function get_order_tokens( $order_id ) {
⋮----
$token_ids = $order->get_payment_tokens();
⋮----
public static function get( $token_id, $token_result = null ) {
⋮----
$token_result = $data_store->get_token_by_id( $token_id );
⋮----
$token_class = self::get_token_classname( $token_result->type );
⋮----
... (26 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-post-data.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\OrderInternalStatus;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer;
use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore as ProductAttributesLookupDataStore;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class WC_Post_Data {
⋮----
private static $editing_term = null;
⋮----
public static function init() {
⋮----
public static function variation_post_link( $permalink, $post ) {
⋮----
if ( $variation && $variation->get_parent_id() ) {
return $variation->get_permalink();
⋮----
public static function do_deferred_product_sync() {
⋮----
self::deferred_product_sync( $product_id );
⋮----
public static function deferred_product_sync( $product_id ) {
⋮----
$product->sync( $product );
⋮----
public static function transition_post_status( $new_status, $old_status, $post ) {
⋮----
... (175 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-post-types.php">
use Automattic\WooCommerce\Enums\OrderInternalStatus;
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
⋮----
class WC_Post_Types {
⋮----
public static function init() {
⋮----
self::queue_rewrite_rules_on_shop_page_save( $post_id, $post );
⋮----
public static function register_taxonomies() {
⋮----
public static function register_post_types() {
⋮----
$theme_unavailable = self::wp_cli_skips_active_theme() || wp_installing();
⋮----
if ( self::should_register_product_archive( $theme_support, $theme_unavailable ) ) {
⋮----
private static function should_register_product_archive( bool $theme_support, bool $theme_unavailable ): bool {
⋮----
private static function wp_cli_skips_active_theme(): bool {
⋮----
$skipped_themes = $get_wp_cli_config( 'skip-themes' );
⋮----
public static function updated_term_messages( $messages ) {
⋮----
/* translators: %s: taxonomy label */
⋮----
public static function register_post_status() {
⋮----
public static function maybe_flush_rewrite_rules() {
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-privacy-background-process.php">
class WC_Privacy_Background_Process extends WC_Background_Process {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
protected function task( $item ) {
⋮----
$process_count = WC_Privacy::trash_pending_orders( $process_limit );
⋮----
$process_count = WC_Privacy::trash_failed_orders( $process_limit );
⋮----
$process_count = WC_Privacy::trash_cancelled_orders( $process_limit );
⋮----
$process_count = WC_Privacy::anonymize_refunded_orders( $process_limit );
⋮----
$process_count = WC_Privacy::anonymize_completed_orders( $process_limit );
⋮----
$process_count = WC_Privacy::delete_inactive_accounts( $process_limit );
</file>

<file path="plugins/woocommerce/includes/class-wc-privacy-erasers.php">
class WC_Privacy_Erasers {
⋮----
public static function customer_data_eraser( $email_address, $page ) {
⋮----
$customer->save();
⋮----
public static function order_data_eraser( $email_address, $page ) {
⋮----
self::remove_order_personal_data( $order );
⋮----
$response['messages'][]    = sprintf( __( 'Removed personal data from order %s.', 'woocommerce' ), $order->get_order_number() );
⋮----
$response['messages'][]     = sprintf( __( 'Personal data within order %s has been retained.', 'woocommerce' ), $order->get_order_number() );
⋮----
public static function download_data_eraser( $email_address, $page ) {
⋮----
$customer_download_data_store = WC_Data_Store::load( 'customer-download' );
⋮----
$result = $customer_download_data_store->delete_by_user_id( (int) $user->ID );
⋮----
$result = $customer_download_data_store->delete_by_user_email( $email_address );
⋮----
public static function remove_order_personal_data( $order ) {
⋮----
/**
				 * Expose a way to control the anonymized value of a prop via 3rd party code.
				 *
				 * @since 3.4.0
				 * @param string   $anon_value Value of this prop after anonymization.
				 * @param string   $prop Name of the prop being removed.
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-privacy-exporters.php">
class WC_Privacy_Exporters {
⋮----
public static function customer_data_exporter( $email_address ) {
⋮----
$customer_personal_data = self::get_customer_personal_data( $user );
⋮----
public static function order_data_exporter( $email_address, $page ) {
⋮----
'item_id'           => 'order-' . $order->get_id(),
'data'              => self::get_order_personal_data( $order ),
⋮----
public static function download_data_exporter( $email_address, $page ) {
⋮----
$customer_download_data_store     = WC_Data_Store::load( 'customer-download' );
$customer_download_log_data_store = WC_Data_Store::load( 'customer-download-log' );
$downloads                        = $customer_download_data_store->get_downloads( $downloads_query );
⋮----
'item_id'           => 'download-' . $download->get_id(),
'data'              => self::get_download_personal_data( $download ),
⋮----
$download_logs = $customer_download_log_data_store->get_download_logs_for_permission( $download->get_id() );
⋮----
'item_id'           => 'download-log-' . $download_log->get_id(),
⋮----
'value' => $download_log->get_permission_id(),
⋮----
'value' => $download_log->get_timestamp(),
⋮----
'value' => $download_log->get_user_ip_address(),
⋮----
... (37 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-privacy.php">
use Automattic\WooCommerce\Enums\OrderInternalStatus;
⋮----
class WC_Privacy extends WC_Abstract_Privacy {
⋮----
protected static $background_process;
⋮----
public function __construct() {
parent::__construct();
⋮----
public function register_erasers_exporters() {
⋮----
$this->add_exporter( 'woocommerce-customer-data', __( 'WooCommerce Customer Data', 'woocommerce' ), array( 'WC_Privacy_Exporters', 'customer_data_exporter' ) );
$this->add_exporter( 'woocommerce-customer-orders', __( 'WooCommerce Customer Orders', 'woocommerce' ), array( 'WC_Privacy_Exporters', 'order_data_exporter' ) );
$this->add_exporter( 'woocommerce-customer-downloads', __( 'WooCommerce Customer Downloads', 'woocommerce' ), array( 'WC_Privacy_Exporters', 'download_data_exporter' ) );
$this->add_exporter( 'woocommerce-customer-tokens', __( 'WooCommerce Customer Payment Tokens', 'woocommerce' ), array( 'WC_Privacy_Exporters', 'customer_tokens_exporter' ) );
⋮----
$this->add_eraser( 'woocommerce-customer-data', __( 'WooCommerce Customer Data', 'woocommerce' ), array( 'WC_Privacy_Erasers', 'customer_data_eraser' ) );
$this->add_eraser( 'woocommerce-customer-orders', __( 'WooCommerce Customer Orders', 'woocommerce' ), array( 'WC_Privacy_Erasers', 'order_data_eraser' ) );
$this->add_eraser( 'woocommerce-customer-downloads', __( 'WooCommerce Customer Downloads', 'woocommerce' ), array( 'WC_Privacy_Erasers', 'download_data_eraser' ) );
$this->add_eraser( 'woocommerce-customer-tokens', __( 'WooCommerce Customer Payment Tokens', 'woocommerce' ), array( 'WC_Privacy_Erasers', 'customer_tokens_eraser' ) );
⋮----
public function get_privacy_message() {
⋮----
public function queue_cleanup_personal_data() {
self::$background_process->push_to_queue( array( 'task' => 'trash_pending_orders' ) );
self::$background_process->push_to_queue( array( 'task' => 'trash_failed_orders' ) );
self::$background_process->push_to_queue( array( 'task' => 'trash_cancelled_orders' ) );
self::$background_process->push_to_queue( array( 'task' => 'anonymize_refunded_orders' ) );
self::$background_process->push_to_queue( array( 'task' => 'anonymize_completed_orders' ) );
self::$background_process->push_to_queue( array( 'task' => 'delete_inactive_accounts' ) );
... (38 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-product-attribute.php">
class WC_Product_Attribute implements ArrayAccess {
⋮----
protected $data = array(
⋮----
protected $extra_data = array();
⋮----
public function is_taxonomy() {
return 0 < $this->get_id();
⋮----
public function get_taxonomy() {
return $this->is_taxonomy() ? $this->get_name() : '';
⋮----
/**
	 * Get taxonomy object.
	 *
	 * Returns null when the attribute is not a taxonomy, or when its global attribute is no longer loaded, for example right after it is deleted.
	 *
	 * @return array|null
	 */
public function get_taxonomy_object() {
⋮----
return $this->is_taxonomy() && isset( $wc_product_attributes[ $this->get_name() ] ) ? $wc_product_attributes[ $this->get_name() ] : null;
⋮----
/**
	 * Gets terms from the stored options.
	 *
	 * Returns null when the attribute is not a taxonomy, or when its taxonomy is not registered, for example right after the attribute is deleted.
	 *
	 * @return array|null
	 */
... (100 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-product-download.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register as Download_Directories;
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
use Automattic\WooCommerce\Internal\Utilities\URL;
⋮----
class WC_Product_Download implements ArrayAccess {
⋮----
protected $data = array(
⋮----
protected $extra_data = array();
⋮----
public function get_data() {
⋮----
public function get_allowed_mime_types() {
⋮----
public function get_type_of_file_path( $file_path = '' ) {
$file_path  = $file_path ? $file_path : $this->get_file();
⋮----
public function get_file_type() {
$type = wp_check_filetype( strtok( $this->get_file(), '?' ), $this->get_allowed_mime_types() );
⋮----
public function get_file_extension() {
$parsed_url = wp_parse_url( $this->get_file(), PHP_URL_PATH );
⋮----
public function check_is_valid( bool $auto_add_to_approved_directory_list = true ) {
$download_file = $this->get_file();
⋮----
if ( ! $this->is_allowed_filetype() ) {
⋮----
'<code>' . implode( ', ', array_keys( $this->get_allowed_mime_types() ) ) . '</code>'
... (77 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-product-external.php">
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class WC_Product_External extends WC_Product {
⋮----
protected $extra_data = array(
⋮----
/**
	 * Get internal type.
	 *
	 * @return string
	 */
public function get_type() {
⋮----
/*
	|--------------------------------------------------------------------------
	| Getters
	|--------------------------------------------------------------------------
	|
	| Methods for getting data from the product object.
	*/
⋮----
/**
	 * Get product url.
	 *
	 * @param  string $context What the value is for. Valid values are 'view' and 'edit'.
	 * @return string
	 */
public function get_product_url( $context = 'view' ) {
return esc_url_raw( $this->get_prop( 'product_url', $context ) );
... (40 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-product-factory.php">
use Automattic\WooCommerce\Internal\Caches\ProductCache;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class WC_Product_Factory {
⋮----
public function get_product( $product_id = false, $deprecated = array() ) {
$product_id = (int) $this->get_product_id( $product_id );
⋮----
$use_product_cache = \Automattic\WooCommerce\Utilities\FeaturesUtil::feature_is_enabled( 'product_instance_caching' );
⋮----
$product_cache = wc_get_container()->get( ProductCache::class );
$product       = $product_cache->get( $product_id );
⋮----
$product_type = self::get_product_type( $product_id );
⋮----
$product_type = self::get_classname_from_product_type( $deprecated['product_type'] );
⋮----
$classname = self::get_product_classname( $product_id, $product_type );
⋮----
$product = new $classname( $product_id, $deprecated );
⋮----
$product_cache->set( $product );
⋮----
public static function get_product_classname( $product_id, $product_type ) {
⋮----
$classname = apply_filters( 'woocommerce_product_class', self::get_classname_from_product_type( $product_type ), $product_type, ProductType::VARIATION === $product_type ? 'product_variation' : 'product', $product_id );
⋮----
public static function get_product_type( $product_id ) {
⋮----
return WC_Data_Store::load( 'product' )->get_product_type( $product_id );
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-product-grouped.php">
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
⋮----
class WC_Product_Grouped extends WC_Product {
⋮----
protected $extra_data = array(
⋮----
public function get_type() {
⋮----
public function add_to_cart_text() {
⋮----
public function add_to_cart_description() {
⋮----
return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( __( 'View products in the &ldquo;%s&rdquo; group', 'woocommerce' ), $this->get_name() ), $this );
⋮----
public function is_on_sale( $context = 'view' ) {
$children = $this->get_primed_visible_children( $context );
⋮----
if ( $child->is_purchasable() && ! $child->has_child() && $child->is_on_sale() ) {
⋮----
public function is_purchasable() {
⋮----
public function get_price_html( $price = '' ) {
⋮----
$children         = $this->get_primed_visible_children();
⋮----
if ( '' !== $child->get_price() ) {
⋮----
$price = apply_filters( 'woocommerce_grouped_price_html', $price . $this->get_price_suffix(), $this, $child_prices );
⋮----
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-product-query.php">
use Automattic\WooCommerce\Enums\ProductStatus;
⋮----
class WC_Product_Query extends WC_Object_Query {
⋮----
protected function get_default_query_vars() {
⋮----
parent::get_default_query_vars(),
⋮----
/**
	 * Get products matching the current query vars.
	 *
	 * @return array|object of WC_Product objects
	 */
public function get_products() {
$args    = apply_filters( 'woocommerce_product_object_query_args', $this->get_query_vars() );
$results = WC_Data_Store::load( 'product' )->query( $args );
</file>

<file path="plugins/woocommerce/includes/class-wc-product-simple.php">
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class WC_Product_Simple extends WC_Product {
⋮----
public function __construct( $product = 0 ) {
⋮----
parent::__construct( $product );
⋮----
public function get_type() {
⋮----
public function add_to_cart_url() {
$url = $this->is_purchasable() && $this->is_in_stock() ? remove_query_arg(
⋮----
'add-to-cart' => $this->get_id(),
⋮----
( function_exists( 'is_feed' ) && is_feed() ) || ( function_exists( 'is_404' ) && is_404() ) ? $this->get_permalink() : false
⋮----
) : $this->get_permalink();
⋮----
public function add_to_cart_text() {
$text = $this->is_purchasable() && $this->is_in_stock() ? __( 'Add to cart', 'woocommerce' ) : __( 'Read more', 'woocommerce' );
⋮----
public function add_to_cart_description() {
⋮----
$text = $this->is_purchasable() && $this->is_in_stock() ? __( 'Add to cart: &ldquo;%s&rdquo;', 'woocommerce' ) : __( 'Read more about &ldquo;%s&rdquo;', 'woocommerce' );
⋮----
return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( $text, $this->get_name() ), $this );
⋮----
public function add_to_cart_success_message() {
⋮----
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-product-variable.php">
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
⋮----
class WC_Product_Variable extends WC_Product {
⋮----
protected $children = null;
⋮----
protected $visible_children = null;
⋮----
protected $variation_attributes = null;
⋮----
private array $variation_prices = array(
⋮----
public function get_type() {
⋮----
public function add_to_cart_aria_describedby() {
⋮----
return apply_filters( 'woocommerce_product_add_to_cart_aria_describedby', $this->is_purchasable() ? __( 'This product has multiple variants. The options may be chosen on the product page', 'woocommerce' ) : '', $this );
⋮----
/**
	 * Get the add to cart button text.
	 *
	 * @return string
	 */
public function add_to_cart_text() {
return apply_filters( 'woocommerce_product_add_to_cart_text', $this->is_purchasable() ? __( 'Select options', 'woocommerce' ) : __( 'Read more', 'woocommerce' ), $this );
⋮----
public function add_to_cart_description() {
⋮----
... (234 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-product-variation.php">
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\CatalogVisibility;
⋮----
class WC_Product_Variation extends WC_Product_Simple {
⋮----
protected $post_type = 'product_variation';
⋮----
protected $parent_data = array(
⋮----
/**
	 * Override the default constructor to set custom defaults.
	 *
	 * @param int|WC_Product|object $product Product to init.
	 */
public function __construct( $product = 0 ) {
⋮----
parent::__construct( $product );
⋮----
protected function get_hook_prefix() {
⋮----
public function get_type() {
⋮----
public function get_stock_managed_by_id() {
return 'parent' === $this->get_manage_stock() ? $this->get_parent_id() : $this->get_id();
⋮----
public function get_title() {
⋮----
public function get_formatted_name() {
if ( $this->get_sku() ) {
... (181 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-query.php">
use Automattic\WooCommerce\Internal\ProductAttributesLookup\Filterer;
use Automattic\WooCommerce\Internal\ProductFilters\Params;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
⋮----
class WC_Query {
⋮----
public $query_vars = array();
⋮----
private static $product_query;
⋮----
private static $chosen_attributes;
⋮----
private $filterer;
⋮----
public function __construct() {
$this->filterer = wc_get_container()->get( Filterer::class );
⋮----
$this->init_query_vars();
⋮----
public static function reset_chosen_attributes() {
⋮----
public function get_errors() {
⋮----
public function init_query_vars() {
⋮----
public function get_endpoint_title( $endpoint, $action = '' ) {
⋮----
$title = ( $order ) ? sprintf( __( 'Order #%s', 'woocommerce' ), $order->get_order_number() ) : '';
... (231 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-rate-limiter.php">
class WC_Rate_Limiter {
⋮----
public static function init() {
⋮----
public static function storage_id( $action_id ) {
⋮----
protected static function get_cache_key( $action_id ) {
return WC_Cache_Helper::get_cache_prefix( 'rate_limit' . $action_id );
⋮----
protected static function get_cached( $action_id ) {
return wp_cache_get( self::get_cache_key( $action_id ), self::CACHE_GROUP );
⋮----
protected static function set_cache( $action_id, $expiry ) {
return wp_cache_set( self::get_cache_key( $action_id ), $expiry, self::CACHE_GROUP );
⋮----
public static function retried_too_soon( $action_id ) {
⋮----
$next_try_allowed_at = self::get_cached( $action_id );
⋮----
$next_try_allowed_at = $wpdb->get_var(
$wpdb->prepare(
⋮----
self::set_cache( $action_id, $next_try_allowed_at );
⋮----
public static function set_rate_limit( $action_id, $delay ) {
⋮----
$result = $wpdb->replace(
⋮----
public static function cleanup() {
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-regenerate-images-request.php">
class WC_Regenerate_Images_Request extends WC_Background_Process {
⋮----
protected $attachment_id = 0;
⋮----
public function __construct() {
⋮----
Imagick::setResourceLimit( Imagick::RESOURCETYPE_THREAD, 1 );
⋮----
Imagick::setResourceLimit( 6, 1 );
⋮----
parent::__construct();
⋮----
public function is_running() {
return $this->is_queue_empty();
⋮----
protected function batch_limit_exceeded() {
⋮----
protected function is_regeneratable( $attachment ) {
⋮----
protected function task( $item ) {
⋮----
if ( ! $attachment || 'attachment' !== $attachment->post_type || ! $this->is_regeneratable( $attachment ) ) {
⋮----
$log->info(
⋮----
public function filter_image_sizes_to_only_missing_thumbnails( $sizes, $metadata, $attachment_id = null ) {
⋮----
public function adjust_intermediate_image_sizes( $sizes ) {
⋮----
protected function complete() {
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-regenerate-images.php">
class WC_Regenerate_Images {
⋮----
protected static $background_process;
⋮----
protected static $regenerate_size;
⋮----
public static function init() {
⋮----
if ( method_exists( 'Jetpack', 'is_module_active' ) && Jetpack::is_module_active( 'photon' ) ) {
⋮----
public static function filter_image_get_intermediate_size( $data, $attachment_id, $size ) {
⋮----
if ( ! self::image_size_matches_settings( $data, $size ) ) {
⋮----
public static function add_uncropped_metadata( $meta_data ) {
⋮----
protected static function image_size_matches_settings( $image, $size ) {
⋮----
public static function is_regeneration_in_progress() {
⋮----
return self::$background_process && ! self::$background_process->is_running();
⋮----
public static function regenerating_notice() {
⋮----
public static function dismiss_regenerating_notice() {
⋮----
self::$background_process->kill_process();
⋮----
$log->info(
⋮----
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-register-wp-admin-settings.php">
class WC_Register_WP_Admin_Settings {
⋮----
protected $object;
⋮----
protected $type;
⋮----
public function __construct( $object, $type ) {
⋮----
$this->register();
⋮----
public function register() {
⋮----
add_filter( 'woocommerce_settings-' . $page->get_id(), array( $this, 'register_page_settings' ) );
⋮----
public function register_email_group( $groups ) {
⋮----
public function register_email_settings( $settings ) {
⋮----
$setting['option_key'] = array( $this->object->get_option_key(), $id );
$new_setting           = $this->register_setting( $setting );
⋮----
public function register_page_group( $groups ) {
⋮----
'id'    => $this->object->get_id(),
'label' => $this->object->get_label(),
⋮----
public function register_page_settings( $settings ) {
⋮----
$sections = $this->object->get_sections();
⋮----
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-rest-authentication.php">
class WC_REST_Authentication {
⋮----
protected $error = null;
⋮----
protected $user = null;
⋮----
protected $auth_method = '';
⋮----
/**
	 * Provides access to the global WC_REST_Authentication instance.
	 *
	 * @internal
	 * @return self
	 */
public static function instance(): self {
⋮----
/**
	 * Initialize authentication actions.
	 */
public function __construct() {
⋮----
protected function is_request_to_rest_api() {
⋮----
$resolved_route = $this->resolved_route();
$is_wc_route    = $this->is_wc_namespace( $this->route_from_request_uri() )
|| ( null !== $resolved_route && $this->is_wc_namespace( $resolved_route ) );
⋮----
private function is_wc_namespace( string $route ): bool {
⋮----
private function resolved_route(): ?string {
... (149 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-rest-exception.php">
class WC_REST_Exception extends WC_Data_Exception {}
</file>

<file path="plugins/woocommerce/includes/class-wc-session-handler.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Utilities\StringUtil;
use Automattic\WooCommerce\StoreApi\Utilities\CartTokenUtils;
⋮----
class WC_Session_Handler extends WC_Session {
⋮----
protected $_cookie = ''; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
⋮----
/**
	 * Stores session expiry.
	 *
	 * @var int session due to expire timestamp
	 */
protected $_session_expiring = 0; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
⋮----
/**
	 * Stores session due to expire timestamp.
	 *
	 * @var int session expiration timestamp
	 */
protected $_session_expiration = 0; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
⋮----
/**
	 * True when the cookie exists.
	 *
	 * @var bool Based on whether a cookie exists.
	 */
protected $_has_cookie = false; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
⋮----
... (223 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-shipping-rate.php">
use Automattic\WooCommerce\Enums\ProductTaxStatus;
⋮----
class WC_Shipping_Rate implements JsonSerializable {
⋮----
protected $data = array(
⋮----
/**
	 * Stores meta data for this rate.
	 *
	 * @var array
	 */
protected $meta_data = array();
⋮----
/**
	 * Constructor.
	 *
	 * @param string  $id            Shipping rate ID.
	 * @param string  $label         Shipping rate label.
	 * @param integer $cost          Cost.
	 * @param array   $taxes         Taxes applied to shipping rate.
	 * @param string  $method_id     Shipping method ID.
	 * @param int     $instance_id   Shipping instance ID.
	 * @param string  $tax_status    Tax status.
	 * @param string  $description   Shipping rate description.
	 * @param string  $delivery_time Shipping rate delivery time.
	 */
public function __construct( $id = '', $label = '', $cost = 0, $taxes = array(), $method_id = '', $instance_id = 0, $tax_status = ProductTaxStatus::TAXABLE, $description = '', $delivery_time = '' ) {
$this->set_id( $id );
$this->set_label( $label );
$this->set_cost( $cost );
... (85 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-shipping-zone.php">
class WC_Shipping_Zone extends WC_Legacy_Shipping_Zone {
⋮----
protected $id = null;
⋮----
protected $object_type = 'shipping_zone';
⋮----
protected $data = array(
⋮----
public function __construct( $zone = null ) {
⋮----
$this->set_id( $zone );
⋮----
$this->set_id( $zone->zone_id );
⋮----
$this->set_id( 0 );
⋮----
$this->set_object_read( true );
⋮----
$this->data_store = WC_Data_Store::load( 'shipping-zone' );
if ( false === $this->get_object_read() ) {
$this->data_store->read( $this );
⋮----
public function get_zone_name( $context = 'view' ) {
return $this->get_prop( 'zone_name', $context );
⋮----
public function get_zone_order( $context = 'view' ) {
return $this->get_prop( 'zone_order', $context );
⋮----
public function get_zone_locations( $context = 'view' ) {
return $this->get_prop( 'zone_locations', $context );
... (91 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-shipping-zones.php">
class WC_Shipping_Zones {
⋮----
public static function get_zones( $context = 'admin' ) {
$zone_objects = self::get_shipping_zones();
⋮----
$zones[ $zone_object->get_id() ]                            = $zone_object->get_data();
$zones[ $zone_object->get_id() ]['zone_id']                 = $zone_object->get_id();
$zones[ $zone_object->get_id() ]['formatted_zone_location'] = $zone_object->get_formatted_location();
$zones[ $zone_object->get_id() ]['shipping_methods']        = $zone_object->get_shipping_methods( false, $context );
⋮----
public static function get_zones_with_order_conflict_warnings( $context = 'admin' ) {
$zones = self::get_zones( $context );
⋮----
return self::add_zone_order_conflict_warnings( $zones );
⋮----
private static function add_zone_order_conflict_warnings( $zones ) {
⋮----
$shadowing_zone = self::get_shadowing_zone( $zone, $higher_priority_zones );
⋮----
private static function get_shadowing_zone( $zone, $higher_priority_zones ) {
⋮----
if ( self::zone_covers_zone( $higher_priority_zone, $zone ) ) {
⋮----
private static function zone_covers_zone( $possible_broader_zone, $zone ) {
if ( self::zone_has_postcode_locations( $possible_broader_zone ) ) {
⋮----
self::zone_has_unsupported_non_postcode_locations( $possible_broader_zone ) ||
self::zone_has_unsupported_non_postcode_locations( $zone )
⋮----
$broader_locations = self::get_zone_locations_by_type( $possible_broader_zone, array( 'continent', 'country', 'state' ) );
... (68 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-shipping.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\StoreApi\Utilities\LocalPickupUtils;
⋮----
class WC_Shipping {
⋮----
public $enabled = false;
⋮----
public $shipping_methods = null;
⋮----
public $shipping_classes = array();
⋮----
public $packages = array();
⋮----
protected static $_instance = null;
⋮----
public static function instance() {
⋮----
public function __clone() {
⋮----
public function __wakeup() {
⋮----
public function __get( $name ) {
⋮----
return WC()->cart->get_shipping_total();
⋮----
return WC()->cart->get_shipping_taxes();
⋮----
public function __construct() {
⋮----
$this->init();
... (69 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-shortcodes.php">
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class WC_Shortcodes {
⋮----
public static function init() {
⋮----
public static function shortcode_wrapper(
⋮----
public static function cart() {
return is_null( WC()->cart ) ? '' : self::shortcode_wrapper( array( 'WC_Shortcode_Cart', 'output' ) );
⋮----
public static function checkout( $atts ) {
return self::shortcode_wrapper( array( 'WC_Shortcode_Checkout', 'output' ), $atts );
⋮----
public static function order_tracking( $atts ) {
return self::shortcode_wrapper( array( 'WC_Shortcode_Order_Tracking', 'output' ), $atts );
⋮----
public static function my_account( $atts ) {
return self::shortcode_wrapper( array( 'WC_Shortcode_My_Account', 'output' ), $atts );
⋮----
public static function product_category( $atts ) {
⋮----
return $shortcode->get_content();
⋮----
public static function product_categories( $atts ) {
⋮----
public static function recent_products( $atts ) {
⋮----
public static function products( $atts ) {
... (70 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-structured-data.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
⋮----
class WC_Structured_Data {
⋮----
private $_data = array();
⋮----
public function __construct() {
⋮----
public function set_data( $data, $reset = false ) {
⋮----
public function get_data() {
⋮----
public function get_structured_data( $types ) {
⋮----
foreach ( $this->get_data() as $value ) {
⋮----
protected function get_data_type_for_page() {
⋮----
public function output_email_structured_data( $order, $sent_to_admin = false, $plain_text = false ) {
⋮----
$this->output_structured_data();
⋮----
public function output_structured_data() {
$types = $this->get_data_type_for_page();
$data  = $this->get_structured_data( $types );
⋮----
... (194 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-tax.php">
use Automattic\WooCommerce\Enums\DefaultCustomerAddress;
use Automattic\WooCommerce\Enums\TaxBasedOn;
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
class WC_Tax {
⋮----
public static $precision;
⋮----
public static $round_at_subtotal = false;
⋮----
public static function init() {
⋮----
public static function maybe_remove_tax_class_rates( $old_value, $value ) {
⋮----
$existing_tax_classes = self::get_tax_classes();
⋮----
self::delete_tax_class_by( 'name', $name );
⋮----
public static function calc_tax( $price, $rates, $price_includes_tax = false, $deprecated = false ) {
⋮----
$taxes = self::calc_inclusive_tax( $price, $rates );
⋮----
$taxes = self::calc_exclusive_tax( $price, $rates );
⋮----
public static function calc_shipping_tax( $price, $rates ) {
⋮----
public static function round( $in ) {
return apply_filters( 'woocommerce_tax_round', NumberUtil::round( $in, wc_get_rounding_precision() ), $in );
⋮----
public static function calc_inclusive_tax( $price, $rates ) {
... (274 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-template-loader.php">
class WC_Template_Loader {
⋮----
private static $shop_page_id = 0;
⋮----
private static $in_content_filter = false;
⋮----
private static $theme_support = false;
⋮----
public static function init() {
⋮----
self::add_support_for_product_page_gallery();
⋮----
public static function template_loader( $template ) {
⋮----
$default_file = self::get_template_loader_default_file();
⋮----
$search_files = self::get_template_loader_files( $default_file );
⋮----
$template    = WC()->plugin_path() . '/templates/' . $cs_template;
⋮----
$template = WC()->plugin_path() . '/templates/' . $default_file;
⋮----
private static function taxonomy_has_block_template( $taxonomy ): bool {
⋮----
return self::has_block_template( $template_name );
⋮----
private static function has_block_template( $template_name ) {
⋮----
$has_template = WP_Block_Templates_Registry::get_instance()->is_registered( 'woocommerce//' . $template_name );
⋮----
... (112 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-tracker.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Internal\Admin\EmailImprovements\EmailImprovements;
use Automattic\WooCommerce\Internal\CLI\Migrator\Core\MigratorTracker;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\Internal\Utilities\BlocksUtil;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use Automattic\WooCommerce\Utilities\{ FeaturesUtil, OrderUtil, PluginUtil };
⋮----
class WC_Tracker {
⋮----
private static $api_url = 'https://tracking.woocommerce.com/v1/';
⋮----
public static function init() {
⋮----
public static function send_tracking_data( $override = false ) {
⋮----
if ( Constants::is_true( 'DOING_AJAX' ) ) {
⋮----
$last_send = self::get_last_send_time();
⋮----
$last_attempt = max( (int) self::get_last_send_time(), (int) get_option( 'woocommerce_tracker_last_attempt', 0 ) );
⋮----
self::finish_snapshot();
wc_get_logger()->warning(
⋮----
$body = wp_json_encode( self::get_tracking_data() );
... (457 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-validation.php">
class WC_Validation {
⋮----
public static function is_email( $email ) {
⋮----
public static function is_phone_format( $phone ): bool {
⋮----
/**
	 * Validates a phone number using a regular expression.
	 *
	 * @param  string      $phone   Phone number to validate.
	 * @param  string|null $country The country code the phone is being validated for, or null if unknown.
	 * @return bool
	 */
public static function is_phone( $phone, $country = null ) {
$valid = self::is_phone_format( $phone );
⋮----
/**
		 * Filters whether a phone number is considered valid.
		 *
		 * @since 11.0.0
		 *
		 * @param bool        $valid   Whether the phone number passed the default validation.
		 * @param string      $phone   The phone number being validated.
		 * @param string|null $country The country code the phone is being validated for, or null if unknown.
		 */
⋮----
public static function is_postcode( $postcode, $country ) {
⋮----
$valid = Automattic\WooCommerce\Internal\Utilities\PostcodeValidation::validate( (string) $postcode, (string) $country );
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-wc-webhook.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Utilities\NumberUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Utilities\RestApiUtil;
use Automattic\WooCommerce\Utilities\LoggingUtil;
⋮----
class WC_Webhook extends WC_Legacy_Webhook {
⋮----
protected $processed = array();
⋮----
protected $data = array(
⋮----
public function __construct( $data = 0 ) {
parent::__construct( $data );
⋮----
$this->set_id( absint( $data->get_id() ) );
⋮----
$this->set_id( $data );
⋮----
$this->data_store = WC_Data_Store::load( 'webhook' );
⋮----
if ( $this->get_id() ) {
⋮----
$this->data_store->read( $this );
⋮----
$this->set_id( 0 );
$this->set_object_read( true );
⋮----
public function enqueue() {
... (249 lines truncated)
</file>

<file path="plugins/woocommerce/includes/class-woocommerce.php">
use Automattic\WooCommerce\Internal\AddressProvider\AddressProviderController;
use Automattic\WooCommerce\Internal\AssignDefaultCategory;
use Automattic\WooCommerce\Internal\TermCount;
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessingController;
use Automattic\WooCommerce\Internal\Caches\ProductCacheController;
use Automattic\WooCommerce\Internal\Caches\ProductTermCacheInvalidator;
use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonAdminBarBadge;
use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonCacheInvalidator;
use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonRequestHandler;
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Automattic\WooCommerce\Internal\DownloadPermissionsAdjuster;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\LegacyAssets\LegacySelect2UsageTracker;
use Automattic\WooCommerce\Internal\MCP\MCPAdapterProvider;
use Automattic\WooCommerce\Internal\Abilities\AbilitiesRegistry;
use Automattic\WooCommerce\Internal\ProductAttributes\VisualAttributeTermAdmin;
use Automattic\WooCommerce\Internal\ProductAttributesLookup\DataRegenerator;
use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore;
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register as ProductDownloadDirectories;
use Automattic\WooCommerce\Internal\ProductImage\MatchImageBySKU;
use Automattic\WooCommerce\Internal\RestockRefundedItemsAdjuster;
use Automattic\WooCommerce\Internal\Settings\OptionSanitizer;
use Automattic\WooCommerce\Internal\Utilities\LegacyRestApiStub;
use Automattic\WooCommerce\Internal\Utilities\WebhookUtil;
use Automattic\WooCommerce\Internal\Admin\EmailImprovements\EmailImprovements;
use Automattic\WooCommerce\Internal\Email\DeferredEmailQueue;
use Automattic\WooCommerce\Internal\Email\EmailLogger;
use Automattic\WooCommerce\Internal\Admin\Marketplace;
use Automattic\WooCommerce\Internal\Admin\OrderMilestoneEasterEgg;
use Automattic\WooCommerce\Proxies\LegacyProxy;
... (371 lines truncated)
</file>

<file path="plugins/woocommerce/includes/README.md">
# WooCommerce `includes` files

This directory contains WooCommerce legacy code. Ideally, the code in this folder should only get the minimum required changes for bug fixing, and any new code should go in [the `src` directory](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/src/README.md) instead.

This applies especially to standalone (global) functions: **new functions must not be added to `includes` (nor to `src`)**: all new logic belongs in classes. This rule is enforced by a CI check (`bin/check-new-functions.php`) that fails any pull request adding a new function in either directory. The only exceptions are the database update files (`wc-update-functions.php` and `react-admin/wc-admin-update-functions.php`), whose routines have to be global functions because `WC_Install::$db_updates` registers and invokes them by name; those two files are excluded from the check.

Adding a new public or protected method to an existing class in `includes/` is also discouraged, but (unlike a new function) it may be acceptable in special, well-justified cases (for example, as part of a bug fix).


## A note on `@internal` annotations

Some classes, methods and functions in this folder have an `@internal` annotation in their documentation comment block. This means that the code entity is intended for internal usage of WooCommerce core only, and **must not** be used in extensions. Backwards compatibility for these code entities is not guaranteed: they could be renamed, modified (in behavior, return value or arguments accepted) or deleted.


## Interacting with the `src` folder

Whenever you need to get an instance of a class from the `src` directory, please don't instantiate it directly, but instead use [the container](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/src/README.md#the-container). To get an instance of the container itself you can use the `wc_get_container` function, for example:


```php
$container = wc_get_container();
$service = $container->get( \Automattic\WooCommerce\TheNamespace\TheService::class );
$service->do_something();
```

The exception to this rule might be data-only classes that could be created the old way (using a plain `new` statement); but in general, all classes in the `src` directory are registered in the container and should be resolved using it.


## Adding new actions and filters

... (15 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-account-functions.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\PaymentGatewayFeature;
⋮----
function wc_lostpassword_url( $default_url = '' ) {
// Avoid loading too early.
⋮----
function wc_customer_edit_account_url() {
⋮----
function wc_edit_address_i18n( $id, $flip = false ) {
⋮----
function wc_get_account_menu_items() {
⋮----
foreach ( WC()->payment_gateways->get_available_payment_gateways() as $gateway ) {
if ( $gateway->supports( PaymentGatewayFeature::ADD_PAYMENT_METHOD ) || $gateway->supports( PaymentGatewayFeature::TOKENIZATION ) ) {
⋮----
function wc_is_current_account_menu_item( $endpoint ) {
⋮----
function wc_get_account_menu_item_classes( $endpoint ) {
⋮----
function wc_get_account_endpoint_url( $endpoint ) {
⋮----
function wc_get_account_orders_columns() {
⋮----
function wc_get_account_downloads_columns() {
⋮----
function wc_get_account_payment_methods_columns() {
⋮----
function wc_get_account_payment_methods_types() {
⋮----
function wc_get_account_orders_actions( $order ) {
... (48 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-attribute-functions.php">
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
function wc_get_text_attributes( $raw_attributes ) {
⋮----
function wc_get_text_attributes_filter_callback( $value ) {
⋮----
/**
 * Implode an array of attributes using WC_DELIMITER.
 *
 * @since  3.0.0
 * @param  array $attributes Attributes list.
 * @return string
 */
function wc_implode_text_attributes( $attributes ) {
⋮----
/**
 * Get attribute taxonomies.
 *
 * @return array of objects, @since 3.6.0 these are also indexed by ID.
 */
function wc_get_attribute_taxonomies() {
$prefix      = WC_Cache_Helper::get_cache_prefix( 'woocommerce-attributes' );
⋮----
$raw_attribute_taxonomies = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_name != '' ORDER BY attribute_name ASC;" );
⋮----
function wc_get_attribute_taxonomy_ids() {
⋮----
function wc_get_attribute_taxonomy_labels() {
⋮----
... (90 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-brands-functions.php">
function wc_get_brand_thumbnail_url( $brand_id, $size = 'full' ) {
⋮----
/**
 * Helper function :: wc_get_brand_thumbnail_image function.
 *
 * @since 9.4.0
 *
 * @param  object $brand Brand term.
 * @param  string $size  Thumbnail image size.
 * @return string
 */
function wc_get_brand_thumbnail_image( $brand, $size = '' ) {
⋮----
function wc_get_brands( $post_id = 0, $sep = ', ', $before = '', $after = '' ) {
⋮----
function get_brand_thumbnail_url( $brand_id, $size = 'full' ) {
⋮----
function get_brand_thumbnail_image( $brand, $size = '' ) {
⋮----
function get_brands( $post_id = 0, $sep = ', ', $before = '', $after = '' ) {
</file>

<file path="plugins/woocommerce/includes/wc-cart-functions.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\StoreApi\Utilities\LocalPickupUtils;
⋮----
function wc_protected_product_add_to_cart( $passed, $product_id ) {
⋮----
function wc_empty_cart() {
⋮----
WC()->cart->empty_cart( false );
⋮----
/**
 * Retrieves unvalidated referer from '_wp_http_referer' or HTTP referer.
 *
 * Do not use for redirects, use {@see wp_get_referer()} instead.
 *
 * @since 2.6.1
 * @return string|false Referer URL on success, false on failure.
 */
function wc_get_raw_referer() {
⋮----
function wc_add_to_cart_message( $products, $show_qty = false, $return = false ) {
⋮----
/**
		 * Filters the item name in quotes for the add to cart message.
		 *
		 * @since 2.6.1
		 * @param string $item_name_in_quotes The item name in quotes.
		 * @param int    $product_id The product ID.
... (114 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-conditional-functions.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
⋮----
function is_woocommerce() {
⋮----
function is_shop() {
⋮----
function is_product_taxonomy() {
⋮----
function is_product_category( $term = '' ) {
⋮----
function is_product_tag( $term = '' ) {
⋮----
function is_product() {
⋮----
function is_cart() {
⋮----
return apply_filters( 'woocommerce_is_cart', false ) || Constants::is_defined( 'WOOCOMMERCE_CART' ) || CartCheckoutUtils::is_cart_page();
⋮----
function is_checkout() {
⋮----
return apply_filters( 'woocommerce_is_checkout', false ) || Constants::is_defined( 'WOOCOMMERCE_CHECKOUT' ) || CartCheckoutUtils::is_checkout_page();
⋮----
function is_checkout_pay_page( bool $use_query_params = false ): bool {
⋮----
function is_wc_endpoint_url( $endpoint = false ) {
⋮----
$wc_endpoints = WC()->query->get_query_vars();
⋮----
function is_account_page() {
... (73 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-core-functions.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Enums\DefaultCustomerAddress;
use Automattic\WooCommerce\Utilities\NumberUtil;
use Automattic\WooCommerce\Internal\Logging\OrderLogsCleanupHelper;
⋮----
function wc_maybe_define_constant( $name, $value ) {
⋮----
function wc_create_order( $args = array() ) {
⋮----
$order->set_parent_id( absint( $args['parent'] ) );
⋮----
$order->set_status( $args['status'] );
⋮----
$order->set_customer_note( $args['customer_note'] );
⋮----
$order->set_customer_id( is_numeric( $args['customer_id'] ) ? absint( $args['customer_id'] ) : 0 );
⋮----
$order->set_created_via( sanitize_text_field( $args['created_via'] ) );
⋮----
$order->set_cart_hash( sanitize_text_field( $args['cart_hash'] ) );
⋮----
$order->set_currency( get_woocommerce_currency() );
$order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
$order->set_customer_ip_address( WC_Geolocation::get_ip_address() );
$order->set_customer_user_agent( wc_get_user_agent() );
⋮----
$order->save();
⋮----
return new WP_Error( 'error', $e->getMessage() );
... (370 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-coupon-functions.php">
use Automattic\WooCommerce\Utilities\StringUtil;
use Automattic\WooCommerce\Admin\API\Reports\Coupons\DataStore as CouponsDataStore;
⋮----
function wc_get_coupon_types() {
⋮----
function wc_get_coupon_type( $type = '' ) {
⋮----
/**
 * Coupon types that apply to individual products. Controls which validation rules will apply.
 *
 * @since  2.5.0
 * @return array
 */
function wc_get_product_coupon_types() {
⋮----
function wc_get_cart_coupon_types() {
⋮----
function wc_coupons_enabled() {
⋮----
function wc_is_same_coupon( $coupon_1, $coupon_2 ) {
⋮----
function wc_get_coupon_code_by_id( $id ) {
$data_store = WC_Data_Store::load( 'coupon' );
return empty( $id ) ? '' : (string) $data_store->get_code_by_id( $id );
⋮----
/**
 * Get coupon ID by code.
 *
 * @since 3.0.0
 * @param string $code    Coupon code.
... (26 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-deprecated-functions.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Logging\Settings;
use Automattic\WooCommerce\Utilities\LoggingUtil;
⋮----
function wc_do_deprecated_action( $tag, $args, $version, $replacement = null, $message = null ) {
⋮----
function wc_deprecated_function( $function, $version, $replacement = null ) {
⋮----
if ( wp_doing_ajax() || WC()->is_rest_api_request() ) {
⋮----
// @codingStandardsIgnoreEnd
⋮----
/**
 * Wrapper for deprecated hook so we can apply some extra logic.
 *
 * @since 3.3.0
 * @param string $hook        The hook that was used.
 * @param string $version     The version of WordPress that deprecated the hook.
 * @param string $replacement The hook that should have been used.
 * @param string $message     A message regarding the change.
 * @return void
 */
function wc_deprecated_hook( $hook, $version, $replacement = null, $message = null ) {
// @codingStandardsIgnoreStart
⋮----
/**
 * When catching an exception, this allows us to log it if unexpected.
 *
 * @since 3.3.0
 * @param Throwable $exception_object The exception (or error) object.
... (336 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-formatting-functions.php">
use Automattic\WooCommerce\Enums\WeightUnit;
use Automattic\WooCommerce\Internal\Settings\OptionSanitizer;
use Automattic\WooCommerce\Utilities\I18nUtil;
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
function wc_string_to_bool( $string ) {
⋮----
function wc_bool_to_string( $bool ) {
⋮----
function wc_string_to_array( $string, $delimiter = ',' ) {
⋮----
/**
 * Sanitize taxonomy names. Slug format (no spaces, lowercase).
 * Urldecode is used to reverse munging of UTF8 characters.
 *
 * @param string $taxonomy Taxonomy name.
 * @return string
 */
function wc_sanitize_taxonomy_name( $taxonomy ) {
⋮----
/**
 * Sanitize permalink values before insertion into DB.
 *
 * Cannot use wc_clean because it sometimes strips % chars and breaks the user's setting.
 *
 * @since  2.6.0
 * @param  string $value Permalink.
 * @return string
 */
function wc_sanitize_permalink( $value ) {
... (286 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-interactivity-api-functions.php">
use Automattic\WooCommerce\Blocks\SharedStores\ProductsStore;
⋮----
function wc_interactivity_api_load_product( string $consent_statement, int $product_id ): array {
return ProductsStore::load_product( $consent_statement, $product_id );
⋮----
function wc_interactivity_api_load_purchasable_child_products( string $consent_statement, int $parent_id ): array {
return ProductsStore::load_purchasable_child_products( $consent_statement, $parent_id );
⋮----
function wc_interactivity_api_load_variations( string $consent_statement, int $parent_id ): array {
return ProductsStore::load_variations( $consent_statement, $parent_id );
</file>

<file path="plugins/woocommerce/includes/wc-notice-functions.php">
function wc_notice_count( $notice_type = '' ) {
⋮----
$all_notices  = WC()->session->get( 'wc_notices', array() );
⋮----
function wc_has_notice( $message, $notice_type = 'success' ) {
⋮----
$notices = WC()->session->get( 'wc_notices', array() );
⋮----
function wc_add_notice( $message, $notice_type = 'success', $data = array() ) {
⋮----
WC()->session->set( 'wc_notices', $notices );
⋮----
function wc_set_notices( $notices ) {
⋮----
WC()->session->set( 'wc_notices', empty( $notices ) ? null : $notices );
⋮----
function wc_clear_notices() {
⋮----
WC()->session->set( 'wc_notices', null );
⋮----
function wc_print_notices( $return = false ) {
⋮----
$all_notices  = $session->get( 'wc_notices', array() );
⋮----
function wc_print_notice( $message, $notice_type = 'success', $data = array(), $return = false ) {
⋮----
function wc_get_notices( $notice_type = '' ) {
⋮----
$all_notices = WC()->session->get( 'wc_notices', array() );
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-order-functions.php">
use Automattic\WooCommerce\Caches\OrderCountCache;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\OrderInternalStatus;
use Automattic\WooCommerce\Enums\PaymentGatewayFeature;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer;
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
use Automattic\WooCommerce\Internal\Utilities\Users;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Utilities\StringUtil;
⋮----
function wc_get_orders( $args ) {
⋮----
$date_before = strpos( $args['date_before'], ':' ) ? $datetime->getOffsetTimestamp() : $datetime->date( 'Y-m-d' );
⋮----
$date_after = strpos( $args['date_after'], ':' ) ? $datetime->getOffsetTimestamp() : $datetime->date( 'Y-m-d' );
⋮----
return $query->get_orders();
⋮----
function wc_get_order( $the_order = false ) {
⋮----
return WC()->order_factory->get_order( $the_order );
⋮----
function wc_get_order_statuses() {
⋮----
function wc_is_order_status( $maybe_status ) {
⋮----
function wc_get_is_paid_statuses() {
⋮----
function wc_get_is_pending_statuses() {
... (280 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-order-item-functions.php">
function wc_add_order_item( $order_id, $item_array ) {
⋮----
$data_store = WC_Data_Store::load( 'order-item' );
$item_id    = $data_store->add_order_item( $order_id, $item_array );
$item       = WC_Order_Factory::get_order_item( $item_id );
⋮----
function wc_update_order_item( $item_id, $args ) {
⋮----
$update     = $data_store->update_order_item( $item_id, $args );
⋮----
function wc_delete_order_item( $item_id ) {
⋮----
$data_store->delete_order_item( $item_id );
⋮----
function wc_update_order_item_meta( $item_id, $meta_key, $meta_value, $prev_value = '' ) {
⋮----
if ( $data_store->update_metadata( $item_id, $meta_key, $meta_value, $prev_value ) ) {
WC_Cache_Helper::invalidate_cache_group( 'object_' . $item_id );
⋮----
function wc_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique = false ) {
⋮----
$meta_id    = $data_store->add_metadata( $item_id, $meta_key, $meta_value, $unique );
⋮----
function wc_delete_order_item_meta( $item_id, $meta_key, $meta_value = '', $delete_all = false ) {
⋮----
if ( $data_store->delete_metadata( $item_id, $meta_key, $meta_value, $delete_all ) ) {
⋮----
function wc_get_order_item_meta( $item_id, $key, $single = true ) {
⋮----
return $data_store->get_metadata( $item_id, $key, $single );
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-order-step-logger-functions.php">
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessingController;
use Automattic\WooCommerce\Internal\Logging\OrderLogsDeletionProcessor;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
function wc_log_order_step( string $message, ?array $context = null, bool $final_step = false, bool $first_step = false ): void {
⋮----
$order->add_meta_data( '_debug_log_source', $context['source'], true );
$order->save();
⋮----
$logger->log( WC_Log_Levels::DEBUG, $message, $context );
⋮----
$order->delete_meta_data( '_debug_log_source' );
if ( OrderUtil::unknown_orders_data_store_in_use() ) {
⋮----
$logger->clear( $context['source'] );
⋮----
$order->add_meta_data( '_debug_log_source_pending_deletion', $context['source'], true );
⋮----
wc_get_container()->get( BatchProcessingController::class )->enqueue_processor( OrderLogsDeletionProcessor::class );
⋮----
function extract_order_safe_data( WC_Order $order ) {
⋮----
'order_id'       => $order->get_id(),
'payment_method' => $order->get_payment_method_title(),
⋮----
'country' => $order->get_billing_country(),
'state'   => $order->get_billing_state(),
⋮----
'country' => $order->get_shipping_country(),
'state'   => $order->get_shipping_state(),
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-page-functions.php">
function wc_page_endpoint_title( $title, $post_id = 0 ) {
⋮----
$endpoint       = WC()->query->get_current_endpoint();
⋮----
$endpoint_title = WC()->query->get_endpoint_title( $endpoint, $action );
⋮----
function wc_page_endpoint_document_title_parts( $title ) {
⋮----
$action         = isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
⋮----
function wc_get_page_id( $page ) {
⋮----
function wc_get_page_permalink( $page, $fallback = null ) {
⋮----
function wc_get_endpoint_url( $endpoint, $value = '', $permalink = '' ) {
⋮----
// Map endpoint to options.
$query_vars = WC()->query->get_query_vars();
⋮----
function wc_get_review_order_url( $order ) {
⋮----
return \Automattic\WooCommerce\Internal\OrderReviews\Endpoint::get_url( $order );
⋮----
/**
 * Hide or adjust menu items conditionally.
 *
 * @param array $items Navigation items.
 * @return array
 */
function wc_nav_menu_items( $items ) {
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-product-functions.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\CatalogVisibility;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
use Automattic\WooCommerce\Internal\Caches\ProductTransientsDeferrer;
use Automattic\WooCommerce\Internal\ProductGallery\ProductMediaGallery;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\ArrayUtil;
use Automattic\WooCommerce\Utilities\NumberUtil;
use Automattic\WooCommerce\Internal\ProductImage\MatchImageBySKU;
⋮----
function wc_get_products( $args ) {
⋮----
return $query->get_products();
⋮----
function wc_get_product( $the_product = false, $deprecated = array() ) {
⋮----
return WC()->product_factory->get_product( $the_product, $deprecated );
⋮----
function wc_get_product_object( $product_type, $product_id = 0 ) {
$classname = WC_Product_Factory::get_product_classname( $product_id, $product_type );
⋮----
return new $classname( $product_id );
⋮----
function wc_product_sku_enabled() {
⋮----
function wc_product_weight_enabled() {
⋮----
... (355 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-rest-functions.php">
use Automattic\WooCommerce\Internal\Utilities\Users;
⋮----
function wc_rest_prepare_date_response( $date, $utc = true ) {
⋮----
$date->setTimezone( new DateTimeZone( wc_timezone_string() ) );
⋮----
return gmdate( 'Y-m-d\TH:i:s', $utc ? $date->getTimestamp() : $date->getOffsetTimestamp() );
⋮----
function wc_rest_allowed_image_mime_types() {
⋮----
function wc_rest_upload_image_from_url( $image_url ) {
⋮----
. sprintf( __( 'Error: %s', 'woocommerce' ), $file_array['tmp_name']->get_error_message() ),
⋮----
function wc_rest_set_uploaded_image_as_attachment( $upload, $id = 0 ) {
⋮----
function wc_rest_validate_reports_request_arg( $value, $request, $param ) {
⋮----
$attributes = $request->get_attributes();
⋮----
function wc_rest_urlencode_rfc3986( $value ) {
⋮----
function wc_rest_check_post_permissions( $post_type, $context = 'read', $object_id = 0 ) {
⋮----
function wc_rest_check_user_permissions( $context = 'read', $object_id = 0 ) {
⋮----
if ( $permission && ! Users::get_user_in_current_site( $object_id ) ) {
⋮----
function wc_rest_check_product_term_permissions( $taxonomy, $context = 'read', $object_id = 0 ) {
⋮----
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-stock-functions.php">
use Automattic\WooCommerce\Checkout\Helpers\ReserveStock;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
⋮----
function wc_update_product_stock( $product, $stock_quantity = null, $operation = 'set', $updating = false ) {
⋮----
if ( ! is_null( $stock_quantity ) && $product->managing_stock() ) {
⋮----
$product_id_with_stock = $product->get_stock_managed_by_id();
$product_with_stock    = $product_id_with_stock !== $product->get_id() ? wc_get_product( $product_id_with_stock ) : $product;
$data_store            = WC_Data_Store::load( 'product' );
⋮----
if ( $product_with_stock->is_type( ProductType::VARIATION ) ) {
⋮----
$new_stock = $data_store->update_product_stock( $product_id_with_stock, $stock_quantity, $operation );
⋮----
$data_store->read_stock_quantity( $product_with_stock, $new_stock );
⋮----
$product_with_stock->save();
⋮----
return $product_with_stock->get_stock_quantity();
⋮----
return $product->get_stock_quantity();
⋮----
function wc_update_product_stock_status( $product_id, $status ) {
⋮----
$product->set_stock_status( $status );
$product->save();
⋮----
function wc_maybe_reduce_stock_levels( $order_id ) {
... (84 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-template-functions.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\PaymentGatewayFeature;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Admin\Features\Fulfillments\Fulfillment;
use Automattic\WooCommerce\Internal\Utilities\HtmlSanitizer;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
function wc_template_redirect() {
⋮----
if ( is_page( wc_get_page_id( 'checkout' ) ) && wc_get_page_id( 'checkout' ) !== wc_get_page_id( 'cart' ) && WC()->cart->is_empty() && empty( $wp->query_vars['order-pay'] ) && ! isset( $wp->query_vars['order-received'] ) && ! is_customize_preview() && apply_filters( 'woocommerce_checkout_redirect_empty_cart', true ) ) {
⋮----
$wp_query->set_404();
⋮----
if ( $product && $product->is_visible() ) {
wp_safe_redirect( get_permalink( $product->get_id() ), 302 );
⋮----
WC()->payment_gateways();
WC()->shipping();
⋮----
function wc_send_frame_options_header() {
⋮----
function wc_prevent_endpoint_indexing() {
⋮----
function wc_prevent_adjacent_posts_rel_link_wp_head() {
⋮----
function wc_gallery_noscript() {
⋮----
function wc_setup_product_data( $post ) {
... (946 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-template-hooks.php">

</file>

<file path="plugins/woocommerce/includes/wc-term-functions.php">
use Automattic\WooCommerce\Enums\ProductStockStatus;
⋮----
function wc_change_get_terms_defaults( $defaults, $taxonomies ) {
⋮----
function wc_change_pre_get_terms( $terms_query ) {
⋮----
$terms_query->meta_query->parse_query_vars( $args );
⋮----
function wc_terms_clauses( $clauses, $taxonomies, $args ) {
⋮----
function wc_get_object_terms( $object_id, $taxonomy, $field = null, $index_key = null ) {
⋮----
function _wc_get_cached_product_terms( $product_id, $taxonomy, $args = array() ) {
$cache_key   = WC_Cache_Helper::get_cache_prefix( 'product_terms_' . $taxonomy ) . 'wc_' . $taxonomy . md5( wp_json_encode( $args ) );
$cache_group = WC_Cache_Helper::get_cache_prefix( 'product_' . $product_id ) . $product_id;
⋮----
function wc_get_product_terms( $product_id, $taxonomy, $args = array() ) {
⋮----
function _wc_get_product_terms_name_num_usort_callback( $a, $b ) {
⋮----
function _wc_get_product_terms_parent_usort_callback( $a, $b ) {
⋮----
function wc_product_dropdown_categories( $args = array() ) {
⋮----
function wc_walk_category_dropdown_tree( ...$args ) {
⋮----
include_once WC()->plugin_path() . '/includes/walkers/class-wc-product-cat-dropdown-walker.php';
⋮----
return $walker->walk( ...$args );
⋮----
... (29 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-update-functions.php">
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Database\Migrations\MigrationHelper;
use Automattic\WooCommerce\Enums\DefaultCustomerAddress;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\Admin\Marketing\MarketingSpecs;
use Automattic\WooCommerce\Internal\Admin\Notes\WooSubscriptionsNotes;
use Automattic\WooCommerce\Internal\AssignDefaultCategory;
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailPostsCleanup;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateSyncBackfill;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\ProductAttributesLookup\DataRegenerator;
use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore;
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register as Download_Directories;
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Synchronize as Download_Directories_Sync;
use Automattic\WooCommerce\Internal\StockNotifications\StockNotifications;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EmailNormalizer;
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
use Automattic\WooCommerce\Internal\VariationGallery\Telemetry as VariationGalleryTelemetry;
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use Automattic\WooCommerce\Internal\VariationGallery\Package as VariationGalleryPackage;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Utilities\StringUtil;
use Automattic\WooCommerce\Blocks\InboxNotifications;
... (638 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-user-functions.php">
use Automattic\WooCommerce\Enums\OrderInternalStatus;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\Internal\Utilities\Users;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
function wc_disable_admin_bar( $show_admin_bar ) {
⋮----
function wc_create_new_customer( $email, $username = '', $password = '', $args = array() ) {
⋮----
if ( is_wp_error( $errors ) && $errors->get_error_code() ) {
⋮----
function wc_create_new_customer_username( $email, $new_user_args = array(), $suffix = '' ) {
⋮----
function wc_set_customer_auth_cookie( $customer_id ) {
⋮----
WC()->session->init_session_cookie();
⋮----
function wc_update_new_customer_past_orders( $customer_id ) {
⋮----
$order->set_customer_id( $customer->ID );
$order->save();
⋮----
if ( $order->has_downloadable_item() ) {
$data_store = WC_Data_Store::load( 'customer-download' );
$data_store->delete_by_order_id( $order->get_id() );
wc_downloadable_product_permissions( $order->get_id(), true );
⋮----
if ( $order->get_status() === OrderInternalStatus::COMPLETED ) {
⋮----
Users::update_site_user_meta( $customer_id, 'wc_order_count', '' );
... (132 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-webhook-functions.php">
function wc_webhook_execute_queue() {
⋮----
'webhook_id' => $data['webhook']->get_id(),
⋮----
$next_scheduled_date = WC()->queue()->get_next( 'woocommerce_deliver_webhook_async', $queue_args, 'woocommerce-webhooks' );
⋮----
if ( is_null( $next_scheduled_date ) || $next_scheduled_date->getTimestamp() >= ( 600 + gmdate( 'U' ) ) ) {
WC()->queue()->add( 'woocommerce_deliver_webhook_async', $queue_args, 'woocommerce-webhooks' );
⋮----
$data['webhook']->deliver( $data['arg'] );
⋮----
function wc_webhook_process_delivery( $webhook, $arg ) {
⋮----
function wc_deliver_webhook_async( $webhook_id, $arg ) {
⋮----
if ( 0 === $webhook->get_id() ) {
⋮----
$webhook->deliver( $arg );
⋮----
function wc_is_webhook_valid_topic( $topic ) {
⋮----
$default_topics = array_keys( array_filter( WC_Webhook::get_default_topic_hooks() ) );
⋮----
function wc_is_webhook_valid_status( $status ) {
⋮----
function wc_get_webhook_statuses() {
⋮----
function wc_load_webhooks( $status = '', $limit = null ) {
// short-circuit if webhooks should not be loaded at all.
⋮----
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/includes/wc-widget-functions.php">
function wc_register_widgets() {
</file>

<file path="plugins/woocommerce/packages/README.md">
# External Packages

This directory holds Composer packages containing functionality developed outside of WooCommerce core.

## Installing Composer

You need Composer to use the packages. If you don't have it installed, go and check how to [install Composer](https://developer.woocommerce.com/docs/contribution/contributing/#setting-up-your-development-environment) and then continue here.

## Developing new packages

To create a package and/or feature plugin for core, you can base your plugin on [the example package](https://github.com/woocommerce/woocommerce-example-package).

Packages require a Package class which inits the package and returns version information, and Packages also require that you use the `jetpack-autoloader` package which prevents version conflicts should the same package be used by multiple plugins at once. This is shown in the example package above.

## Publishing a package

Your package should be published to Packagist ([example](https://packagist.org/packages/woocommerce/woocommerce-example-package)). The package name in this case is `woocommerce/woocommerce-example-package`.

## Including packages in core

Edit `composer.json` in the root directory and add the package and package version under the "require" section. For example:

```json
{
  "name": "woocommerce/woocommerce",
  "description": "An eCommerce toolkit that helps you sell anything. Beautifully.",
  "homepage": "https://woocommerce.com/",
  "type": "wordpress-plugin",
  "license": "GPL-3.0-or-later",
  "prefer-stable": true,
... (55 lines truncated)
</file>

<file path="plugins/woocommerce/patterns/coming-soon-entire-site.php">
use Automattic\WooCommerce\Blocks\Templates\ComingSoonTemplate;
⋮----
$fonts               = ComingSoonTemplate::get_font_families();
</file>

<file path="plugins/woocommerce/patterns/coming-soon-store-only.php">
$current_theme     = wp_get_theme()->get_stylesheet();
</file>

<file path="plugins/woocommerce/patterns/coming-soon.php">
<!-- wp:pattern {"slug":"woocommerce/<?php echo $default_pattern; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>"} /-->
</file>

<file path="plugins/woocommerce/patterns/footer-large.php">

</file>

<file path="plugins/woocommerce/patterns/footer-simple-menu.php">

</file>

<file path="plugins/woocommerce/patterns/footer-with-3-menus.php">

</file>

<file path="plugins/woocommerce/patterns/header-centered-pattern.php">

</file>

<file path="plugins/woocommerce/patterns/header-distraction-free.php">

</file>

<file path="plugins/woocommerce/patterns/header-essential.php">

</file>

<file path="plugins/woocommerce/patterns/header-large.php">

</file>

<file path="plugins/woocommerce/patterns/header-minimal.php">

</file>

<file path="plugins/woocommerce/patterns/no-products-found-filters.php">

</file>

<file path="plugins/woocommerce/patterns/no-products-found.php">

</file>

<file path="plugins/woocommerce/patterns/page-coming-soon-default.php">

</file>

<file path="plugins/woocommerce/patterns/page-coming-soon-image-gallery.php">
use Automattic\WooCommerce\Blocks\Templates\ComingSoonTemplate;
⋮----
$fonts               = ComingSoonTemplate::get_font_families();
</file>

<file path="plugins/woocommerce/patterns/page-coming-soon-minimal-left-image.php">
use Automattic\WooCommerce\Blocks\Templates\ComingSoonTemplate;
⋮----
$fonts                 = ComingSoonTemplate::get_font_families();
</file>

<file path="plugins/woocommerce/patterns/page-coming-soon-modern-black.php">
$current_theme = wp_get_theme()->get_stylesheet();
use Automattic\WooCommerce\Blocks\Templates\ComingSoonTemplate;
⋮----
$fonts               = ComingSoonTemplate::get_font_families();
</file>

<file path="plugins/woocommerce/patterns/page-coming-soon-split-right-image.php">
use Automattic\WooCommerce\Blocks\Templates\ComingSoonTemplate;
⋮----
$fonts                 = ComingSoonTemplate::get_font_families();
</file>

<file path="plugins/woocommerce/patterns/page-coming-soon-with-header-footer.php">
use Automattic\WooCommerce\Blocks\Templates\ComingSoonTemplate;
⋮----
$fonts               = ComingSoonTemplate::get_font_families();
</file>

<file path="plugins/woocommerce/patterns/product-search-form.php">

</file>

<file path="plugins/woocommerce/patterns/README.md">
# WooCommerce Blocks - Patterns

## Naming Conventions for Patterns

* Use spaces as a separator. Only use hyphens for compound words or expressions.
* Use consistent title case capitalization.
* Use clear, descriptive names that indicate the component's function or appearance.
* Group similar items together with a common name structure.
</file>

<file path="plugins/woocommerce/patterns/related-products.php">

</file>

<file path="plugins/woocommerce/php-stubs/wc-admin-feature-config.php">
function wc_admin_get_feature_config() {
</file>

<file path="plugins/woocommerce/php-stubs/wc-constants.php">

</file>

<file path="plugins/woocommerce/sample-data/sample_products.xml">
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:excerpt="http://wordpress.org/export/1.2/excerpt/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wp="http://wordpress.org/export/1.2/">
  <channel>
<title>WooCommerce Demo Store</title>
<link>http:</link>
<description>Just another WooCommerce store</description>
<pubDate>Wed, 16 Jan 2019 13:09:24 +0000</pubDate>
<language>en-US</language>
<wp:wxr_version>1.2</wp:wxr_version>
<wp:base_site_url>http:</wp:base_site_url>
<wp:base_blog_url>http:</wp:base_blog_url>
<wp:author>
  <wp:author_id>1</wp:author_id>
  <wp:author_login>shopmanager</wp:author_login>
  <wp:author_email>info@woocommerce.com</wp:author_email>
  <wp:author_display_name><![CDATA[Shop Manager]]></wp:author_display_name>
  <wp:author_first_name><![CDATA[]]></wp:author_first_name>
  <wp:author_last_name><![CDATA[]]></wp:author_last_name>
</wp:author>
<generator>https://wordpress.org/?v=5.0.3</generator>
<item>
  <title>V-Neck T-Shirt</title>
  <link>https://woocommercecore.mystagingwebsite.com/product/v-neck-t-shirt/</link>
  <pubDate>Wed, 16 Jan 2019 13:01:52 +0000</pubDate>
  <dc:creator>shopmanager</dc:creator>
  <guid isPermaLink="false">https://woocommercecore.mystagingwebsite.com/product/v-neck-t-shirt/</guid>
  <description/>
  <content:encoded><![CDATA[Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.]]></content:encoded>
  <excerpt:encoded><![CDATA[This is a variable product.]]></excerpt:encoded>
  <wp:post_id>6</wp:post_id>
... (4806 lines truncated)
</file>

<file path="plugins/woocommerce/src/Abilities/AbilityDefinition.php">
namespace Automattic\WooCommerce\Abilities;
⋮----
interface AbilityDefinition {
⋮----
public static function get_name(): string;
⋮----
public static function get_registration_args(): array;
</file>

<file path="plugins/woocommerce/src/Admin/API/AI/BusinessDescription.php">
namespace Automattic\WooCommerce\Admin\API\AI;
⋮----
class BusinessDescription {}
</file>

<file path="plugins/woocommerce/src/Admin/API/AI/Images.php">
namespace Automattic\WooCommerce\Admin\API\AI;
⋮----
class Images {}
</file>

<file path="plugins/woocommerce/src/Admin/API/AI/Middleware.php">
namespace Automattic\WooCommerce\Admin\API\AI;
⋮----
class Middleware {}
</file>

<file path="plugins/woocommerce/src/Admin/API/AI/Patterns.php">
namespace Automattic\WooCommerce\Admin\API\AI;
⋮----
class Patterns {}
</file>

<file path="plugins/woocommerce/src/Admin/API/AI/Product.php">
namespace Automattic\WooCommerce\Admin\API\AI;
⋮----
class Product {}
</file>

<file path="plugins/woocommerce/src/Admin/API/AI/StoreInfo.php">
namespace Automattic\WooCommerce\Admin\API\AI;
⋮----
class StoreInfo {}
</file>

<file path="plugins/woocommerce/src/Admin/API/AI/StoreTitle.php">
namespace Automattic\WooCommerce\Admin\API\AI;
⋮----
class StoreTitle {}
</file>

<file path="plugins/woocommerce/src/Admin/API/RateLimits/QRLoginRateLimits.php">
namespace Automattic\WooCommerce\Admin\API\RateLimits;
⋮----
use Automattic\WooCommerce\Admin\API\MobileAppQRLogin;
use WC_Rate_Limiter;
⋮----
class QRLoginRateLimits extends WC_Rate_Limiter {
⋮----
public static function get_action_id( string $bucket, string $identifier ): string {
⋮----
public static function consume( string $bucket, string $identifier ): bool {
⋮----
$options = self::get_bucket_options( $bucket );
⋮----
$action_id         = self::get_action_id( $bucket, $identifier );
⋮----
$result = $wpdb->query(
$wpdb->prepare(
⋮----
return (int) $wpdb->get_var( 'SELECT LAST_INSERT_ID()' ) > 0;
⋮----
private static function get_bucket_options( string $bucket ): ?array {
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Categories/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Categories;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\ExportableInterface;
use Automattic\WooCommerce\Admin\API\Reports\GenericController;
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
use Automattic\WooCommerce\Admin\API\Reports\OrderAwareControllerTrait;
⋮----
class Controller extends GenericController implements ExportableInterface {
⋮----
protected $rest_base = 'reports/categories';
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
protected function prepare_reports_query( $request ) {
⋮----
public function prepare_item_for_response( $report, $request ) {
⋮----
$response = parent::prepare_item_for_response( $report, $request );
$response->add_links( $this->prepare_links( $report ) );
⋮----
protected function prepare_links( $object ) {
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
⋮----
public function get_collection_params() {
$params                       = parent::get_collection_params();
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Categories/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Categories;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
⋮----
class DataStore extends ReportsDataStore implements DataStoreInterface {
⋮----
protected static $table_name = 'wc_order_product_lookup';
⋮----
protected $cache_key = 'categories';
⋮----
private $order_by = '';
⋮----
/**
	 * Order setting used for sorting categories data.
	 *
	 * @var string
	 */
private $order = '';
⋮----
/**
	 * Mapping columns to data type to return correct response types.
	 *
	 * @override ReportsDataStore::$column_types
	 *
	 * @var array
	 */
protected $column_types = array(
⋮----
... (85 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Categories/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Categories;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Query as ReportsQuery;
⋮----
class Query extends ReportsQuery {
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
⋮----
$args    = apply_filters( 'woocommerce_analytics_categories_query_args', $this->get_query_vars() );
$results = \WC_Data_Store::load( self::REPORT_NAME )->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Coupons/Stats/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Coupons\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericStatsController;
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends GenericStatsController {
⋮----
protected $rest_base = 'reports/coupons/stats';
⋮----
protected function prepare_reports_query( $request ) {
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
public function prepare_item_for_response( $report, $request ) {
$response = parent::prepare_item_for_response( $report, $request );
⋮----
protected function get_item_properties_schema() {
⋮----
public function get_item_schema() {
$schema          = parent::get_item_schema();
⋮----
return $this->add_additional_fields_schema( $schema );
⋮----
public function get_collection_params() {
$params                    = parent::get_collection_params();
$params['orderby']['enum'] = $this->apply_custom_orderby_filters(
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Coupons/Stats/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Coupons\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Coupons\DataStore as CouponsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\Admin\API\Reports\StatsDataStoreTrait;
⋮----
class DataStore extends CouponsDataStore implements DataStoreInterface {
⋮----
protected $column_types = array(
⋮----
protected $report_columns;
⋮----
protected $context = 'coupons_stats';
⋮----
protected $cache_key = 'coupons_stats';
⋮----
protected function assign_report_columns() {
$table_name           = self::get_db_table_name();
⋮----
protected function update_sql_query_params( $query_args ) {
⋮----
$order_coupon_lookup_table = self::get_db_table_name();
⋮----
$included_coupons = $this->get_included_coupons( $query_args, 'coupons' );
⋮----
$order_status_filter = $this->get_status_subquery( $query_args );
⋮----
$this->add_time_period_sql_params( $query_args, $order_coupon_lookup_table );
$this->add_intervals_sql_params( $query_args, $order_coupon_lookup_table );
... (64 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Coupons/Stats/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Coupons\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Query as ReportsQuery;
⋮----
class Query extends ReportsQuery {
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
⋮----
$args = apply_filters( 'woocommerce_analytics_coupons_stats_query_args', $this->get_query_vars() );
⋮----
$data_store = \WC_Data_Store::load( 'report-coupons-stats' );
$results    = $data_store->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Coupons/Stats/Segmenter.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Coupons\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Segmenter as ReportsSegmenter;
use Automattic\WooCommerce\Admin\API\Reports\ParameterException;
⋮----
class Segmenter extends ReportsSegmenter {
⋮----
protected function get_segment_selections_product_level( $products_table ) {
⋮----
protected function get_segment_selections_order_level( $coupons_lookup_table ) {
⋮----
protected function segment_selections_orders( $coupons_lookup_table, $overrides = array() ) {
⋮----
protected function get_product_related_totals_segments( $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $totals_query, $unique_orders_table ) {
⋮----
$segments_products = $wpdb->get_results(
⋮----
$totals_segments = $this->merge_segment_totals_results( $segmenting_dimension_name, $segments_products, array() );
⋮----
protected function get_product_related_intervals_segments( $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $intervals_query, $unique_orders_table ) {
⋮----
$segmenting_limit = $limit_parts[0] . ',' . $orig_rowcount * count( $this->get_all_segments() );
⋮----
$intervals_segments = $this->merge_segment_intervals_results( $segmenting_dimension_name, $segments_products, array() );
⋮----
protected function get_order_related_totals_segments( $segmenting_select, $segmenting_from, $segmenting_where, $segmenting_groupby, $table_name, $totals_query ) {
⋮----
$totals_segments = $wpdb->get_results(
⋮----
$totals_segments = $this->reformat_totals_segments( $totals_segments, $segmenting_groupby );
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Coupons/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Coupons;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericController;
use Automattic\WooCommerce\Admin\API\Reports\ExportableInterface;
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends GenericController implements ExportableInterface {
⋮----
protected $rest_base = 'reports/coupons';
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
protected function prepare_reports_query( $request ) {
⋮----
public function prepare_item_for_response( $report, $request ) {
$response = parent::prepare_item_for_response( $report, $request );
$response->add_links( $this->prepare_links( $report ) );
⋮----
protected function prepare_links( $object ) {
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
⋮----
public function get_collection_params() {
$params                       = parent::get_collection_params();
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Coupons/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Coupons;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
use Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
use Automattic\WooCommerce\Enums\OrderItemType;
⋮----
class DataStore extends ReportsDataStore implements DataStoreInterface {
⋮----
protected static $table_name = 'wc_order_coupon_lookup';
⋮----
protected $cache_key = 'coupons';
⋮----
protected $column_types = array(
⋮----
protected $context = 'coupons';
⋮----
protected function assign_report_columns() {
$table_name           = self::get_db_table_name();
⋮----
public static function init() {
⋮----
protected function get_included_coupons_array( $query_args ) {
⋮----
protected function add_sql_query_params( $query_args ) {
⋮----
$order_coupon_lookup_table = self::get_db_table_name();
⋮----
... (148 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Coupons/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Coupons;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Query as ReportsQuery;
⋮----
class Query extends ReportsQuery {
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
⋮----
$args = apply_filters( 'woocommerce_analytics_coupons_query_args', $this->get_query_vars() );
⋮----
$data_store = \WC_Data_Store::load( 'report-coupons' );
$results    = $data_store->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Customers/Stats/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Customers\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Customers\Query;
use Automattic\WooCommerce\Admin\API\Reports\Customers\Controller as CustomersController;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
⋮----
class Controller extends \WC_REST_Reports_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
protected $rest_base = 'reports/customers/stats';
⋮----
protected function prepare_reports_query( $request ) {
⋮----
$normalized_params_numeric = TimeInterval::normalize_between_params( $request, $between_params_numeric, false );
⋮----
$normalized_params_date    = TimeInterval::normalize_between_params( $request, $between_params_date, true );
⋮----
$args = CustomersController::consolidate_customer_id_filters( $args );
⋮----
public function get_items( $request ) {
$query_args      = $this->prepare_reports_query( $request );
⋮----
$report_data     = $customers_query->get_data();
⋮----
public function prepare_item_for_response( $report, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Customers/Stats/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Customers\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore as CustomersDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
⋮----
class DataStore extends CustomersDataStore implements DataStoreInterface {
⋮----
protected $column_types = array(
⋮----
protected $cache_key = 'customers_stats';
⋮----
protected $context = 'customers_stats';
⋮----
protected function assign_report_columns() {
⋮----
public function get_default_query_vars() {
$defaults            = ReportsDataStore::get_default_query_vars();
⋮----
public function get_noncached_data( $query_args ) {
⋮----
$this->initialize_queries();
⋮----
$countable_order   = static::get_countable_customer_order_predicate( $order_stats_table );
⋮----
$selections = $this->selected_columns( $query_args );
$this->add_sql_query_params( $query_args );
⋮----
$this->subquery->clear_sql_clause( 'select' );
$this->subquery->add_sql_clause( 'select', 'SUM( total_sales ) AS total_spend,' );
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Customers/Stats/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Customers\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Query as ReportsQuery;
⋮----
class Query extends ReportsQuery {
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
⋮----
$args = apply_filters( 'woocommerce_analytics_customers_stats_query_args', $this->get_query_vars() );
⋮----
$data_store = \WC_Data_Store::load( 'report-customers-stats' );
$results    = $data_store->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Customers/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Customers;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericController;
use Automattic\WooCommerce\Admin\API\Reports\ExportableTraits;
use Automattic\WooCommerce\Admin\API\Reports\ExportableInterface;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
⋮----
class Controller extends GenericController implements ExportableInterface {
⋮----
protected $rest_base = 'reports/customers';
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
$report_data = $query->get_data();
⋮----
protected function prepare_reports_query( $request ) {
⋮----
$normalized_params_numeric = TimeInterval::normalize_between_params( $request, $between_params_numeric, false );
⋮----
$normalized_params_date    = TimeInterval::normalize_between_params( $request, $between_params_date, true );
⋮----
$args = self::consolidate_customer_id_filters( $args );
⋮----
public static function consolidate_customer_id_filters( $args ) {
⋮----
if ( ! empty( $args[ $param ] ) && self::is_id_list( $args[ $param ] ) ) {
⋮----
private static function is_id_list( $value ) {
⋮----
public function get_item( $request ) {
... (67 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Customers/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Customers;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
use Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
use Automattic\WooCommerce\Admin\Overrides\Order as OverridesOrder;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class DataStore extends ReportsDataStore implements DataStoreInterface {
⋮----
protected static $table_name = 'wc_customer_lookup';
⋮----
protected $cache_key = 'customers';
⋮----
protected $column_types = array(
⋮----
protected $context = 'customers';
⋮----
protected function assign_report_columns() {
⋮----
$table_name           = self::get_db_table_name();
⋮----
$countable_order      = static::get_countable_customer_order_predicate( $order_stats_table );
⋮----
protected static function get_countable_customer_order_predicate( $order_stats_table ) {
$orders_table      = OrderUtil::get_table_for_orders();
$hpos_enabled      = OrderUtil::custom_orders_table_usage_is_enabled();
⋮----
... (287 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Customers/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Customers;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
⋮----
class Query extends GenericQuery {
⋮----
protected $name = 'customers';
⋮----
protected function get_default_query_vars() {
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Downloads/Files/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Downloads\Files;
⋮----
class Controller extends \WC_REST_Reports_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
protected $rest_base = 'reports/downloads/files';
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Downloads/Stats/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Downloads\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
use Automattic\WooCommerce\Admin\API\Reports\GenericStatsController;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends GenericStatsController {
⋮----
protected $rest_base = 'reports/downloads/stats';
⋮----
protected function prepare_reports_query( $request ) {
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
public function prepare_item_for_response( $report, $request ) {
$response = parent::prepare_item_for_response( $report, $request );
⋮----
protected function get_item_properties_schema() {
⋮----
public function get_item_schema() {
$totals = $this->get_item_properties_schema();
⋮----
return $this->add_additional_fields_schema( $schema );
⋮----
public function get_collection_params() {
$params                     = parent::get_collection_params();
$params['orderby']['enum']  = $this->apply_custom_orderby_filters(
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Downloads/Stats/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Downloads\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Downloads\DataStore as DownloadsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\Admin\API\Reports\StatsDataStoreTrait;
⋮----
class DataStore extends DownloadsDataStore implements DataStoreInterface {
⋮----
protected $column_types = array(
⋮----
protected $cache_key = 'downloads_stats';
⋮----
protected $context = 'downloads_stats';
⋮----
protected function assign_report_columns() {
⋮----
public function get_default_query_vars() {
$defaults             = parent::get_default_query_vars();
⋮----
public function get_noncached_stats_data( $query_args, $params, &$data, $expected_interval_count ) {
⋮----
$table_name = self::get_db_table_name();
⋮----
$this->initialize_queries();
$selections = $this->selected_columns( $query_args );
$this->add_sql_query_params( $query_args );
$where_time = $this->add_time_period_sql_params( $query_args, $table_name );
$this->add_intervals_sql_params( $query_args, $table_name );
⋮----
... (42 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Downloads/Stats/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Downloads\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Query as ReportsQuery;
⋮----
class Query extends ReportsQuery {
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
⋮----
$args = apply_filters( 'woocommerce_analytics_downloads_stats_query_args', $this->get_query_vars() );
⋮----
$data_store = \WC_Data_Store::load( 'report-downloads-stats' );
$results    = $data_store->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Downloads/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Downloads;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\ExportableInterface;
use Automattic\WooCommerce\Admin\API\Reports\GenericController;
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
use Automattic\WooCommerce\Admin\API\Reports\OrderAwareControllerTrait;
⋮----
class Controller extends GenericController implements ExportableInterface {
⋮----
protected $rest_base = 'reports/downloads';
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
public function prepare_item_for_response( $report, $request ) {
⋮----
$response = parent::prepare_item_for_response( $report, $request );
$response->add_links( $this->prepare_links( $report ) );
⋮----
$file_path                   = $_product->get_file_download_path( $report['download_id'] );
⋮----
$customer                       = new \WC_Customer( $report['user_id'] );
$response->data['username']     = $customer->get_username();
$response->data['order_number'] = $this->get_order_number( $report['order_id'] );
⋮----
protected function prepare_links( $object ) {
⋮----
protected function prepare_reports_query( $request ) {
⋮----
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Downloads/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Downloads;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
⋮----
class DataStore extends ReportsDataStore implements DataStoreInterface {
⋮----
protected static $table_name = 'wc_download_log';
⋮----
protected $cache_key = 'downloads';
⋮----
protected $column_types = array(
⋮----
protected $context = 'downloads';
⋮----
protected function assign_report_columns() {
⋮----
protected function add_sql_query_params( $query_args ) {
⋮----
$lookup_table     = self::get_db_table_name();
⋮----
$operator         = $this->get_match_operator( $query_args );
⋮----
$where_time = $this->add_time_period_sql_params( $query_args, $lookup_table );
⋮----
$this->subquery->add_sql_clause( 'where_time', $where_time );
⋮----
$this->interval_query->add_sql_clause( 'where_time', $where_time );
... (100 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Downloads/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Downloads;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Query as ReportsQuery;
⋮----
class Query extends ReportsQuery {
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
⋮----
$args = apply_filters( 'woocommerce_analytics_downloads_query_args', $this->get_query_vars() );
⋮----
$data_store = \WC_Data_Store::load( 'report-downloads' );
$results    = $data_store->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Export/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Export;
⋮----
use Automattic\WooCommerce\Admin\ReportExporter;
use Automattic\WooCommerce\Admin\ReportCSVExporter;
⋮----
class Controller extends \Automattic\WooCommerce\Admin\API\Reports\Controller {
⋮----
protected $rest_base = 'reports/(?P<type>[a-z]+)/export';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_export_collection_params(),
⋮----
protected function get_export_collection_params() {
⋮----
public function validate_report_args( $value, $request, $param ) {
⋮----
$report_controller = ReportCSVExporter::get_report_controller( $request['type'] );
⋮----
return new \WP_Error(
⋮----
$schema_check = new \WP_REST_Request();
$schema_check->set_attributes( array( 'args' => $report_controller->get_collection_params() ) );
$schema_check->set_query_params( is_array( $value ) ? $value : array() );
⋮----
return $schema_check->has_valid_params();
⋮----
public function get_export_public_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Import/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Import;
⋮----
use Automattic\WooCommerce\Admin\ReportsSync;
⋮----
class Controller extends \Automattic\WooCommerce\Admin\API\Reports\Controller {
⋮----
protected $rest_base = 'reports/import';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_import_collection_params(),
⋮----
public function import_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function import_items( $request ) {
$query_args = $this->prepare_objects_query( $request );
$import     = ReportsSync::regenerate_report_data( $query_args['days'], $query_args['skip_existing'] );
⋮----
'message' => $import->get_error_message(),
⋮----
$response = $this->prepare_item_for_response( $result, $request );
$data     = $this->prepare_response_for_collection( $response );
⋮----
protected function prepare_objects_query( $request ) {
⋮----
public function prepare_item_for_response( $item, $request ) {
$data     = $this->add_additional_fields_to_object( $item, $request );
$data     = $this->filter_response_by_context( $data, 'view' );
... (24 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Orders/Stats/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Orders\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericStatsController;
use Automattic\WooCommerce\Admin\API\Reports\OrderAwareControllerTrait;
use Automattic\WooCommerce\Admin\API\Reports\Orders\Stats\Query;
⋮----
class Controller extends GenericStatsController {
⋮----
protected $rest_base = 'reports/orders/stats';
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
protected function prepare_reports_query( $request ) {
⋮----
public function prepare_item_for_response( $report, $request ) {
⋮----
$response = parent::prepare_item_for_response( $report, $request );
⋮----
protected function get_item_properties_schema() {
⋮----
public function get_item_schema() {
$schema          = parent::get_item_schema();
⋮----
return $this->add_additional_fields_schema( $schema );
⋮----
public function get_collection_params() {
$params                     = parent::get_collection_params();
$params['orderby']['enum']  = $this->apply_custom_orderby_filters(
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Orders/Stats/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Orders\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
use Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
use Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore as CustomersDataStore;
use Automattic\WooCommerce\Enums\OrderItemType;
use Automattic\WooCommerce\Internal\Admin\Schedulers\OrdersScheduler;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Admin\API\Reports\StatsDataStoreTrait;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use stdClass;
use WC_Order;
use WC_Order_Refund;
use Automattic\WooCommerce\Admin\Overrides\Order;
use Automattic\WooCommerce\Admin\Overrides\OrderRefund;
⋮----
class DataStore extends ReportsDataStore implements DataStoreInterface {
⋮----
protected static $table_name = 'wc_order_stats';
⋮----
protected $cache_key = 'orders_stats';
⋮----
protected $column_types = array(
⋮----
protected $context = 'orders_stats';
⋮----
... (270 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Orders/Stats/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Orders\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
⋮----
class Query extends GenericQuery {
⋮----
protected $name = 'orders-stats';
⋮----
protected function get_default_query_vars() {
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Orders/Stats/Segmenter.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Orders\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Segmenter as ReportsSegmenter;
use Automattic\WooCommerce\Admin\API\Reports\ParameterException;
⋮----
class Segmenter extends ReportsSegmenter {
⋮----
protected function get_segment_selections_product_level( $products_table ) {
⋮----
protected function get_segment_selections_order_level( $unique_orders_table ) {
⋮----
protected function segment_selections_orders( $order_stats_table, $overrides = array() ) {
⋮----
protected function get_product_related_totals_segments( $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $totals_query, $unique_orders_table ) {
⋮----
$segments_products = $wpdb->get_results(
⋮----
$segments_orders = $wpdb->get_results(
⋮----
$totals_segments = $this->merge_segment_totals_results( $segmenting_dimension_name, $segments_products, $segments_orders );
⋮----
protected function get_product_related_intervals_segments( $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $intervals_query, $unique_orders_table ) {
⋮----
$segmenting_limit = $limit_parts[0] . ',' . $orig_rowcount * count( $this->get_all_segments() );
⋮----
$intervals_segments = $this->merge_segment_intervals_results( $segmenting_dimension_name, $segments_products, $segments_orders );
⋮----
protected function get_order_related_totals_segments( $segmenting_select, $segmenting_from, $segmenting_where, $segmenting_groupby, $table_name, $totals_query ) {
⋮----
$totals_segments = $wpdb->get_results(
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Orders/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Orders;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\ExportableInterface;
use Automattic\WooCommerce\Admin\API\Reports\GenericController;
use Automattic\WooCommerce\Admin\API\Reports\OrderAwareControllerTrait;
⋮----
class Controller extends GenericController implements ExportableInterface {
⋮----
protected $rest_base = 'reports/orders';
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
protected function prepare_reports_query( $request ) {
⋮----
public function prepare_item_for_response( $report, $request ) {
$report['order_number']    = $this->get_order_number( $report['order_id'] );
$report['total_formatted'] = $this->get_total_formatted( $report['order_id'] );
⋮----
$response = parent::prepare_item_for_response( $report, $request );
$response->add_links( $this->prepare_links( $report ) );
⋮----
protected function prepare_links( $object ) {
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
⋮----
public function get_collection_params() {
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Orders/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Orders;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\Internal\Traits\OrderAttributionMeta;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class DataStore extends ReportsDataStore implements DataStoreInterface {
⋮----
public function __construct() {
$this->date_column_name = $this->sanitize_date_column_name( get_option( 'woocommerce_date_type' ), 'date_paid' );
parent::__construct();
⋮----
final public static function init() {
⋮----
protected static $table_name = 'wc_order_stats';
⋮----
protected $cache_key = 'orders';
⋮----
protected $column_types = array(
⋮----
protected $context = 'orders';
⋮----
protected function assign_report_columns() {
$table_name = self::get_db_table_name();
⋮----
protected function add_sql_query_params( $query_args ) {
⋮----
... (145 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Orders/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Orders;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
⋮----
class Query extends GenericQuery {
⋮----
protected $name = 'orders';
⋮----
protected function get_default_query_vars() {
return \WC_Object_Query::get_default_query_vars();
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/PerformanceIndicators/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\PerformanceIndicators;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericController;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends GenericController {
⋮----
protected $rest_base = 'reports/performance-indicators';
⋮----
protected $endpoints = array();
⋮----
protected $active_jetpack_modules = null;
⋮----
protected $allowed_stats = array();
⋮----
protected $labels = array();
⋮----
protected $urls = array();
⋮----
protected $stats_data = array();
⋮----
public function __construct() {
⋮----
public function register_routes() {
parent::register_routes();
⋮----
'args'                => $this->get_collection_params(),
⋮----
... (92 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Products/Stats/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Products\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
use Automattic\WooCommerce\Admin\API\Reports\GenericStatsController;
use Automattic\WooCommerce\Internal\Admin\Reports\ProductSearchQuery;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends GenericStatsController {
⋮----
protected $rest_base = 'reports/products/stats';
⋮----
protected $param_mapping = array(
⋮----
public function __construct() {
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
protected function prepare_reports_query( $request ) {
⋮----
$registered = array_keys( $this->get_collection_params() );
⋮----
public function prepare_item_for_response( $report, $request ) {
$response = parent::prepare_item_for_response( $report, $request );
⋮----
protected function get_item_properties_schema() {
⋮----
public function get_item_schema() {
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Products/Stats/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Products\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Products\DataStore as ProductsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\Admin\API\Reports\StatsDataStoreTrait;
use Automattic\WooCommerce\Internal\Admin\Reports\ProductSearchQuery;
⋮----
class DataStore extends ProductsDataStore implements DataStoreInterface {
⋮----
protected $column_types = array(
⋮----
protected $cache_key = 'products_stats';
⋮----
protected $context = 'products_stats';
⋮----
protected function assign_report_columns() {
$table_name           = self::get_db_table_name();
⋮----
protected function update_sql_query_params( $query_args ) {
⋮----
$order_product_lookup_table = self::get_db_table_name();
⋮----
$included_products = $this->get_included_products_array( $query_args );
$product_id_filter = ProductSearchQuery::get_id_condition(
⋮----
ProductSearchQuery::get_ids_subquery( $query_args['search'] ?? array(), $included_products ),
⋮----
$included_variations = $this->get_included_variations( $query_args );
... (81 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Products/Stats/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Products\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Query as ReportsQuery;
⋮----
class Query extends ReportsQuery {
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
⋮----
$args = apply_filters( 'woocommerce_analytics_products_stats_query_args', $this->get_query_vars() );
⋮----
$data_store = \WC_Data_Store::load( 'report-products-stats' );
$results    = $data_store->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Products/Stats/Segmenter.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Products\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Segmenter as ReportsSegmenter;
use Automattic\WooCommerce\Admin\API\Reports\ParameterException;
⋮----
class Segmenter extends ReportsSegmenter {
⋮----
protected function get_segment_selections_product_level( $products_table ) {
⋮----
protected function get_product_related_totals_segments( $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $totals_query, $unique_orders_table ) {
⋮----
$segments_products = $wpdb->get_results(
⋮----
$totals_segments = $this->merge_segment_totals_results( $segmenting_dimension_name, $segments_products, array() );
⋮----
protected function get_product_related_intervals_segments( $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $intervals_query, $unique_orders_table ) {
⋮----
$segment_count    = count( $this->get_all_segments() );
⋮----
$segmenting_limit = $wpdb->prepare( 'LIMIT %d, %d', $orig_offset * $segment_count, $orig_rowcount * $segment_count );
⋮----
$intervals_segments = $this->merge_segment_intervals_results( $segmenting_dimension_name, $segments_products, array() );
⋮----
protected function get_segments( $type, $query_params, $table_name ) {
⋮----
// Product, variation, and category are bound to product, so here product segmenting table is required,
// while coupon and customer are bound to order, so we don't need the extra JOIN for those.
⋮----
$product_level_columns     = $this->get_segment_selections_product_level( $product_segmenting_table );
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Products/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Products;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\ExportableInterface;
use Automattic\WooCommerce\Admin\API\Reports\GenericController;
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
use Automattic\WooCommerce\Internal\Admin\Reports\ProductSearchQuery;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends GenericController implements ExportableInterface {
⋮----
protected $rest_base = 'reports/products';
⋮----
protected $param_mapping = array(
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
public function prepare_item_for_response( $report, $request ) {
$response = parent::prepare_item_for_response( $report, $request );
$response->add_links( $this->prepare_links( $report ) );
⋮----
protected function prepare_reports_query( $request ) {
⋮----
$registered = array_keys( $this->get_collection_params() );
⋮----
protected function prepare_links( $object ) {
⋮----
public function get_item_schema() {
... (27 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Products/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Products;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Internal\Admin\Reports\ProductSearchQuery;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class DataStore extends ReportsDataStore implements DataStoreInterface {
⋮----
protected static $table_name = 'wc_order_product_lookup';
⋮----
protected $cache_key = 'products';
⋮----
protected $column_types = array(
⋮----
protected $extended_attributes = array(
⋮----
protected $context = 'products';
⋮----
private $is_search = false;
⋮----
private $search_subquery = null;
⋮----
protected function assign_report_columns() {
$table_name           = self::get_db_table_name();
⋮----
... (202 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Products/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Products;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Query as ReportsQuery;
⋮----
class Query extends ReportsQuery {
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
⋮----
$args = apply_filters( 'woocommerce_analytics_products_query_args', $this->get_query_vars() );
⋮----
$data_store = \WC_Data_Store::load( 'report-products' );
$results    = $data_store->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Revenue/Stats/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Revenue\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericStatsController;
use Automattic\WooCommerce\Admin\API\Reports\Revenue\Query as RevenueQuery;
use Automattic\WooCommerce\Admin\API\Reports\ExportableInterface;
use Automattic\WooCommerce\Admin\API\Reports\ExportableTraits;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends GenericStatsController implements ExportableInterface {
⋮----
protected $rest_base = 'reports/revenue/stats';
⋮----
protected function prepare_reports_query( $request ) {
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
public function get_export_items( $request ) {
$response  = $this->get_items( $request );
$data      = $response->get_data();
⋮----
$response->set_data( $intervals );
⋮----
public function prepare_item_for_response( $report, $request ) {
$response = parent::prepare_item_for_response( $report, $request );
⋮----
protected function get_item_properties_schema() {
⋮----
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Revenue/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Revenue;
⋮----
class Query extends \WC_Object_Query {
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
$args = apply_filters( 'woocommerce_analytics_revenue_query_args', $this->get_query_vars() );
⋮----
$data_store = \WC_Data_Store::load( 'report-revenue-stats' );
$results    = $data_store->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Stock/Stats/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Stock\Stats;
⋮----
class Controller extends \WC_REST_Reports_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
protected $rest_base = 'reports/stock/stats';
⋮----
public function get_items( $request ) {
⋮----
$report_data = $stock_query->get_data();
⋮----
public function prepare_item_for_response( $report, $request ) {
⋮----
$data    = $this->add_additional_fields_to_object( $data, $request );
$data    = $this->filter_response_by_context( $data, $context );
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
⋮----
public function get_collection_params() {
⋮----
$params['context'] = $this->get_context_param( array( 'default' => 'view' ) );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Stock/Stats/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Stock\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
⋮----
class DataStore extends ReportsDataStore implements DataStoreInterface {
⋮----
public function get_data( $query ) {
⋮----
$low_stock_count = $this->get_low_stock_count();
⋮----
$count = $this->get_count( $status );
⋮----
$product_count = $this->get_product_count();
⋮----
private function get_low_stock_count() {
⋮----
return (int) $wpdb->get_var(
$wpdb->prepare(
⋮----
private function get_count( $status ) {
⋮----
private function get_product_count() {
⋮----
$query = new \WP_Query();
$query->query( $query_args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Stock/Stats/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Stock\Stats;
⋮----
class Query extends \WC_Object_Query {
⋮----
public function get_data() {
$data_store = \WC_Data_Store::load( 'report-stock-stats' );
$results    = $data_store->get_data();
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Stock/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Stock;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericController;
use Automattic\WooCommerce\Admin\API\Reports\ExportableInterface;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
use WP_REST_Request;
use WP_REST_Response;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
⋮----
class Controller extends GenericController implements ExportableInterface {
⋮----
protected $rest_base = 'reports/stock';
⋮----
protected $status_options;
⋮----
public function __construct() {
⋮----
protected function prepare_reports_query( $request ) {
⋮----
protected function get_products( $query_args ) {
$query  = new \WP_Query();
$result = $query->query( $query_args );
⋮----
$count_query = new \WP_Query();
$count_query->query( $query_args );
⋮----
public function get_items( $request ) {
⋮----
... (72 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Taxes/Stats/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Taxes\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
use Automattic\WooCommerce\Admin\API\Reports\GenericStatsController;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends GenericStatsController {
⋮----
protected $rest_base = 'reports/taxes/stats';
⋮----
public function __construct() {
⋮----
public function set_default_report_data( $results ) {
⋮----
$results                       = new \stdClass();
⋮----
$results->totals               = new \stdClass();
⋮----
protected function prepare_reports_query( $request ) {
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
public function prepare_item_for_response( $report, $request ) {
$response = parent::prepare_item_for_response( $report, $request );
⋮----
protected function get_item_properties_schema() {
⋮----
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Taxes/Stats/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Taxes\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\Taxes\DataStore as TaxesDataStore;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\Admin\API\Reports\StatsDataStoreTrait;
⋮----
class DataStore extends ReportsDataStore implements DataStoreInterface {
⋮----
protected static $table_name = 'wc_order_tax_lookup';
⋮----
protected $cache_key = 'taxes_stats';
⋮----
protected $column_types = array(
⋮----
protected $context = 'taxes_stats';
⋮----
public function __construct() {
$this->date_column_name = $this->sanitize_date_column_name( get_option( 'woocommerce_date_type' ), 'date_paid' );
parent::__construct();
⋮----
protected function assign_report_columns() {
$table_name           = self::get_db_table_name();
⋮----
protected function update_sql_query_params( $query_args ) {
⋮----
$order_tax_lookup_table = self::get_db_table_name();
⋮----
$this->add_time_period_sql_params( $query_args, $order_stats_table );
... (86 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Taxes/Stats/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Taxes\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Query as ReportsQuery;
⋮----
class Query extends ReportsQuery {
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
⋮----
$args = apply_filters( 'woocommerce_analytics_taxes_stats_query_args', $this->get_query_vars() );
⋮----
$data_store = \WC_Data_Store::load( 'report-taxes-stats' );
$results    = $data_store->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Taxes/Stats/Segmenter.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Taxes\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Segmenter as ReportsSegmenter;
⋮----
class Segmenter extends ReportsSegmenter {
⋮----
protected function get_segment_selections_order_level( $lookup_table ) {
⋮----
protected function get_order_related_totals_segments( $segmenting_select, $segmenting_from, $segmenting_where, $segmenting_groupby, $table_name, $totals_query ) {
⋮----
$totals_segments = $wpdb->get_results(
⋮----
$totals_segments = $this->reformat_totals_segments( $totals_segments, $segmenting_groupby );
⋮----
protected function get_order_related_intervals_segments( $segmenting_select, $segmenting_from, $segmenting_where, $segmenting_groupby, $table_name, $intervals_query ) {
⋮----
$segmenting_limit = $limit_parts[0] . ',' . $orig_rowcount * count( $this->get_all_segments() );
⋮----
$intervals_segments = $wpdb->get_results(
⋮----
$intervals_segments = $this->reformat_intervals_segments( $intervals_segments, $segmenting_groupby );
⋮----
protected function get_segments( $type, $query_params, $table_name ) {
⋮----
$tax_rate_level_columns = $this->get_segment_selections_order_level( $table_name );
$segmenting_select      = $this->prepare_selections( $tax_rate_level_columns );
⋮----
$segments = $this->get_order_related_segments( $type, $segmenting_select, $segmenting_from, $segmenting_where, $segmenting_groupby, $table_name, $query_params );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Taxes/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Taxes;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\ExportableInterface;
use Automattic\WooCommerce\Admin\API\Reports\ExportableTraits;
use Automattic\WooCommerce\Admin\API\Reports\GenericController;
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends GenericController implements ExportableInterface {
⋮----
protected $rest_base = 'reports/taxes';
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
protected function prepare_reports_query( $request ) {
⋮----
public function prepare_item_for_response( $report, $request ) {
$response = parent::prepare_item_for_response( $report, $request );
⋮----
$response->add_links( $this->prepare_links( $report ) );
⋮----
protected function prepare_links( $object ) {
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
⋮----
... (20 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Taxes/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Taxes;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
use Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
use Automattic\WooCommerce\Enums\OrderItemType;
⋮----
class DataStore extends ReportsDataStore implements DataStoreInterface {
⋮----
protected static $table_name = 'wc_order_tax_lookup';
⋮----
protected $cache_key = 'taxes';
⋮----
protected $column_types = array(
⋮----
protected $context = 'taxes';
⋮----
public function __construct() {
$this->date_column_name = $this->sanitize_date_column_name( get_option( 'woocommerce_date_type' ), 'date_paid' );
parent::__construct();
⋮----
protected function assign_report_columns() {
⋮----
$table_name = self::get_db_table_name();
⋮----
if ( ! static::has_taxable_amount_column() ) {
⋮----
public static function has_taxable_amount_column() {
... (146 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Taxes/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Taxes;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Query as ReportsQuery;
⋮----
class Query extends ReportsQuery {
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
⋮----
$args = apply_filters( 'woocommerce_analytics_taxes_query_args', $this->get_query_vars() );
⋮----
$data_store = \WC_Data_Store::load( 'report-taxes' );
$results    = $data_store->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Variations/Stats/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Variations\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
use Automattic\WooCommerce\Admin\API\Reports\GenericStatsController;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends GenericStatsController {
⋮----
protected $rest_base = 'reports/variations/stats';
⋮----
protected $param_mapping = array(
⋮----
public function __construct() {
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
protected function prepare_reports_query( $request ) {
⋮----
$collection_params = apply_filters( 'experimental_woocommerce_analytics_variations_stats_collection_params', $this->get_collection_params() );
⋮----
public function prepare_item_for_response( $report, $request ) {
$response = parent::prepare_item_for_response( $report, $request );
⋮----
protected function get_item_properties_schema() {
⋮----
public function get_item_schema() {
$schema          = parent::get_item_schema();
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Variations/Stats/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Variations\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Variations\DataStore as VariationsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\Admin\API\Reports\StatsDataStoreTrait;
⋮----
class DataStore extends VariationsDataStore implements DataStoreInterface {
⋮----
protected $column_types = array(
⋮----
protected $cache_key = 'variations_stats';
⋮----
protected $context = 'variations_stats';
⋮----
protected function assign_report_columns() {
$table_name           = self::get_db_table_name();
⋮----
protected function update_sql_query_params( $query_args ) {
⋮----
$order_product_lookup_table = self::get_db_table_name();
⋮----
$included_products = $this->get_included_products( $query_args );
⋮----
$excluded_products = $this->get_excluded_products( $query_args );
⋮----
$included_variations = $this->get_included_variations( $query_args );
⋮----
} elseif ( $this->should_exclude_simple_products( $query_args ) ) {
⋮----
... (79 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Variations/Stats/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Variations\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Query as ReportsQuery;
⋮----
class Query extends ReportsQuery {
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
⋮----
$args = apply_filters( 'woocommerce_analytics_variations_stats_query_args', $this->get_query_vars() );
⋮----
$data_store = \WC_Data_Store::load( 'report-variations-stats' );
$results    = $data_store->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Variations/Stats/Segmenter.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Variations\Stats;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Segmenter as ReportsSegmenter;
use Automattic\WooCommerce\Admin\API\Reports\ParameterException;
⋮----
class Segmenter extends ReportsSegmenter {
⋮----
protected function get_segment_selections_product_level( $products_table ) {
⋮----
protected function get_product_related_totals_segments( $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $totals_query, $unique_orders_table ) {
⋮----
$segments_products = $wpdb->get_results(
⋮----
$totals_segments = $this->merge_segment_totals_results( $segmenting_dimension_name, $segments_products, array() );
⋮----
protected function get_product_related_intervals_segments( $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $intervals_query, $unique_orders_table ) {
⋮----
$segment_count    = count( $this->get_all_segments() );
⋮----
$segmenting_limit = $wpdb->prepare( 'LIMIT %d, %d', $orig_offset * $segment_count, $orig_rowcount * $segment_count );
⋮----
$intervals_segments = $this->merge_segment_intervals_results( $segmenting_dimension_name, $segments_products, array() );
⋮----
protected function get_segments( $type, $query_params, $table_name ) {
⋮----
// Product, variation, and category are bound to product, so here product segmenting table is required,
// while coupon and customer are bound to order, so we don't need the extra JOIN for those.
⋮----
$product_level_columns     = $this->get_segment_selections_product_level( $product_segmenting_table );
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Variations/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Variations;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\ExportableInterface;
use Automattic\WooCommerce\Admin\API\Reports\ExportableTraits;
use Automattic\WooCommerce\Admin\API\Reports\GenericController;
use Automattic\WooCommerce\Admin\API\Reports\GenericQuery;
use Automattic\WooCommerce\Admin\API\Reports\OrderAwareControllerTrait;
⋮----
class Controller extends GenericController implements ExportableInterface {
⋮----
protected $rest_base = 'reports/variations';
⋮----
protected $param_mapping = array(
⋮----
protected function get_datastore_data( $query_args = array() ) {
⋮----
return $query->get_data();
⋮----
public function prepare_item_for_response( $report, $request ) {
⋮----
$response = parent::prepare_item_for_response( $report, $request );
⋮----
$response->add_links( $this->prepare_links( $report ) );
⋮----
protected function prepare_reports_query( $request ) {
⋮----
$this->get_collection_params()
⋮----
protected function prepare_links( $object ) {
⋮----
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Variations/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Variations;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
⋮----
class DataStore extends ReportsDataStore implements DataStoreInterface {
⋮----
protected static $table_name = 'wc_order_product_lookup';
⋮----
protected $cache_key = 'variations';
⋮----
protected $column_types = array(
⋮----
protected $extended_attributes = array(
⋮----
protected $context = 'variations';
⋮----
protected function assign_report_columns() {
$table_name           = self::get_db_table_name();
⋮----
protected function add_from_sql_params( $query_args, $arg_name ) {
⋮----
$table_name = self::get_db_table_name();
⋮----
$this->subquery->add_sql_clause( 'join', $join );
⋮----
$this->add_sql_clause( 'join', $join );
⋮----
protected function get_order_item_by_attribute_subquery( $query_args ) {
... (126 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Variations/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports\Variations;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Query as ReportsQuery;
⋮----
class Query extends ReportsQuery {
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
⋮----
$args = apply_filters( 'woocommerce_analytics_variations_query_args', $this->get_query_vars() );
⋮----
$data_store = \WC_Data_Store::load( 'report-variations' );
$results    = $data_store->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Cache.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
class Cache {
⋮----
public static function invalidate() {
\WC_Cache_Helper::get_transient_version( self::VERSION_OPTION, true );
⋮----
public static function get_version() {
$version = \WC_Cache_Helper::get_transient_version( self::VERSION_OPTION );
⋮----
public static function get( $key ) {
$transient_version = self::get_version();
⋮----
public static function set( $key, $value ) {
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Controller.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericController;
use Automattic\WooCommerce\Admin\API\Reports\OrderAwareControllerTrait;
⋮----
class Controller extends GenericController {
⋮----
public function get_items( $request ) {
⋮----
$item   = $this->prepare_item_for_response( (object) $report, $request );
$data[] = $this->prepare_response_for_collection( $item );
⋮----
public function prepare_item_for_response( $report, $request ) {
⋮----
$response = parent::prepare_item_for_response( $data, $request );
$response->add_links(
⋮----
public function get_item_schema() {
⋮----
return $this->add_additional_fields_schema( $schema );
⋮----
public function get_collection_params() {
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/DataStore.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
class DataStore extends SqlQuery implements DataStoreInterface {
⋮----
protected $cache_group = 'reports';
⋮----
protected $cache_timeout = 3600;
⋮----
protected $cache_key = '';
⋮----
/**
	 * Table used as a data store for this report.
	 *
	 * @var string
	 */
protected static $table_name = '';
⋮----
/**
	 * Date field name.
	 *
	 * @var string
	 */
protected $date_column_name = 'date_created';
⋮----
protected function sanitize_date_column_name( $column, $fallback = 'date_created' ) {
⋮----
... (390 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/DataStoreInterface.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
interface DataStoreInterface {
⋮----
public function get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/ExportableInterface.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
interface ExportableInterface {
⋮----
public function get_export_columns();
⋮----
public function prepare_item_for_export( $item );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/ExportableTraits.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
trait ExportableTraits {
⋮----
public static function csv_number_format( $value ) {
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/FilteredGetDataTrait.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
trait FilteredGetDataTrait {
⋮----
public function get_data( $query_args ) {
⋮----
$results = parent::get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/GenericController.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
use WP_REST_Request;
use WP_REST_Response;
⋮----
abstract class GenericController extends \WC_REST_Reports_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
public function add_pagination_headers( $request, $response, int $total, int $page, int $max_pages ) {
⋮----
$response->header( 'X-WP-Total', $total );
$response->header( 'X-WP-TotalPages', $max_pages );
⋮----
$request->get_query_params(),
⋮----
$response->link_header( 'prev', $prev_link );
⋮----
$response->link_header( 'next', $next_link );
⋮----
protected function get_datastore_data( $query_args = array() ) {
$data_store = \WC_Data_Store::load( $this->rest_base );
return $data_store->get_data( $query_args );
⋮----
public function get_collection_params() {
⋮----
$params['context']             = $this->get_context_param( array( 'default' => 'view' ) );
⋮----
public function get_items( $request ) {
$query_args  = $this->prepare_reports_query( $request );
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/GenericQuery.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
use WC_Data_Store;
⋮----
class GenericQuery extends \WC_Object_Query {
⋮----
protected $name;
⋮----
public function __construct( $args, $name = null ) {
⋮----
return parent::__construct( $args );
⋮----
protected function get_default_query_vars() {
⋮----
public function get_data() {
⋮----
$args = apply_filters( "woocommerce_analytics_{$snake_name}_query_args", $this->get_query_vars() );
⋮----
$data_store = \WC_Data_Store::load( "report-{$this->name}" );
$results    = $data_store->get_data( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/GenericStatsController.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\GenericController;
use WP_Error;
⋮----
abstract class GenericStatsController extends GenericController {
⋮----
public function get_collection_params() {
$params             = parent::get_collection_params();
⋮----
abstract protected function get_item_properties_schema();
⋮----
public function get_item_schema() {
$data_values = $this->get_item_properties_schema();
⋮----
public function get_items( $request ) {
$query_args = $this->prepare_reports_query( $request );
⋮----
$report_data = $this->get_datastore_data( $query_args );
⋮----
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
⋮----
$item                    = $this->prepare_item_for_response( $interval_data, $request );
$out_data['intervals'][] = $this->prepare_response_for_collection( $item );
⋮----
return $this->add_pagination_headers(
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/OrderAwareControllerTrait.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
trait OrderAwareControllerTrait {
⋮----
protected function get_order_number( $order_id ) {
⋮----
if ( ! $this->is_valid_order( $order ) ) {
⋮----
if ( 'shop_order_refund' === $order->get_type() ) {
$order = wc_get_order( $order->get_parent_id() );
⋮----
return $order->get_id();
⋮----
return $order->get_order_number();
⋮----
protected function is_valid_order( $order ) {
⋮----
protected function get_total_formatted( $order_id ) {
⋮----
return wp_strip_all_tags( html_entity_decode( $order->get_formatted_order_total() ), true );
⋮----
public static function get_order_statuses() {
⋮----
$default_actionable_statuses = Settings::get_default_actionable_order_statuses();
⋮----
$actionable_statuses = Settings::get_valid_order_statuses_or_default( $actionable_statuses, $default_actionable_statuses );
⋮----
$registered_statuses = array_merge( array( 'any', 'trash' ), array_keys( self::get_order_status_labels() ) );
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/ParameterException.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
class ParameterException extends \WC_Data_Exception {}
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Query.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
abstract class Query extends \WC_Object_Query {
⋮----
public function __construct( $args = array() ) {
⋮----
parent::__construct( $args );
⋮----
public function get_data() {
⋮----
return new \WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass.", 'woocommerce' ), __METHOD__ ), array( 'status' => 405 ) );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/Segmenter.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Coupons\DataStore as CouponsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\Taxes\Stats\DataStore as TaxesStatsDataStore;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\Admin\Reports\ProductSearchQuery;
⋮----
class Segmenter {
⋮----
protected $all_segment_ids = false;
⋮----
protected $segment_labels = array();
⋮----
protected $query_args = '';
⋮----
/**
	 * SQL definition for each column.
	 *
	 * @var array
	 */
protected $report_columns = array();
⋮----
/**
	 * Constructor.
	 *
	 * @param array $query_args Query arguments supplied by the user for data store.
	 * @param array $report_columns Report columns lookup from data store.
	 */
public function __construct( $query_args, $report_columns ) {
⋮----
... (91 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/SqlQuery.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
class SqlQuery {
⋮----
private $sql_clauses = array(
⋮----
private $sql_filters = array(
⋮----
protected $context;
⋮----
public function __construct( $context = '' ) {
⋮----
/**
	 * Add a SQL clause to be included when get_data is called.
	 *
	 * @param string $type   Clause type.
	 * @param string $clause SQL clause.
	 */
public function add_sql_clause( $type, $clause ) {
⋮----
/**
	 * Get SQL clause by type.
	 *
	 * @param string $type     Clause type.
	 * @param string $handling Whether to filter the return value (filtered|unfiltered). Default unfiltered.
	 *
	 * @return string SQL clause.
	 */
protected function get_sql_clause( $type, $handling = 'unfiltered' ) {
⋮----
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/StatsDataStoreTrait.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
⋮----
trait StatsDataStoreTrait {
⋮----
protected function initialize_queries() {
$this->clear_all_clauses();
⋮----
$table_name = self::get_db_table_name();
⋮----
$this->total_query->add_sql_clause( 'from', $table_name );
⋮----
$this->interval_query->add_sql_clause( 'from', $table_name );
$this->interval_query->add_sql_clause( 'group_by', 'time_interval' );
⋮----
public function get_noncached_data( $query_args ) {
$params                  = $this->get_limit_params( $query_args );
$expected_interval_count = TimeInterval::intervals_between( $query_args['after'], $query_args['before'], $query_args['interval'] );
⋮----
$data = $this->get_noncached_stats_data( $query_args, $params, $data, $expected_interval_count );
⋮----
$this->create_interval_subtotals( $data->intervals );
</file>

<file path="plugins/woocommerce/src/Admin/API/Reports/TimeInterval.php">
namespace Automattic\WooCommerce\Admin\API\Reports;
⋮----
class TimeInterval {
⋮----
public static $iso_datetime_format = 'Y-m-d\TH:i:s';
⋮----
public static $sql_datetime_format = 'Y-m-d H:i:s';
⋮----
public static function convert_local_datetime_to_gmt( $datetime_string ) {
$datetime = new \DateTime( $datetime_string, new \DateTimeZone( wc_timezone_string() ) );
$datetime->setTimezone( new \DateTimeZone( 'GMT' ) );
⋮----
public static function default_before() {
$datetime = new \WC_DateTime();
⋮----
$datetime->setTimezone( new \DateTimeZone( wc_timezone_string() ) );
⋮----
$datetime->set_utc_offset( wc_timezone_offset() );
⋮----
public static function default_after() {
⋮----
$datetime->setTimestamp( $week_back );
⋮----
public static function db_datetime_format( $time_interval, $table_name, $date_column_name = 'date_created' ) {
⋮----
public static function quarter( $datetime ) {
switch ( (int) $datetime->format( 'm' ) ) {
⋮----
public static function simple_week_number( $datetime, $first_day_of_week ) {
$beg_of_year_day          = new \DateTime( "{$datetime->format('Y')}-01-01" );
... (132 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/views/mobile-app-qr-login-signin-email.php">
// /qr-login-scan requires a device payload, so by the time this email
// renders we have at least an OS label. Prefer "{Brand} {Model}" when both
// are present; fall back to model alone, then to OS.
⋮----
<html lang="<?php echo $language; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- already escaped above. ?>">
⋮----
/* translators: %s: mobile app version, e.g. "24.7.0". */
</file>

<file path="plugins/woocommerce/src/Admin/API/ActivityPanelCounts.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
class ActivityPanelCounts extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
protected $rest_base = 'activity-panel/counts';
⋮----
public function register_routes(): void {
⋮----
'args'                => $this->get_counts_params(),
⋮----
public function get_counts( $request ) {
$order_statuses = (array) $request->get_param( 'order_statuses' );
⋮----
: $this->get_count_via(
⋮----
'reviews_to_moderate_count'   => $this->get_count_via(
⋮----
'status'   => $request->get_param( 'review_status' ),
⋮----
'products_low_in_stock_count' => $this->get_count_via(
⋮----
array( 'status' => $request->get_param( 'product_status' ) )
⋮----
private function get_count_via( $route, $params ) {
$sub_request = new \WP_REST_Request( 'GET', $route );
⋮----
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/AnalyticsImports.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use WP_Error;
use Automattic\WooCommerce\Internal\Admin\Schedulers\OrdersScheduler;
⋮----
class AnalyticsImports extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
protected $rest_base = 'imports';
⋮----
public function register_routes(): void {
⋮----
public function permissions_check( $request ) {
⋮----
public function get_status( $request ) {
$is_scheduled_mode = $this->is_scheduled_import_enabled();
⋮----
$failed_imports = OrdersScheduler::get_failed_order_imports();
⋮----
$response['next_scheduled']            = $this->get_next_scheduled_time();
$response['import_in_progress_or_due'] = $this->is_import_in_progress_or_due();
⋮----
public function trigger_import( $request ) {
⋮----
if ( $this->is_import_in_progress_or_due() ) {
⋮----
$action_hook = OrdersScheduler::get_action( OrdersScheduler::PROCESS_PENDING_ORDERS_BATCH_ACTION );
⋮----
WC()->queue()->cancel_all( $action_hook, array(), (string) OrdersScheduler::$group );
... (40 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Coupons.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class Coupons extends \WC_REST_Coupons_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
public function get_collection_params() {
$params           = parent::get_collection_params();
⋮----
protected function prepare_objects_query( $request ) {
$args = parent::prepare_objects_query( $request );
⋮----
public function get_items( $request ) {
⋮----
$response = parent::get_items( $request );
⋮----
public static function add_wp_query_search_code_filter( $where, $wp_query ) {
⋮----
$search = $wp_query->get( 'search' );
⋮----
$code_like = '%' . $wpdb->esc_like( $search ) . '%';
$where    .= $wpdb->prepare( "AND {$wpdb->posts}.post_title LIKE %s", $code_like );
</file>

<file path="plugins/woocommerce/src/Admin/API/CustomAttributeTraits.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
trait CustomAttributeTraits {
⋮----
public function get_custom_attribute_by_slug( $slug ) {
$matching_attributes = $this->get_custom_attributes( array( 'slug' => $slug ) );
⋮----
return new \WP_Error(
⋮----
protected function get_custom_attributes( $args ) {
⋮----
$like = '%"name";s:%:"%' . $wpdb->esc_like( $name ) . '%"%';
⋮----
$query_results = $wpdb->get_results(
$wpdb->prepare(
</file>

<file path="plugins/woocommerce/src/Admin/API/Customers.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class Customers extends \Automattic\WooCommerce\Admin\API\Reports\Customers\Controller {
⋮----
protected $rest_base = 'customers';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
protected function prepare_reports_query( $request ) {
$args              = parent::prepare_reports_query( $request );
⋮----
public function get_collection_params() {
$params            = parent::get_collection_params();
</file>

<file path="plugins/woocommerce/src/Admin/API/Data.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class Data extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
public function get_items( $request ) {
$response         = parent::get_items( $request );
$response->data[] = $this->prepare_response_for_collection(
$this->prepare_item_for_response(
</file>

<file path="plugins/woocommerce/src/Admin/API/DataCountries.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class DataCountries extends \WC_REST_Data_Countries_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
public function register_routes() {
⋮----
parent::register_routes();
⋮----
public function get_locales() {
$locales = WC()->countries->get_country_locale();
</file>

<file path="plugins/woocommerce/src/Admin/API/DataDownloadIPs.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class DataDownloadIPs extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
protected $rest_base = 'data/download-ips';
⋮----
public function register_routes() {
⋮----
public function get_items( $request ) {
⋮----
$downloads = $wpdb->get_results(
$wpdb->prepare(
⋮----
return new \WP_Error( 'woocommerce_rest_data_download_ips_invalid_request', __( 'Invalid request. Please pass the match parameter.', 'woocommerce' ), array( 'status' => 400 ) );
⋮----
$response = $this->prepare_item_for_response( $download, $request );
$data[]   = $this->prepare_response_for_collection( $response );
⋮----
public function prepare_item_for_response( $item, $request ) {
$data     = $this->add_additional_fields_to_object( $item, $request );
$data     = $this->filter_response_by_context( $data, 'view' );
⋮----
$response->add_links( $this->prepare_links( $item ) );
⋮----
protected function prepare_links( $item ) {
⋮----
public function get_collection_params() {
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Experiments.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class Experiments extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'experiments';
⋮----
public function register_routes() {
⋮----
public function get_assignment( $request ) {
$args = $request->get_query_params();
⋮----
return new \WP_Error(
⋮----
$abtest   = new \WooCommerce\Admin\Experimental_Abtest(
$request->get_param( 'anon_id' ) ?? '',
⋮----
$response = $abtest->request_assignment( $args );
</file>

<file path="plugins/woocommerce/src/Admin/API/Features.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\Features\Features as FeaturesClass;
⋮----
class Features extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'features';
⋮----
public function register_routes() {
⋮----
public function get_items_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function get_features( $request ) {
return FeaturesClass::get_available_features();
</file>

<file path="plugins/woocommerce/src/Admin/API/Init.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use AllowDynamicProperties;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
use Automattic\WooCommerce\Utilities\RestApiUtil;
⋮----
class Init {
⋮----
protected static $instance = null;
⋮----
final public static function instance() {
⋮----
public function __construct() {
⋮----
public function rest_api_init() {
⋮----
$this->rest_api_init_wc_admin();
⋮----
$rest_api_util = wc_get_container()->get( RestApiUtil::class );
$rest_api_util->lazy_load_namespace( 'wc-analytics', array( $this, 'rest_api_init_wc_analytics' ) );
⋮----
$this->$controller = new $controller();
$this->$controller->register_routes();
⋮----
public function rest_api_init_wc_admin() {
⋮----
public function rest_api_init_wc_analytics() {
⋮----
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/LaunchYourStore.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\WCAdminHelper;
⋮----
class LaunchYourStore {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'launch-your-store';
⋮----
public function register_routes() {
⋮----
public function must_be_shop_manager_or_admin() {
⋮----
public function initialize_coming_soon() {
⋮----
$store_pages_only = WCAdminHelper::is_site_fresh() ? 'no' : 'yes';
⋮----
public function get_woopay_test_orders_count() {
⋮----
return new \WP_REST_Response( array( 'count' => $count ) );
⋮----
return $return( count( $orders ) );
⋮----
public function delete_woopay_test_orders() {
⋮----
return new \WP_REST_Response( null, $status );
⋮----
$order->delete();
⋮----
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Leaderboards.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Categories\DataStore as CategoriesDataStore;
use Automattic\WooCommerce\Admin\API\Reports\Coupons\DataStore as CouponsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore as CustomersDataStore;
use Automattic\WooCommerce\Admin\API\Reports\Products\DataStore as ProductsDataStore;
⋮----
class Leaderboards extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
protected $rest_base = 'leaderboards';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
protected function get_coupons_leaderboard( $per_page, $after, $before, $persisted_query ) {
⋮----
$coupons_data       = $per_page > 0 ? $coupons_data_store->get_data(
⋮----
protected function get_categories_leaderboard( $per_page, $after, $before, $persisted_query ) {
⋮----
$categories_data       = $per_page > 0 ? $categories_data_store->get_data(
⋮----
protected function get_customers_leaderboard( $per_page, $after, $before, $persisted_query ) {
... (51 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Marketing.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Internal\Admin\Marketing\MarketingSpecs;
use Automattic\WooCommerce\Admin\Features\MarketingRecommendations\Init as MarketingRecommendationsInit;
⋮----
class Marketing extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'marketing';
⋮----
public function register_routes() {
⋮----
'per_page' => $this->get_collection_params()['per_page'],
⋮----
public function get_recommended_plugins_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_update', __( 'You do not have permissions to manage plugins. Please contact your site administrator.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function get_recommended_plugins( $request ) {
⋮----
$category      = ( ! empty( $request->get_param( 'category' ) ) ) ? $request->get_param( 'category' ) : 'marketing';
$all_plugins   = MarketingRecommendationsInit::get_recommended_plugins();
⋮----
$per_page      = $request->get_param( 'per_page' );
⋮----
if ( ! PluginsHelper::is_plugin_installed( $plugin['plugin'] ) && in_array( $category, $plugin_categories, true ) ) {
⋮----
public function get_knowledge_base_posts( $request ) {
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/MarketingCampaigns.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\Marketing\MarketingCampaign;
use Automattic\WooCommerce\Admin\Marketing\MarketingChannels as MarketingChannelsService;
use Automattic\WooCommerce\Admin\Marketing\Price;
use Automattic\WooCommerce\Enums\CurrencyPosition;
use WC_REST_Controller;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class MarketingCampaigns extends WC_REST_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'marketing/campaigns';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
⋮----
$marketing_channels_service = wc_get_container()->get( MarketingChannelsService::class );
⋮----
foreach ( $marketing_channels_service->get_registered_channels() as $channel ) {
foreach ( $channel->get_campaigns() as $campaign ) {
$response    = $this->prepare_item_for_response( $campaign, $request );
... (49 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/MarketingCampaignTypes.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\Marketing\MarketingCampaignType;
use Automattic\WooCommerce\Admin\Marketing\MarketingChannels as MarketingChannelsService;
use WC_REST_Controller;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class MarketingCampaignTypes extends WC_REST_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'marketing/campaign-types';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function get_collection_params() {
$params = parent::get_collection_params();
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
⋮----
$marketing_channels_service = wc_get_container()->get( MarketingChannelsService::class );
⋮----
foreach ( $marketing_channels_service->get_registered_channels() as $channel ) {
foreach ( $channel->get_supported_campaign_types() as $campaign_type ) {
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/MarketingChannels.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\Marketing\MarketingChannelInterface;
use Automattic\WooCommerce\Admin\Marketing\MarketingChannels as MarketingChannelsService;
use WC_REST_Controller;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class MarketingChannels extends WC_REST_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'marketing/channels';
⋮----
public function register_routes() {
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
⋮----
$marketing_channels_service = wc_get_container()->get( MarketingChannelsService::class );
⋮----
$channels = $marketing_channels_service->get_registered_channels();
⋮----
$response    = $this->prepare_item_for_response( $item, $request );
$responses[] = $this->prepare_response_for_collection( $response );
⋮----
public function prepare_item_for_response( $item, $request ) {
⋮----
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/MarketingOverview.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\Marketing\InstalledExtensions;
use Automattic\WooCommerce\Admin\PluginsHelper;
⋮----
class MarketingOverview extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'marketing/overview';
⋮----
public function register_routes() {
⋮----
public function activate_plugin( $request ) {
$plugin_slug = $request->get_param( 'plugin' );
⋮----
if ( ! PluginsHelper::is_plugin_installed( $plugin_slug ) ) {
return new \WP_Error( 'woocommerce_rest_invalid_plugin', __( 'Invalid plugin.', 'woocommerce' ), 404 );
⋮----
$result = activate_plugin( PluginsHelper::get_plugin_path_from_slug( $plugin_slug ) );
⋮----
return new \WP_Error( 'woocommerce_rest_invalid_plugin', __( 'The plugin could not be activated.', 'woocommerce' ), 500 );
⋮----
public function install_plugins_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_update', __( 'You do not have permissions to manage plugins. Please contact your site administrator.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function get_installed_plugins( $request ) {
return rest_ensure_response( InstalledExtensions::get_data() );
</file>

<file path="plugins/woocommerce/src/Admin/API/MarketingRecommendations.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\Features\MarketingRecommendations\Init as MarketingRecommendationsInit;
use WC_REST_Controller;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class MarketingRecommendations extends WC_REST_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'marketing/recommendations';
⋮----
public function register_routes() {
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
$category = $request->get_param( 'category' );
⋮----
$items = MarketingRecommendationsInit::get_recommended_marketing_channels();
⋮----
$items = MarketingRecommendationsInit::get_recommended_marketing_extensions_excluding_channels();
⋮----
$response    = $this->prepare_item_for_response( $item, $request );
$responses[] = $this->prepare_response_for_collection( $response );
⋮----
public function prepare_item_for_response( $item, $request ) {
⋮----
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/MobileAppMagicLink.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\Jetpack\Connection\Manager as Jetpack_Connection_Manager;
⋮----
class MobileAppMagicLink extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'mobile-app';
⋮----
public function register_routes() {
⋮----
parent::register_routes();
⋮----
public function send_magic_link() {
⋮----
if ( $jetpack_connection_manager->is_active() ) {
⋮----
$xml = new \Jetpack_IXR_Client(
⋮----
$xml->query( 'jetpack.sendMobileMagicLink', array( 'app' => 'woocommerce' ) );
if ( $xml->isError() ) {
return new \WP_Error(
⋮----
$xml->getErrorCode(),
$xml->getErrorMessage()
⋮----
return new \WP_Error( 'jetpack_not_connected', __( 'Jetpack is not connected.', 'woocommerce' ) );
</file>

<file path="plugins/woocommerce/src/Admin/API/MobileAppQRLogin.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\API\RateLimits\QRLoginRateLimits;
⋮----
class MobileAppQRLogin extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'mobile-app';
⋮----
public function register_routes() {
⋮----
parent::register_routes();
⋮----
public function get_items_permissions_check( $request ) {
⋮----
return new \WP_Error(
⋮----
private function are_application_passwords_available() {
⋮----
private function rest_ensure_nocache_response( array $data ): \WP_REST_Response {
⋮----
$response->header( $header_name, (string) $header_value );
⋮----
public function get_availability( $request ): \WP_REST_Response {
⋮----
$site_url     = $this->get_secure_site_url();
⋮----
$ap_available = $this->are_application_passwords_available();
⋮----
... (252 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/NoteActions.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\Notes as NotesFactory;
use Automattic\WooCommerce\Internal\Admin\Notes\NoteActionForbiddenException;
⋮----
class NoteActions extends Notes {
⋮----
public function register_routes() {
⋮----
public function trigger_note_action( $request ) {
$note = NotesFactory::get_note( $request->get_param( 'note_id' ) );
⋮----
return new \WP_Error(
⋮----
$note->set_is_read( true );
$note->save();
⋮----
$triggered_action = NotesFactory::get_action_by_id( $note, $request->get_param( 'action_id' ) );
⋮----
$triggered_note = NotesFactory::trigger_note_action( $note, $triggered_action );
⋮----
$e->getMessage(),
⋮----
$data = $triggered_note->get_data();
$data = $this->prepare_item_for_response( $data, $request );
$data = $this->prepare_response_for_collection( $data );
</file>

<file path="plugins/woocommerce/src/Admin/API/Notes.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\Notes as NotesRepository;
⋮----
class Notes extends \WC_REST_CRUD_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
protected $rest_base = 'admin/notes';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'enum' => Note::get_allowed_statuses(),
⋮----
public function get_item( $request ) {
$note = NotesRepository::get_note( $request->get_param( 'id' ) );
⋮----
return new \WP_Error(
⋮----
$data = $this->prepare_note_data_for_response( $note, $request );
⋮----
public function get_items( $request ) {
$query_args = $this->prepare_objects_query( $request );
⋮----
$notes = NotesRepository::get_notes( 'edit', $query_args );
⋮----
$note   = $this->prepare_item_for_response( $note_obj, $request );
... (116 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Notice.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\PluginsHelper;
⋮----
class Notice extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'notice';
⋮----
public function register_routes() {
⋮----
public function dissmiss_notice( $request ) {
⋮----
public function get_permission(): bool {
</file>

<file path="plugins/woocommerce/src/Admin/API/OnboardingFreeExtensions.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions\Init as RemoteFreeExtensions;
use WC_REST_Data_Controller;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
⋮----
class OnboardingFreeExtensions extends WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'onboarding/free-extensions';
⋮----
public function register_routes() {
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_available_extensions( $request ) {
$extensions = RemoteFreeExtensions::get_extensions();
</file>

<file path="plugins/woocommerce/src/Admin/API/OnboardingPlugins.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Internal\Jetpack\JetpackConnection;
use WC_REST_Data_Controller;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class OnboardingPlugins extends WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'onboarding/plugins';
⋮----
public function register_routes() {
⋮----
public function install_and_activate( WP_REST_Request $request ) {
⋮----
$response['install']  = PluginsHelper::install_plugins( $request->get_param( 'plugins' ) );
$response['activate'] = PluginsHelper::activate_plugins( $response['install']['installed'] );
⋮----
public function install_and_activate_async( WP_REST_Request $request ) {
$plugins = $request->get_param( 'plugins' );
$source  = $request->get_param( 'source' );
⋮----
WC()->queue()->add( 'woocommerce_plugins_install_and_activate_async_callback', array( $plugins, $job_id, $source ) );
⋮----
public function get_scheduled_installs( WP_REST_Request $request ) {
$job_id = $request->get_param( 'job_id' );
... (27 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/OnboardingProducts.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class OnboardingProducts extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'onboarding';
⋮----
public function register_routes() {
⋮----
public function create_products( $request ) {
⋮----
public function update_item_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_update', __( 'Sorry, you cannot create dummy products.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
</file>

<file path="plugins/woocommerce/src/Admin/API/OnboardingProductTypes.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProducts;
⋮----
class OnboardingProductTypes extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'onboarding/product-types';
⋮----
public function register_routes() {
⋮----
public function get_items_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function get_product_types( $request ) {
return OnboardingProducts::get_product_types_with_data();
</file>

<file path="plugins/woocommerce/src/Admin/API/OnboardingProfile.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile as Profile;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProducts;
use Automattic\Jetpack\Connection\Manager as Jetpack_Connection_Manager;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class OnboardingProfile extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'onboarding/profile';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function update_items_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function get_items( $request ) {
⋮----
$onboarding_data['industry'] = isset( $onboarding_data['industry'] ) ? $this->filter_industries( $onboarding_data['industry'] ) : null;
... (57 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/OnboardingTasks.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\DeprecatedExtendedTask;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskLists;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingIndustries;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
⋮----
class OnboardingTasks extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'onboarding/tasks';
⋮----
protected $duration_to_ms = array(
⋮----
public function register_routes() {
⋮----
$this->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE ),
⋮----
'enum' => TaskLists::get_list_ids(),
⋮----
'args'                => $this->get_task_list_params(),
⋮----
public function create_products_permission_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to create resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
... (148 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/OnboardingThemes.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class OnboardingThemes extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'onboarding/themes';
⋮----
public function register_routes() {
⋮----
public function install_item_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_update', __( 'Sorry, you cannot install themes.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function update_item_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_update', __( 'Sorry, you cannot manage themes.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function install_theme( $request ) {
⋮----
'name'   => $installed_themes[ $theme ]->get( 'Name' ),
⋮----
return new \WP_Error(
⋮----
$upgrader = new \Theme_Upgrader( new \Automatic_Upgrader_Skin() );
$result   = $upgrader->install( $api->download_link );
⋮----
public function activate_theme( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_invalid_theme', sprintf( __( 'Invalid theme %s.', 'woocommerce' ), $theme ), 404 );
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Options.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class Options extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'options';
⋮----
public function register_routes() {
⋮----
public function get_item_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'You must supply an array of options.', 'woocommerce' ), 500 );
⋮----
if ( ! $this->user_has_permission( $option, $request ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view these options.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function user_has_permission( $option, $request, $is_update = false ) {
$permissions = $this->get_option_permissions( $request );
⋮----
public function update_item_permissions_check( $request ) {
$params = $request->get_json_params();
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_update', __( 'You must supply an array of options and values.', 'woocommerce' ), 500 );
⋮----
if ( ! $this->user_has_permission( $option_name, $request, true ) ) {
return new \WP_Error( 'woocommerce_rest_cannot_update', __( 'Sorry, you cannot manage these options.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function get_option_permissions( $request ) {
$permissions = self::get_default_option_permissions();
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Orders.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Controller as ReportsController;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class Orders extends \WC_REST_Orders_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
public function get_collection_params() {
$params = parent::get_collection_params();
⋮----
$params['status']['items']['enum'] = ReportsController::get_order_statuses();
⋮----
protected function prepare_objects_query( $request ) {
$args = parent::prepare_objects_query( $request );
⋮----
$args = $this->search_partial_order_number( $request['number'], $args );
⋮----
private function search_partial_order_number( $number, $args ) {
⋮----
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
$order_table_name = OrdersTableDataStore::get_orders_table_name();
⋮----
$order_ids = $wpdb->get_col(
$wpdb->prepare(
⋮----
$wpdb->esc_like( absint( $partial_number ) ) . '%',
⋮----
... (32 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/PaymentGatewaySuggestions.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\DefaultPaymentGateways;
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\Init as Suggestions;
⋮----
class PaymentGatewaySuggestions extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'payment-gateway-suggestions';
⋮----
public function register_routes() {
⋮----
public function get_permission_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_update', __( 'You do not have permissions to manage plugins. Please contact your site administrator.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function user_can_manage_woocommerce() {
⋮----
return new \WP_Error( 'woocommerce_rest_invalid_user', __( 'You are not allowed to make this request.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function get_suggestions( $request ) {
⋮----
$should_display = Suggestions::should_display();
$force_default  = $request->get_param( 'force_default_suggestions' );
⋮----
return Suggestions::get_suggestions();
⋮----
return rest_ensure_response( Suggestions::get_suggestions( DefaultPaymentGateways::get_all() ) );
⋮----
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Plugins.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Admin\PluginsHelper;
⋮----
class Plugins extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'plugins';
⋮----
public function register_routes() {
⋮----
public function update_item_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_update', __( 'You do not have permissions to manage plugins. Please contact your site administrator.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function install_plugin( $request ) {
⋮----
return self::install_plugins( $request );
⋮----
public function install_plugins( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_invalid_plugins', __( 'Plugins must be a non-empty array.', 'woocommerce' ), 404 );
⋮----
$job_id = PluginsHelper::schedule_install_plugins( $plugins );
⋮----
$data = PluginsHelper::install_plugins( $plugins, null, $source );
⋮----
$plugin_data = PluginsHelper::get_plugin_data( $plugin_slug );
... (74 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/ProductAttributes.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class ProductAttributes extends \WC_REST_Product_Attributes_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
public function register_routes() {
parent::register_routes();
⋮----
public function get_collection_params() {
$params           = parent::get_collection_params();
⋮----
public function get_item_schema() {
$schema = parent::get_item_schema();
⋮----
public function get_item_by_slug( $request ) {
⋮----
$attributes = $this->get_custom_attribute_by_slug( $request['slug'] );
⋮----
$response_items = $this->format_custom_attribute_items_for_response( $attributes );
⋮----
protected function format_custom_attribute_items_for_response( $custom_attributes ) {
⋮----
$item_response->add_links( $this->prepare_links( (object) array( 'attribute_id' => $attribute_key ) ) );
$item_response = $this->prepare_response_for_collection(
⋮----
public function get_items( $request ) {
⋮----
return parent::get_items( $request );
⋮----
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/ProductAttributeTerms.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class ProductAttributeTerms extends \WC_REST_Product_Attribute_Terms_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
public function register_routes() {
parent::register_routes();
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function get_custom_attribute_permissions_check( $request ) {
⋮----
public function get_item_schema() {
$schema = parent::get_item_schema();
⋮----
protected function get_custom_attribute_values( $slug ) {
⋮----
$attribute = $this->get_custom_attribute_by_slug( $slug );
⋮----
$query_results = $wpdb->get_results(
$wpdb->prepare(
⋮----
$response->add_links(
⋮----
$response = $this->prepare_response_for_collection( $response );
⋮----
public function get_item_by_slug( $request ) {
return $this->get_custom_attribute_values( $request['slug'] );
</file>

<file path="plugins/woocommerce/src/Admin/API/ProductCategories.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class ProductCategories extends \WC_REST_Product_Categories_Controller {
⋮----
protected $namespace = 'wc-analytics';
</file>

<file path="plugins/woocommerce/src/Admin/API/ProductForm.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Internal\Admin\ProductForm\FormFactory;
⋮----
class ProductForm extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'product-form';
⋮----
public function register_routes() {
⋮----
public function get_product_form_permission_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_create', __( 'Sorry, you are not allowed to retrieve product form data.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function get_fields( $request ) {
⋮----
return $field->get_json();
⋮----
FormFactory::get_fields()
⋮----
public function get_form_config( $request ) {
⋮----
return $subsection->get_json();
⋮----
FormFactory::get_subsections()
⋮----
return $section->get_json();
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/ProductReviews.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class ProductReviews extends \WC_REST_Product_Reviews_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
protected function prepare_links( $review ) {
</file>

<file path="plugins/woocommerce/src/Admin/API/Products.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
⋮----
class Products extends \WC_REST_Products_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
protected $last_order_dates = array();
⋮----
public function get_item_schema() {
$schema = parent::get_item_schema();
⋮----
public function get_collection_params() {
$params                 = parent::get_collection_params();
⋮----
protected function prepare_objects_query( $request ) {
$args = parent::prepare_objects_query( $request );
⋮----
public function get_items( $request ) {
⋮----
$response = parent::get_items( $request );
⋮----
if ( $this->is_low_in_stock_request( $request ) ) {
$response->header( 'Cache-Control', 'max-age=300' );
⋮----
private function is_low_in_stock_request( $request ) {
⋮----
$request->get_param( 'low_in_stock' ) === true &&
$request->get_param( 'page' ) === 1 &&
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/ProductsLowInStock.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
final class ProductsLowInStock extends \WC_REST_Products_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
'args'                => $this->get_low_in_stock_count_params(),
⋮----
public function get_low_in_stock_count( $request ) {
$status              = $request->get_param( 'status' );
⋮----
$sidewide_stock_threshold_only = $this->is_using_sitewide_stock_threshold_only( $low_stock_threshold );
$total_results                 = $this->get_count( $sidewide_stock_threshold_only, $status, $low_stock_threshold );
⋮----
$response->header( 'X-WP-Total', $total_results );
$response->header( 'X-WP-TotalPages', 0 );
⋮----
public function get_items( $request ) {
$query_results = $this->get_low_in_stock_products(
$request->get_param( 'page' ),
$request->get_param( 'per_page' ),
$request->get_param( 'status' )
⋮----
... (72 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/ProductVariations.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class ProductVariations extends \WC_REST_Product_Variations_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
public function register_routes() {
parent::register_routes();
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function get_collection_params() {
$params           = parent::get_collection_params();
⋮----
public static function add_wp_query_filter( $where, $wp_query ) {
⋮----
$search = $wp_query->get( 'search' );
⋮----
$like       = '%' . $wpdb->esc_like( $search ) . '%';
⋮----
$wpdb->prepare( "{$wpdb->posts}.post_title LIKE %s", $like ),
$wpdb->prepare( 'attr_search_meta.meta_value LIKE %s', $like ),
⋮----
$conditions[] = $wpdb->prepare( 'wc_product_meta_lookup.sku LIKE %s', $like );
⋮----
public static function add_wp_query_join( $join, $wp_query ) {
⋮----
protected function prepare_objects_query( $request ) {
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/SettingOptions.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
⋮----
class SettingOptions extends \WC_REST_Setting_Options_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
public function batch_items( $request ) {
⋮----
ReportsCache::invalidate();
⋮----
return parent::batch_items( $request );
</file>

<file path="plugins/woocommerce/src/Admin/API/Settings.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class Settings {
⋮----
public function register_routes(): void {}
</file>

<file path="plugins/woocommerce/src/Admin/API/ShippingPartnerSuggestions.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\Features\ShippingPartnerSuggestions\DefaultShippingPartners;
use Automattic\WooCommerce\Admin\Features\ShippingPartnerSuggestions\ShippingPartnerSuggestions as Suggestions;
⋮----
class ShippingPartnerSuggestions extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'shipping-partner-suggestions';
⋮----
public function register_routes() {
⋮----
public function get_permission_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_update', __( 'You do not have permissions to manage plugins. Please contact your site administrator.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
private function should_display() {
⋮----
public function get_suggestions( $request ) {
$should_display = $this->should_display();
$force_default  = $request->get_param( 'force_default_suggestions' );
⋮----
return Suggestions::get_suggestions();
⋮----
return rest_ensure_response( Suggestions::get_suggestions( DefaultShippingPartners::get_all() ) );
⋮----
public static function get_suggestions_schema() {
</file>

<file path="plugins/woocommerce/src/Admin/API/Taxes.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
class Taxes extends \WC_REST_Taxes_Controller {
⋮----
protected $namespace = 'wc-analytics';
⋮----
public function get_collection_params() {
$params            = parent::get_collection_params();
⋮----
public function get_items( $request ) {
⋮----
// Filter by tax code.
⋮----
$code_like = '%' . $wpdb->esc_like( $tax_code_search ) . '%';
$query    .= $wpdb->prepare( ' AND CONCAT_WS( "-", NULLIF(tax_rate_country, ""), NULLIF(tax_rate_state, ""), NULLIF(tax_rate_name, ""), NULLIF(tax_rate_priority, "") ) LIKE %s', $code_like );
⋮----
// Filter by included tax rate IDs.
⋮----
$results = $wpdb->get_results( $query . $order_by . $pagination );
⋮----
$data    = $this->prepare_item_for_response( $tax, $request );
$taxes[] = $this->prepare_response_for_collection( $data );
⋮----
$wpdb->get_results( str_replace( 'SELECT *', 'SELECT tax_rate_id', $query ) );
⋮----
$response->header( 'X-WP-Total', (int) $total_taxes );
⋮----
$response->header( 'X-WP-TotalPages', (int) $max_pages );
⋮----
$base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) );
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/API/Themes.php">
namespace Automattic\WooCommerce\Admin\API;
⋮----
use Automattic\WooCommerce\Admin\Overrides\ThemeUpgrader;
use Automattic\WooCommerce\Admin\Overrides\ThemeUpgraderSkin;
⋮----
class Themes extends \WC_REST_Data_Controller {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $rest_base = 'themes';
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function upload_theme_permissions_check( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you are not allowed to install themes on this site.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function upload_theme( $request ) {
⋮----
return new \WP_Error( 'woocommerce_rest_invalid_file', __( 'Specified file failed upload test.', 'woocommerce' ) );
⋮----
$file_upload     = new \File_Upload_Upgrader( 'pluginzip', 'package' );
⋮----
$install         = $upgrader->install( $file_upload->package );
⋮----
$file_upload->cleanup();
⋮----
if ( is_wp_error( $install ) && $install->get_error_code() ) {
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/BlockTemplates/BlockContainerInterface.php">
namespace Automattic\WooCommerce\Admin\BlockTemplates;
⋮----
interface BlockContainerInterface extends BlockInterface, ContainerInterface {}
</file>

<file path="plugins/woocommerce/src/Admin/BlockTemplates/BlockInterface.php">
namespace Automattic\WooCommerce\Admin\BlockTemplates;
⋮----
interface BlockInterface {
</file>

<file path="plugins/woocommerce/src/Admin/BlockTemplates/BlockTemplateInterface.php">
namespace Automattic\WooCommerce\Admin\BlockTemplates;
⋮----
interface BlockTemplateInterface extends ContainerInterface {}
</file>

<file path="plugins/woocommerce/src/Admin/BlockTemplates/ContainerInterface.php">
namespace Automattic\WooCommerce\Admin\BlockTemplates;
⋮----
interface ContainerInterface {}
</file>

<file path="plugins/woocommerce/src/Admin/BlockTemplates/README.md">
# BlockTemplates compatibility shims

This folder contains temporary compatibility shims for PHP interfaces that were part of the removed Block Templates API.

The Block Templates extension APIs were deprecated in WooCommerce 10.9.0, and the Block Templates API was removed in WooCommerce 11.0.0 with no replacement. These interfaces remain only to avoid fatal errors in extensions or custom code that still reference the old PHP symbols during the transition period.

Do not add new Block Templates behavior here. Any code in this folder should be limited to compatibility with the removed APIs, should avoid reintroducing the removed template system, and may be removed in a future WooCommerce version.
</file>

<file path="plugins/woocommerce/src/Admin/Composer/Package.php">
namespace Automattic\WooCommerce\Admin\Composer;
⋮----
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Admin\Notes\NotesUnavailableException;
use Automattic\WooCommerce\Internal\Admin\FeaturePlugin;
⋮----
class Package {
⋮----
private static $package_active = false;
⋮----
private static $active_version = null;
⋮----
public static function init() {
⋮----
$feature_plugin_instance = FeaturePlugin::instance();
⋮----
$feature_plugin_instance->init();
⋮----
public static function get_version() {
⋮----
public static function get_active_version() {
⋮----
public static function is_package_active() {
⋮----
public static function get_path() {
⋮----
private static function is_notes_initialized() {
⋮----
Notes::load_data_store();
</file>

<file path="plugins/woocommerce/src/Admin/DateTimeProvider/CurrentDateTimeProvider.php">
namespace Automattic\WooCommerce\Admin\DateTimeProvider;
⋮----
use Automattic\WooCommerce\Admin\DateTimeProvider\DateTimeProviderInterface;
⋮----
class CurrentDateTimeProvider implements DateTimeProviderInterface {
⋮----
public function get_now() {
return new \DateTime();
</file>

<file path="plugins/woocommerce/src/Admin/DateTimeProvider/DateTimeProviderInterface.php">
namespace Automattic\WooCommerce\Admin\DateTimeProvider;
⋮----
interface DateTimeProviderInterface {
⋮----
public function get_now();
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCCoreProfilerOptions.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\Exporters\StepExporter;
use Automattic\WooCommerce\Blueprint\Exporters\HasAlias;
use Automattic\WooCommerce\Blueprint\Steps\SetSiteOptions;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ExportWCCoreProfilerOptions implements StepExporter, HasAlias {
⋮----
public function export() {
⋮----
'blogname'                       => $this->wp_get_option( 'blogname' ),
'woocommerce_allow_tracking'     => $this->wp_get_option( 'woocommerce_allow_tracking' ),
'woocommerce_onboarding_profile' => $this->wp_get_option( 'woocommerce_onboarding_profile', array() ),
'woocommerce_default_country'    => $this->wp_get_option( 'woocommerce_default_country' ),
⋮----
public function get_step_name() {
⋮----
public function get_alias() {
⋮----
public function get_label() {
⋮----
public function get_description() {
⋮----
public function check_step_capabilities(): bool {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCPaymentGateways.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\Exporters\StepExporter;
use Automattic\WooCommerce\Blueprint\Steps\SetSiteOptions;
use Automattic\WooCommerce\Blueprint\Steps\Step;
⋮----
class ExportWCPaymentGateways implements StepExporter {
⋮----
protected array $exclude_ids = array( 'pre_install_woocommerce_payments_promotion' );
⋮----
public function export(): Step {
⋮----
public function get_wc_payment_gateways() {
return WC()->payment_gateways->payment_gateways();
⋮----
public function get_step_name() {
⋮----
protected function maybe_hide_wcpay_gateways() {
⋮----
\WC_Payments::hide_gateways_on_settings_page();
⋮----
public function get_label() {
⋮----
public function get_description() {
⋮----
public function check_step_capabilities(): bool {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettings.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Admin\Features\Blueprint\SettingOptions;
use Automattic\WooCommerce\Blueprint\Exporters\HasAlias;
use Automattic\WooCommerce\Blueprint\Exporters\StepExporter;
use Automattic\WooCommerce\Blueprint\Steps\SetSiteOptions;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
abstract class ExportWCSettings implements StepExporter, HasAlias {
⋮----
protected $setting_options;
⋮----
public function __construct( ?SettingOptions $setting_options = null ) {
⋮----
abstract protected function get_page_id(): string;
⋮----
public function export() {
return new SetSiteOptions( $this->setting_options->get_page_options( $this->get_page_id() ) );
⋮----
public function get_step_name() {
⋮----
public function get_alias() {
⋮----
public function get_label() {
⋮----
public function get_description() {
⋮----
public function check_step_capabilities(): bool {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettingsAccount.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ExportWCSettingsAccount extends ExportWCSettings {
⋮----
public function get_alias() {
⋮----
public function get_label() {
⋮----
public function get_description() {
⋮----
protected function get_page_id(): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettingsAdvanced.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ExportWCSettingsAdvanced extends ExportWCSettings {
⋮----
public function get_alias() {
⋮----
public function get_label() {
⋮----
public function get_description() {
⋮----
protected function get_page_id(): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettingsEmails.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Admin\Features\Blueprint\SettingOptions;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
use Automattic\WooCommerce\Blueprint\Steps\SetSiteOptions;
⋮----
class ExportWCSettingsEmails extends ExportWCSettings {
⋮----
public function get_alias() {
⋮----
public function export() {
$emails          = \WC_Emails::instance();
⋮----
$email_settings = $setting_options->get_page_options( $this->get_page_id() );
⋮----
foreach ( $emails->get_emails() as $email ) {
⋮----
$setting_options->get_page_options( 'email_' . $email->id )
⋮----
public function get_label() {
⋮----
public function get_description() {
⋮----
protected function get_page_id(): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettingsGeneral.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ExportWCSettingsGeneral extends ExportWCSettings {
⋮----
public function get_alias() {
⋮----
public function get_label() {
⋮----
public function get_description() {
⋮----
protected function get_page_id(): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettingsIntegrations.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\Steps\SetSiteOptions;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ExportWCSettingsIntegrations extends ExportWCSettings {
⋮----
public function get_alias() {
⋮----
public function get_label() {
⋮----
public function export() {
⋮----
$integrations = WC()->integrations->get_integrations();
⋮----
$option_key              = $integration->get_option_key();
⋮----
public function get_description() {
⋮----
protected function get_page_id(): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettingsProducts.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ExportWCSettingsProducts extends ExportWCSettings {
⋮----
public function get_alias() {
⋮----
public function get_label() {
⋮----
public function get_description() {
⋮----
protected function get_page_id(): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettingsShipping.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\Steps\RunSql;
use Automattic\WooCommerce\Blueprint\Steps\SetSiteOptions;
⋮----
class ExportWCSettingsShipping extends ExportWCSettings {
⋮----
public function export(): array {
$shipping_settings = parent::export();
⋮----
$this->get_steps_for_classes_and_terms(),
$this->get_steps_for_zones(),
$this->get_steps_for_locations(),
$this->get_steps_for_methods_and_options()
⋮----
$steps[] = $this->get_step_for_local_pickup();
⋮----
protected function get_terms( array $classes ): array {
⋮----
return ! empty( $term_ids ) ? $wpdb->get_results(
$wpdb->prepare(
⋮----
protected function get_steps_for_classes_and_terms(): array {
⋮----
$classes = $wpdb->get_results(
⋮----
fn( $class_row ) => RunSql::from_table_row( $class_row, 'term_taxonomy' ),
⋮----
fn( $term ) => RunSql::from_table_row( $term, 'terms' ),
$this->get_terms( $classes )
... (35 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettingsSiteVisibility.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\Exporters\HasAlias;
use Automattic\WooCommerce\Blueprint\Exporters\StepExporter;
use Automattic\WooCommerce\Blueprint\Steps\SetSiteOptions;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ExportWCSettingsSiteVisibility implements StepExporter, HasAlias {
⋮----
public function export() {
⋮----
'woocommerce_coming_soon'      => $this->wp_get_option( 'woocommerce_coming_soon' ),
'woocommerce_store_pages_only' => $this->wp_get_option( 'woocommerce_store_pages_only' ),
⋮----
public function get_alias() {
⋮----
public function get_label() {
⋮----
public function get_description() {
⋮----
public function get_step_name() {
⋮----
public function check_step_capabilities(): bool {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCSettingsTax.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
use Automattic\WooCommerce\Blueprint\Steps\RunSql;
use Automattic\WooCommerce\Admin\Features\Blueprint\SettingOptions;
⋮----
class ExportWCSettingsTax extends ExportWCSettings {
⋮----
public function __construct( ?SettingOptions $setting_options = null ) {
parent::__construct( $setting_options );
⋮----
public function get_alias() {
⋮----
public function export(): array {
$basic_tax_settings = parent::export();
⋮----
...$this->generateTaxRateSteps( 'wc_tax_rate_classes' ),
...$this->generateTaxRateSteps( 'woocommerce_tax_rates' ),
...$this->generateTaxRateSteps( 'woocommerce_tax_rate_locations' ),
⋮----
public function get_label() {
⋮----
public function get_description() {
⋮----
protected function get_page_id(): string {
⋮----
private function generateTaxRateSteps( string $table ): array {
⋮----
fn( $record ) => RunSql::from_table_row( $record, $table ),
$wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i', $prefixed_table ), ARRAY_A ),
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Exporters/ExportWCTaskOptions.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint\Exporters;
⋮----
use Automattic\WooCommerce\Blueprint\Exporters\HasAlias;
use Automattic\WooCommerce\Blueprint\Exporters\StepExporter;
use Automattic\WooCommerce\Blueprint\Steps\SetSiteOptions;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class ExportWCTaskOptions implements StepExporter, HasAlias {
⋮----
public function export() {
⋮----
'woocommerce_admin_customize_store_completed' => $this->wp_get_option( 'woocommerce_admin_customize_store_completed', 'no' ),
'woocommerce_task_list_tracked_completed_actions' => $this->wp_get_option( 'woocommerce_task_list_tracked_completed_actions', array() ),
⋮----
public function get_step_name() {
⋮----
public function get_alias() {
⋮----
public function get_label() {
⋮----
public function get_description() {
⋮----
public function check_step_capabilities(): bool {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/Init.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint;
⋮----
use Automattic\WooCommerce\Admin\Features\Blueprint\Exporters\ExportWCSettingsAccount;
use Automattic\WooCommerce\Admin\Features\Blueprint\Exporters\ExportWCSettingsAdvanced;
use Automattic\WooCommerce\Admin\Features\Blueprint\Exporters\ExportWCSettingsEmails;
use Automattic\WooCommerce\Admin\Features\Blueprint\Exporters\ExportWCSettingsGeneral;
use Automattic\WooCommerce\Admin\Features\Blueprint\Exporters\ExportWCSettingsTax;
use Automattic\WooCommerce\Admin\Features\Blueprint\Exporters\ExportWCSettingsIntegrations;
use Automattic\WooCommerce\Admin\Features\Blueprint\Exporters\ExportWCSettingsProducts;
use Automattic\WooCommerce\Admin\Features\Blueprint\Exporters\ExportWCSettingsSiteVisibility;
use Automattic\WooCommerce\Admin\Features\Blueprint\Exporters\ExportWCSettingsShipping;
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Blueprint\Exporters\HasAlias;
use Automattic\WooCommerce\Blueprint\Exporters\StepExporter;
use Automattic\WooCommerce\Blueprint\UseWPFunctions;
⋮----
class Init {
⋮----
private array $initialized_exporters = array();
⋮----
public function __construct() {
⋮----
public function init_rest_api() {
( new RestApi() )->register_routes();
⋮----
public function get_woo_exporters() {
⋮----
$exporters[ $classname ]                   = $this->initialized_exporters[ $classname ] ?? new $classname();
⋮----
public function add_woo_exporters( array $exporters ) {
... (61 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/RestApi.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint;
⋮----
use Automattic\WooCommerce\Blueprint\Exporters\ExportInstallPluginSteps;
use Automattic\WooCommerce\Blueprint\Exporters\ExportInstallThemeSteps;
use Automattic\WooCommerce\Blueprint\ExportSchema;
use Automattic\WooCommerce\Blueprint\ImportStep;
use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonHelper;
use WP_Error;
⋮----
class RestApi {
⋮----
protected $namespace = 'wc-admin';
⋮----
protected $coming_soon_helper;
⋮----
public function __construct() {
⋮----
protected function get_max_file_size() {
⋮----
public function register_routes() {
⋮----
public function check_export_permission() {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot export WooCommerce Blueprints.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function check_import_permission() {
⋮----
return new \WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot import WooCommerce Blueprints.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
⋮----
public function export( $request ) {
... (47 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Blueprint/SettingOptions.php">
namespace Automattic\WooCommerce\Admin\Features\Blueprint;
⋮----
class SettingOptions {
⋮----
private $setting_option_controller;
⋮----
private $ignore_setting_types = array( 'title', 'sectionend', 'slotfill_placeholder', 'hidden' );
⋮----
public function __construct() {
$this->setting_option_controller = new \WC_REST_Setting_Options_Controller();
⋮----
public function get_page_options( $page_id ) {
$settings = $this->setting_option_controller->get_group_settings( $page_id );
⋮----
throw new \Exception( esc_html( $settings->get_error_message() ) );
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/DataStore/FulfillmentsDataStore.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\DataStore;
⋮----
use Automattic\WooCommerce\Admin\Features\Fulfillments\Fulfillment;
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
use WC_Meta_Data;
⋮----
class FulfillmentsDataStore extends \WC_Data_Store_WP implements \WC_Object_Data_Store_Interface, FulfillmentsDataStoreInterface {
⋮----
public function create( &$data ): void {
⋮----
if ( ! $data->get_entity_type() ) {
throw new \Exception( esc_html__( 'Invalid entity type.', 'woocommerce' ) );
⋮----
if ( ! $data->get_entity_id() ) {
throw new \Exception( esc_html__( 'Invalid entity ID.', 'woocommerce' ) );
⋮----
if ( ! FulfillmentUtils::is_valid_fulfillment_status( $data->get_status() ) ) {
throw new \Exception( esc_html__( 'Invalid fulfillment status.', 'woocommerce' ) );
⋮----
$this->validate_items( $data );
⋮----
$data->set_date_updated( current_time( 'mysql' ) );
⋮----
$is_fulfill_action = $data->get_is_fulfilled();
⋮----
$data->set_date_fulfilled( current_time( 'mysql' ) );
⋮----
$rows_inserted = $wpdb->insert(
⋮----
'entity_type'  => $data->get_entity_type(),
... (120 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/DataStore/FulfillmentsDataStoreInterface.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\DataStore;
⋮----
use Automattic\WooCommerce\Admin\Features\Fulfillments\Fulfillment;
⋮----
interface FulfillmentsDataStoreInterface {
⋮----
public function read_fulfillments( string $entity_type, string $entity_id ): array;
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/AbstractShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
abstract class AbstractShippingProvider {
⋮----
abstract public function get_key(): string;
⋮----
abstract public function get_name(): string;
⋮----
abstract public function get_icon(): string;
⋮----
abstract public function get_tracking_url( string $tracking_number ): string;
⋮----
public function get_shipping_from_countries(): array {
⋮----
public function get_shipping_to_countries(): array {
⋮----
public function can_ship_from( string $country_code ): bool {
return in_array( $country_code, $this->get_shipping_from_countries(), true );
⋮----
public function can_ship_to( string $country_code ): bool {
return in_array( $country_code, $this->get_shipping_to_countries(), true );
⋮----
public function can_ship_from_to( string $shipping_from, string $shipping_to ): bool {
return $this->can_ship_from( $shipping_from ) && $this->can_ship_to( $shipping_to );
⋮----
public function try_parse_tracking_number( string $tracking_number, string $shipping_from, string $shipping_to ): ?array {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/ACSCourierShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class ACSCourierShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/acs-courier.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/AmazonLogisticsShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class AmazonLogisticsShippingProvider extends AbstractShippingProvider {
⋮----
private array $operating_countries = array( 'US', 'CA', 'GB', 'DE', 'FR', 'BE', 'NL', 'IT', 'IN', 'MX', 'JP', 'AU', 'ES', 'CN', 'HK', 'SG', 'GG', 'JE', 'IM', 'GI', 'AT', 'CH', 'PL', 'SE', 'DK', 'NO', 'FI', 'IE', 'PT', 'CZ', 'HU', 'RO', 'BG', 'HR', 'SK', 'SI', 'EE', 'LV', 'LT', 'CY', 'MT', 'LU', 'GR', 'BR', 'TR', 'AE', 'SA', 'EG', 'KW', 'IL', 'ZA', 'KR', 'TW', 'TH', 'MY', 'ID', 'PH', 'VN', 'NZ' );
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/amazon-logistics.png';
⋮----
public function get_shipping_from_countries(): array {
⋮----
public function get_shipping_to_countries(): array {
⋮----
public function can_ship_from_to( string $shipping_from, string $shipping_to ): bool {
⋮----
public function get_tracking_url( string $tracking_number ): string {
⋮----
public function try_parse_tracking_number(
⋮----
if ( empty( $tracking_number ) || ! $this->can_ship_from_to( $shipping_from, $shipping_to ) ) {
⋮----
// Amazon Logistics tracking number patterns with region/service differentiation.
⋮----
// North America patterns.
⋮----
'url'             => $this->get_tracking_url( $tracking_number ),
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/AnPostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class AnPostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/an-post.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/ArasKargoShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class ArasKargoShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/aras-kargo.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/AustraliaPostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
⋮----
class AustraliaPostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/australia-post.png';
⋮----
public function get_shipping_from_countries(): array {
⋮----
public function get_shipping_to_countries(): array {
⋮----
public function get_tracking_url( string $tracking_number ): string {
⋮----
private function validate_country_pattern( string $tracking_number, string $country_code ): bool {
⋮----
public function try_parse_tracking_number(
⋮----
// Australia Post ships only from Australia.
⋮----
if ( $this->validate_country_pattern( $normalized, $shipping_from ) ) {
⋮----
if ( FulfillmentUtils::validate_mod10_check_digit( $normalized ) ) {
⋮----
if ( FulfillmentUtils::check_s10_upu_format( $normalized ) ) {
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/AzerpostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class AzerpostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/azerpost.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/BartoliniBRTShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class BartoliniBRTShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/bartolini-brt.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/BelpochtaShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class BelpochtaShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/belpochta.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/BpostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class BpostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/bpost.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/BulgarianPostsShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class BulgarianPostsShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/bulgarian-posts.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/CanadaPostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
⋮----
class CanadaPostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/canada-post.png';
⋮----
public function get_shipping_from_countries(): array {
⋮----
public function get_shipping_to_countries(): array {
⋮----
public function get_tracking_url( string $tracking_number ): string {
⋮----
private function validate_country_pattern( string $tracking_number, string $country_code ): bool {
⋮----
public function try_parse_tracking_number(
⋮----
$normalized = strtoupper( preg_replace( '/\s+/', '', $tracking_number ) ); // Normalize input.
⋮----
// Check if shipping from Canada.
⋮----
if ( $this->validate_country_pattern( $normalized, $shipping_from ) ) {
⋮----
if ( FulfillmentUtils::check_s10_upu_format( $normalized ) ) {
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/CDEKShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class CDEKShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/cdek.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/CeskaPostaShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class CeskaPostaShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/ceska-posta.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/ChronopostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class ChronopostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/chronopost.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/CorreosShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class CorreosShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/correos.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/CTTShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class CTTShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/ctt.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/CustomShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class CustomShippingProvider extends AbstractShippingProvider {
⋮----
private string $key;
⋮----
private string $name;
⋮----
private string $icon;
⋮----
private string $tracking_url_template;
⋮----
public function __construct( string $key, string $name, string $icon, string $tracking_url_template ) {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
⋮----
public function get_tracking_url( string $tracking_number ): string {
⋮----
public function try_parse_tracking_number( string $tracking_number, string $shipping_from, string $shipping_to ): ?array {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/CyprusPostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class CyprusPostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/cyprus-post.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/DeutschePostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class DeutschePostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/deutsche-post.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/DHLShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
⋮----
class DHLShippingProvider extends AbstractShippingProvider {
⋮----
private array $major_operation_countries = array( 'DE', 'US', 'CA', 'GB', 'SG', 'JP', 'HK', 'NL', 'FR', 'IT', 'AU', 'CN', 'IN', 'ES', 'BE', 'CH', 'AT', 'SE', 'DK', 'NO', 'PL', 'CZ', 'FI', 'IE', 'PT', 'GR', 'HU', 'RO', 'BG', 'HR', 'SK', 'SI', 'LT', 'LV', 'EE', 'CY', 'MT', 'LU' );
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/dhl.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
⋮----
public function get_shipping_from_countries(): array {
⋮----
public function get_shipping_to_countries(): array {
return array_keys( wc()->countries->get_countries() );
⋮----
public function can_ship_from_to( string $shipping_from, string $shipping_to ): bool {
return in_array( $shipping_from, $this->get_shipping_from_countries(), true ) &&
in_array( $shipping_to, $this->get_shipping_to_countries(), true );
⋮----
public function try_parse_tracking_number( string $tracking_number, string $shipping_from, string $shipping_to ): ?array {
if ( empty( $tracking_number ) || ! $this->can_ship_from_to( $shipping_from, $shipping_to ) ) {
⋮----
$tracking_number  = strtoupper( preg_replace( '/\s+/', '', $tracking_number ) ); // Remove spaces and uppercase for consistency.
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/DPDShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class DPDShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/dpd.png';
⋮----
public function get_shipping_from_countries(): array {
⋮----
public function get_shipping_to_countries(): array {
return $this->get_shipping_from_countries();
⋮----
public function get_tracking_url( string $tracking_number ): string {
⋮----
private function validate_country_pattern( string $tracking_number, string $country_code ) {
⋮----
public function try_parse_tracking_number(
⋮----
// 1. Check international 28-digit format first.
⋮----
if ( in_array( $shipping_from, $this->get_shipping_from_countries(), true ) &&
in_array( $shipping_to, $this->get_shipping_to_countries(), true ) ) {
⋮----
'url'             => $this->get_tracking_url( $normalized ),
⋮----
$validation_result = $this->validate_country_pattern( $normalized, $shipping_from );
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/EcontShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class EcontShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/econt.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/EimskipShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class EimskipShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/eimskip.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/ELTAShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class ELTAShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/elta.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/EvriHermesShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class EvriHermesShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/evri-hermes.png';
⋮----
public function get_shipping_from_countries(): array {
⋮----
public function get_shipping_to_countries(): array {
⋮----
public function get_tracking_url( string $tracking_number ): string {
⋮----
public function try_parse_tracking_number(
⋮----
if ( ! $this->can_ship_from_to( $shipping_from, $shipping_to ) ) {
⋮----
// 1. Check for main 16-digit and legacy Evri/Hermes formats.
⋮----
// Boost for UK shipments.
⋮----
'url'             => $this->get_tracking_url( $normalized ),
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/FanCourierShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class FanCourierShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/fan-courier.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/FastwayShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class FastwayShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/fastway.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/FedExShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
⋮----
class FedExShippingProvider extends AbstractShippingProvider {
⋮----
private array $supported_countries = array( 'US', 'CA', 'GB', 'DE', 'FR', 'AU', 'JP', 'MX', 'CN', 'IN', 'IT', 'ES', 'NL', 'BE', 'CH', 'AT', 'BR', 'SG' );
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/fedex.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
⋮----
public function get_shipping_from_countries(): array {
⋮----
public function get_shipping_to_countries(): array {
⋮----
public function can_ship_from_to( string $shipping_from, string $shipping_to ): bool {
⋮----
public function try_parse_tracking_number( string $tracking_number, string $shipping_from, string $shipping_to ): ?array {
if ( empty( $tracking_number ) || ! $this->can_ship_from_to( $shipping_from, $shipping_to ) ) {
⋮----
$tracking_number  = strtoupper( preg_replace( '/\s+/', '', $tracking_number ) ); // Remove spaces and uppercase for consistency.
⋮----
if ( FulfillmentUtils::validate_fedex_check_digit( $tracking_number ) ) {
⋮----
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/GenikiTaxydromikiShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class GenikiTaxydromikiShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/geniki-taxydromiki.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/GLSShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class GLSShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/gls.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/HayPostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class HayPostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/haypost.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/HelthjemShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class HelthjemShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/helthjem.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/HrvatskaPostaShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class HrvatskaPostaShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/hrvatska-posta.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/InPostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class InPostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/inpost.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/IslandsposturShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class IslandsposturShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/islandspostur.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/ItellaShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class ItellaShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/itella.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/KazpostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class KazpostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/kazpost.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/LaPosteColissimoShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class LaPosteColissimoShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/la-poste-colissimo.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/LasershipOntracShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class LasershipOntracShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/lasership-ontrac.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/LatvijasPastsShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class LatvijasPastsShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/latvijas-pasts.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/LiechtensteinischePostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class LiechtensteinischePostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/liechtensteinische-post.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/MagyarPostaShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class MagyarPostaShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/magyar-posta.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/MakedonskaPostaShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class MakedonskaPostaShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/makedonska-posta.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/MaltaPostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class MaltaPostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/maltapost.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/MatkahuoltoShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class MatkahuoltoShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/matkahuolto.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/MondialRelayShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class MondialRelayShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/mondial-relay.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/MPLShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class MPLShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/mpl.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/MRWShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class MRWShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/mrw.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/NewZealandPostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class NewZealandPostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/new-zealand-post.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/NovaPoshtaShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class NovaPoshtaShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/nova-poshta.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/OmnivaShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class OmnivaShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/omniva.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/OsterreichischePostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class OsterreichischePostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/osterreichische-post.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/ParcelForceShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class ParcelForceShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/parcelforce.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/PocztaPolskaShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class PocztaPolskaShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/poczta-polska.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/PostaMoldoveiShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class PostaMoldoveiShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/posta-moldovei.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/PostaRomanaShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class PostaRomanaShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/posta-romana.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/PosteItalianeShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class PosteItalianeShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/poste-italiane.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/PostenNorgeBringShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class PostenNorgeBringShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/posten-norge-bring.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/PosteSanMarinoShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class PosteSanMarinoShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/poste-san-marino.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/PostLuxembourgShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class PostLuxembourgShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/post-luxembourg.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/PostNLShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class PostNLShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/postnl.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/PostNordShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class PostNordShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/postnord.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/PurolatorShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class PurolatorShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/purolator.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/RoyalMailShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
⋮----
class RoyalMailShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/royal-mail.png';
⋮----
public function get_shipping_from_countries(): array {
⋮----
public function get_shipping_to_countries(): array {
⋮----
public function get_tracking_url( string $tracking_number ): string {
⋮----
private function validate_country_pattern( string $tracking_number, string $country_code ): bool {
⋮----
public function try_parse_tracking_number(
⋮----
$normalized = strtoupper( preg_replace( '/\s+/', '', $tracking_number ) ); // Normalize input.
⋮----
// Check if shipping from UK.
⋮----
if ( $this->validate_country_pattern( $normalized, $shipping_from ) ) {
⋮----
if ( FulfillmentUtils::check_s10_upu_format( $normalized ) ) {
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/RussianPostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class RussianPostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/russian-post.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/SDAShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class SDAShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/sda.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/SeurShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class SeurShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/seur.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/SlovenskaPostaShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class SlovenskaPostaShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/slovenska-posta.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/SpeeDeeDeliveryShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class SpeeDeeDeliveryShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/spee-dee-delivery.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/StarTrackShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class StarTrackShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/startrack.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/SwissPostShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class SwissPostShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/swiss-post.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/TollShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class TollShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/toll.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/UkrposhtaShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class UkrposhtaShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/ukrposhta.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/UPSShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
⋮----
class UPSShippingProvider extends AbstractShippingProvider {
⋮----
private array $international_shipping_countries = array( 'AF', 'AX', 'AL', 'DZ', 'AS', 'AD', 'AO', 'AI', 'AQ', 'AG', 'AM', 'AW', 'AU', 'AT', 'AZ', 'BS', 'BH', 'BD', 'BB', 'BY', 'BE', 'BZ', 'BJ', 'BM', 'BT', 'BO', 'BQ', 'BA', 'BW', 'BV', 'BR', 'IO', 'BN', 'BG', 'BF', 'BI', 'CV', 'KH', 'CM', 'CA', 'KY', 'CF', 'TD', 'CL', 'CN', 'CX', 'CC', 'CO', 'KM', 'CD', 'CG', 'CK', 'CR', 'CI', 'HR', 'CU', 'CW', 'CY', 'CZ', 'DK', 'DJ', 'DM', 'DO', 'EC', 'EG', 'SV', 'GQ', 'ER', 'EE', 'SZ', 'ET', 'FK', 'FO', 'FJ', 'FI', 'FR', 'GF', 'PF', 'TF', 'GA', 'GM', 'GE', 'DE', 'GH', 'GI', 'GR', 'GL', 'GD', 'GP', 'GU', 'GT', 'GG', 'GN', 'GW', 'GY', 'HT', 'HM', 'VA', 'HN', 'HK', 'HU', 'IS', 'IN', 'ID', 'IR', 'IQ', 'IE', 'IM', 'IL', 'IT', 'JM', 'JP', 'JE', 'JO', 'KZ', 'KE', 'KI', 'KP', 'KR', 'KW', 'KG', 'LA', 'LV', 'LB', 'LS', 'LR', 'LY', 'LI', 'LT', 'LU', 'MO', 'MG', 'MW', 'MY', 'MV', 'ML', 'MT', 'MH', 'MQ', 'MR', 'MU', 'YT', 'MX', 'FM', 'MD', 'MC', 'MN', 'ME', 'MS', 'MA', 'MZ', 'MM', 'NA', 'NR', 'NP', 'NL', 'NC', 'NZ', 'NI', 'NE', 'NG', 'NU', 'NF', 'MK', 'MP', 'NO', 'OM', 'PK', 'PW', 'PS', 'PA', 'PG', 'PY', 'PE', 'PH', 'PN', 'PL', 'PT', 'PR', 'QA', 'RE', 'RO', 'RU', 'RW', 'BL', 'SH', 'KN', 'LC', 'MF', 'PM', 'VC', 'WS', 'SM', 'ST', 'SA', 'SN', 'RS', 'SC', 'SL', 'SG', 'SX', 'SK', 'SI', 'SB', 'SO', 'ZA', 'GS', 'SS', 'ES', 'LK', 'SD', 'SR', 'SJ', 'SE', 'CH', 'SY', 'TW', 'TJ', 'TZ', 'TH', 'TL', 'TG', 'TK', 'TO', 'TT', 'TN', 'TR', 'TM', 'TC', 'TV', 'UG', 'UA', 'AE', 'GB', 'US', 'UM', 'UY', 'UZ', 'VU', 'VE', 'VN', 'VG', 'VI', 'WF', 'EH', 'YE', 'ZM', 'ZW' );
⋮----
private array $domestic_shipping_countries = array( 'US', 'CA', 'MX', 'BR', 'AR', 'CL', 'CO', 'PE', 'CR', 'PR', 'DE', 'GB', 'FR', 'IT', 'ES', 'NL', 'BE', 'PL', 'SE', 'DK', 'AT', 'CH', 'PT', 'IE', 'CZ', 'HU', 'FI', 'NO', 'CN', 'HK', 'IN', 'JP', 'KR', 'SG', 'MY', 'TH', 'VN', 'PH', 'AU', 'NZ', 'AE', 'SA', 'ZA', 'TR', 'IL', 'KE', 'NG' );
⋮----
private array $domestic_but_international_tracking = array( 'IN', 'ZA', 'VN', 'NG', 'PR', 'HK', 'MO', 'CN', 'BR', 'KE' );
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/ups.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
⋮----
public function get_shipping_from_countries(): array {
⋮----
public function get_shipping_to_countries(): array {
⋮----
public function can_ship_from_to( string $shipping_from, string $shipping_to ): bool {
⋮----
public function try_parse_tracking_number( string $tracking_number, string $shipping_from, string $shipping_to ): ?array {
if ( empty( $tracking_number ) || empty( $shipping_from ) || empty( $shipping_to ) || ! $this->can_ship_from_to( $shipping_from, $shipping_to ) ) {
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/UrgentCargusShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class UrgentCargusShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/urgent-cargus.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/USPSShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
⋮----
class USPSShippingProvider extends AbstractShippingProvider {
⋮----
private array $domestic_countries = array( 'US', 'PR', 'GU', 'AS', 'VI', 'MP', 'FM', 'MH', 'PW' );
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/usps.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
⋮----
public function get_shipping_from_countries(): array {
⋮----
public function get_shipping_to_countries(): array {
⋮----
public function can_ship_from_to( string $shipping_from, string $shipping_to ): bool {
return in_array( $shipping_from, $this->get_shipping_from_countries(), true )
&& in_array( $shipping_to, $this->get_shipping_to_countries(), true );
⋮----
public function try_parse_tracking_number( string $tracking_number, string $shipping_from, string $shipping_to ): ?array {
if ( empty( $tracking_number ) || ! $this->can_ship_from_to( $shipping_from, $shipping_to ) ) {
⋮----
// USPS tracking number patterns (ordered by confidence).
⋮----
... (27 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/YurticiKargoShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class YurticiKargoShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/yurtici-kargo.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Providers/ZasilkovnaShippingProvider.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments\Providers;
⋮----
class ZasilkovnaShippingProvider extends AbstractShippingProvider {
⋮----
public function get_key(): string {
⋮----
public function get_name(): string {
⋮----
public function get_icon(): string {
return esc_url( WC()->plugin_url() ) . '/assets/images/shipping_providers/zasilkovna.png';
⋮----
public function get_tracking_url( string $tracking_number ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/Fulfillment.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments;
⋮----
use WC_Meta_Data;
⋮----
class Fulfillment extends \WC_Data {
⋮----
protected $data = array(
⋮----
private $meta_snapshot = array();
⋮----
public function __construct( $data = '' ) {
parent::__construct( $data );
⋮----
$this->set_id( absint( $data->get_id() ) );
⋮----
$this->set_id( absint( $data ) );
⋮----
$this->set_id( absint( $data['id'] ) );
⋮----
$this->set_id( absint( $data->id ) );
⋮----
$this->set_object_read( true );
⋮----
$this->data_store = \WC_Data_Store::load( 'order-fulfillment' );
if ( $this->get_id() > 0 ) {
$this->data_store->read( $this );
⋮----
public function snapshot_meta(): void {
⋮----
foreach ( $this->get_meta_data() as $meta ) {
... (156 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/FulfillmentException.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings\Exceptions\ApiException;
⋮----
class FulfillmentException extends ApiException {
⋮----
public function __construct( string $message, int $http_status_code = 400, array $additional_data = array() ) {
parent::__construct( 'woocommerce_fulfillment_error', $message, $http_status_code, $additional_data );
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/FulfillmentOrderNotes.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments;
⋮----
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
⋮----
class FulfillmentOrderNotes {
⋮----
public function register(): void {
⋮----
public function add_fulfillment_created_note( Fulfillment $fulfillment ): void {
$order = $fulfillment->get_order();
⋮----
$items_text    = $this->format_items( $fulfillment, $order );
$tracking_text = $this->format_tracking( $fulfillment );
$status        = $fulfillment->get_status() ?? 'unfulfilled';
$status_label  = $this->get_fulfillment_status_label( $status );
⋮----
$fulfillment->get_id(),
⋮----
$message = $this->normalize_note_message( $message );
⋮----
$order->add_order_note( $message, 0, false, array( 'note_group' => OrderNoteGroup::FULFILLMENT ) );
⋮----
public function add_fulfillment_updated_note( Fulfillment $fulfillment, array $changes = array(), string $previous_status = 'unfulfilled' ): void {
⋮----
$this->add_fulfillment_status_changed_note( $fulfillment, $order, $previous_status, $new_status );
⋮----
public function add_fulfillment_deleted_note( Fulfillment $fulfillment ): void {
⋮----
$fulfillment->get_id()
⋮----
... (32 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/FulfillmentsController.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments;
⋮----
use Automattic\WooCommerce\Admin\Features\Fulfillments\DataStore\FulfillmentsDataStore;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
⋮----
class FulfillmentsController {
⋮----
private $provides = array(
⋮----
public function register() {
⋮----
public function register_data_stores( $data_stores ) {
⋮----
public function initialize_fulfillments() {
⋮----
$features_controller = $container->get( FeaturesController::class );
⋮----
if ( ! $features_controller->feature_is_enabled( 'fulfillments' ) ) {
⋮----
$this->maybe_create_db_tables();
⋮----
$this->register_custom_shipping_providers_taxonomy();
⋮----
$class = $container->get( $class );
⋮----
$class->register();
⋮----
private function register_custom_shipping_providers_taxonomy(): void {
⋮----
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/FulfillmentsManager.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments;
⋮----
use Automattic\WooCommerce\Admin\Features\Fulfillments\Providers\AbstractShippingProvider;
use Automattic\WooCommerce\Admin\Features\Fulfillments\Providers\CustomShippingProvider;
use Automattic\WooCommerce\Utilities\OrderUtil;
use WC_Order;
use WC_Order_Refund;
⋮----
class FulfillmentsManager {
⋮----
private ?FulfillmentOrderNotes $fulfillment_order_notes = null;
⋮----
public function register() {
⋮----
$this->init_fulfillment_status_hooks();
$this->init_refund_hooks();
$this->init_email_template_tracking_hooks();
$this->init_order_deletion_hooks();
⋮----
$this->fulfillment_order_notes = wc_get_container()->get( FulfillmentOrderNotes::class );
⋮----
$this->fulfillment_order_notes->register();
⋮----
private function init_fulfillment_status_hooks() {
⋮----
private function init_refund_hooks() {
⋮----
private function init_email_template_tracking_hooks(): void {
⋮----
FulfillmentsTracker::track_fulfillment_email_template_customized( $email_id );
... (107 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/FulfillmentsRenderer.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments;
⋮----
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
use Automattic\WooCommerce\Utilities\OrderUtil;
use WC_Order;
⋮----
class FulfillmentsRenderer {
⋮----
private array $fulfillments_cache = array();
⋮----
public function register() {
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
⋮----
public function init_admin_hooks() {
⋮----
public function add_fulfillment_columns( $columns ) {
⋮----
public function render_fulfillment_column_row_data_legacy( string $column_name ) {
⋮----
return $this->render_fulfillment_column_row_data( $column_name, $the_order );
⋮----
public function render_fulfillment_column_row_data( string $column_name, WC_Order $order ) {
$fulfillments = $this->maybe_read_fulfillments( $order );
⋮----
$this->render_order_fulfillment_status_column_row_data( $order );
⋮----
$this->render_shipment_tracking_column_row_data( $order, $fulfillments );
⋮----
$this->render_shipment_provider_column_row_data( $order, $fulfillments );
⋮----
... (172 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/FulfillmentsSettings.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments;
⋮----
use WC_Order;
⋮----
class FulfillmentsSettings {
⋮----
public function register() {
⋮----
public function init_settings_auto_fulfill() {
⋮----
public function add_auto_fulfill_settings( array $settings, $current_section ): array {
⋮----
public function auto_fulfill_items_on_processing( int $order_id, $order ): void {
⋮----
if ( ! $order || empty( $order->get_items() ) ) {
⋮----
foreach ( $order->get_items() as $item ) {
⋮----
$product = $item->get_product();
⋮----
if ( ( $product->is_downloadable() && $auto_fulfill_downloadable )
|| ( $product->is_virtual() && $auto_fulfill_virtual )
|| in_array( $product->get_id(), $auto_fulfill_product_ids, true ) ) {
⋮----
$fulfillment->set_entity_type( WC_Order::class );
$fulfillment->set_entity_id( (string) $order_id );
$fulfillment->set_status( 'fulfilled' );
$fulfillment->set_items(
⋮----
'item_id' => $item->get_id(),
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/FulfillmentsTracker.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments;
⋮----
use WC_Tracks;
⋮----
class FulfillmentsTracker {
⋮----
public static function track_fulfillment_modal_opened( string $source, int $order_id ): void {
WC_Tracks::record_event(
⋮----
public static function track_fulfillment_creation( string $source, string $initial_status, string $fulfillment_type, int $item_count, int $total_quantity, bool $notification_sent ): void {
⋮----
public static function track_fulfillment_update( string $source, int $fulfillment_id, string $original_status, array $changed_fields, bool $notification_sent ): void {
⋮----
public static function track_fulfillment_deletion( string $source, int $fulfillment_id, string $status_at_deletion, bool $notification_sent ): void {
⋮----
public static function track_fulfillment_tracking_added( int $fulfillment_id, string $entry_method, string $provider_name, bool $is_custom_provider ): void {
⋮----
public static function track_fulfillment_tracking_lookup_attempt( string $lookup_status, string $provider_identified, bool $url_generated = false ): void {
⋮----
public static function track_fulfillment_bulk_action_used( string $action, int $order_count ): void {
⋮----
public static function track_fulfillment_filter_used( string $filter_by, string $filter_value ): void {
⋮----
public static function track_fulfillment_notification_sent( string $trigger_action, int $fulfillment_id, int $order_id ): void {
⋮----
public static function track_fulfillment_email_template_customized( string $template_name ): void {
⋮----
public static function track_fulfillment_validation_error( string $action_attempted, string $error_code, string $source ): void {
⋮----
public static function determine_tracking_entry_method( string $source, string $shipping_option ): string {
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/FulfillmentUtils.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments;
⋮----
use Automattic\WooCommerce\Admin\Features\Fulfillments\Providers\AbstractShippingProvider;
use WC_Order;
⋮----
class FulfillmentUtils {
⋮----
public static function get_pending_items( WC_Order $order, $fulfillments, $without_refunds = true ): array {
$items_in_fulfillments = self::get_all_items_of_fulfillments( $fulfillments );
⋮----
'item_id' => $item->get_id(),
⋮----
'qty'     => $item->get_quantity() + ( $without_refunds ? $order->get_qty_refunded_for_item( $item->get_id() ) : 0 ),
⋮----
$order->get_items() ?? array()
⋮----
public static function get_refunded_items( WC_Order $order ): array {
⋮----
foreach ( $order->get_items() as $item ) {
$items_refunded[ $item->get_id() ] = -1 * $order->get_qty_refunded_for_item( $item->get_id() );
⋮----
public static function get_fulfillment_items( WC_Order $order, Fulfillment $fulfillment ): array {
⋮----
array_column( $fulfillment->get_items(), 'item_id' ),
array_column( $fulfillment->get_items(), 'qty' )
⋮----
'qty'     => $item->get_quantity() - $order->get_qty_refunded_for_item( $item ),
⋮----
$order->get_items()
⋮----
... (71 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/OrderFulfillmentsRestController.php">
namespace Automattic\WooCommerce\Admin\Features\Fulfillments;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings\Exceptions\ApiException;
use Automattic\WooCommerce\Utilities\MetaDataUtil;
use Automattic\WooCommerce\Internal\RestApiControllerBase;
use WC_Order;
use WP_Http;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
⋮----
class OrderFulfillmentsRestController extends RestApiControllerBase {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = '/orders/(?P<order_id>[\d]+)/fulfillments';
⋮----
protected function get_rest_api_namespace(): string {
⋮----
public function register_routes() {
⋮----
'callback'            => fn( $request ) => $this->run( $request, 'get_fulfillments' ),
'permission_callback' => fn( $request ) => $this->check_permission_for_fulfillments( $request ),
'args'                => $this->get_args_for_get_fulfillments(),
'schema'              => $this->get_schema_for_get_fulfillments(),
⋮----
'callback'            => fn( $request ) => $this->run( $request, 'create_fulfillment' ),
⋮----
'args'                => $this->get_args_for_create_fulfillment(),
'schema'              => $this->get_schema_for_create_fulfillment(),
... (275 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Fulfillments/ShippingProviders.php">
use Automattic\WooCommerce\Admin\Features\Fulfillments\Providers as ShippingProviders;
</file>

<file path="plugins/woocommerce/src/Admin/Features/MarketingRecommendations/DefaultMarketingRecommendations.php">
namespace Automattic\WooCommerce\Admin\Features\MarketingRecommendations;
⋮----
class DefaultMarketingRecommendations {
⋮----
public static function get_all() {
</file>

<file path="plugins/woocommerce/src/Admin/Features/MarketingRecommendations/Init.php">
namespace Automattic\WooCommerce\Admin\Features\MarketingRecommendations;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\RemoteSpecsEngine;
⋮----
class Init extends RemoteSpecsEngine {
⋮----
public function __construct() {
⋮----
public static function delete_specs_transient() {
MarketingRecommendationsDataSourcePoller::get_instance()->delete_specs_transient();
MiscRecommendationsDataSourcePoller::get_instance()->delete_specs_transient();
⋮----
public static function get_specs() {
⋮----
return DefaultMarketingRecommendations::get_all();
⋮----
$specs = MarketingRecommendationsDataSourcePoller::get_instance()->get_specs_from_data_sources();
⋮----
public static function get_misc_recommendations_specs() {
⋮----
$specs = MiscRecommendationsDataSourcePoller::get_instance()->get_specs_from_data_sources();
⋮----
protected static function evaluate_specs( ?array $specs = null ) {
⋮----
$suggestions[] = self::object_to_array( $spec );
⋮----
public static function get_recommended_plugins(): array {
$specs   = self::get_specs();
$results = self::evaluate_specs( $specs );
⋮----
... (31 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/MarketingRecommendations/MarketingRecommendationsDataSourcePoller.php">
namespace Automattic\WooCommerce\Admin\Features\MarketingRecommendations;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller;
use WC_Helper;
⋮----
class MarketingRecommendationsDataSourcePoller extends DataSourcePoller {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
self::get_data_sources(),
⋮----
public static function get_data_sources() {
⋮----
WC_Helper::get_woocommerce_com_base_url() . 'wp-json/wccom/marketing-tab/1.3/recommendations.json',
</file>

<file path="plugins/woocommerce/src/Admin/Features/MarketingRecommendations/MiscRecommendationsDataSourcePoller.php">
namespace Automattic\WooCommerce\Admin\Features\MarketingRecommendations;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller;
use WC_Helper;
⋮----
class MiscRecommendationsDataSourcePoller extends DataSourcePoller {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
self::get_data_sources(),
⋮----
public static function get_data_sources() {
⋮----
WC_Helper::get_woocommerce_com_base_url() . 'wp-json/wccom/marketing-tab/misc/recommendations.json',
</file>

<file path="plugins/woocommerce/src/Admin/Features/Navigation/RemovedDeprecated.php">
namespace Automattic\WooCommerce\Admin\Features\Navigation;
⋮----
use WC_Tracks;
⋮----
class RemovedDeprecated {
⋮----
private static function handle_deprecated_method_call( $name ) {
⋮----
$logger->warning(
⋮----
WC_Tracks::record_event( 'deprecated_navigation_method_called' );
⋮----
public function __call( $name, $arguments ) {
self::handle_deprecated_method_call( $name );
⋮----
public static function __callStatic( $name, $arguments ) {
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/AdditionalPayments.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
use Automattic\WooCommerce\Internal\Admin\Settings\Payments as SettingsPaymentsService;
⋮----
class AdditionalPayments extends Payments {
⋮----
private $is_complete_result = null;
⋮----
private $can_view_result = null;
⋮----
public function get_id() {
⋮----
public function get_title() {
⋮----
public function get_content() {
⋮----
public function get_time() {
⋮----
public function is_complete() {
⋮----
$this->is_complete_result = $this->has_enabled_non_psp_payment_suggestion();
⋮----
public function can_view() {
⋮----
if ( self::has_gateways() ) {
⋮----
public function is_dismissable() {
⋮----
public function get_action_url(): string {
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Appearance.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Internal\Admin\Loader;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\Products;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
⋮----
class Appearance extends Task {
⋮----
public function __construct() {
if ( ! $this->is_complete() ) {
⋮----
public function get_id() {
⋮----
public function get_title() {
⋮----
public function get_content() {
⋮----
public function get_time() {
⋮----
public function get_action_label() {
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/CustomizeStore.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use WP_Post;
⋮----
class CustomizeStore extends Task {
⋮----
public function __construct( $task_list ) {
parent::__construct( $task_list );
⋮----
public function mark_task_as_complete_block_theme( $post_id, $post, $update ) {
⋮----
$is_cys_complete = $this->has_custom_global_styles( $post ) || $this->has_custom_template( $post );
⋮----
public function mark_task_as_complete_classic_theme() {
⋮----
public function get_id() {
⋮----
public function get_image_url() {
return WC()->plugin_url() . '/assets/images/task_list/customize-store-illustration.svg';
⋮----
public function get_image_alt() {
⋮----
public function get_title() {
⋮----
public function get_content() {
⋮----
/**
	 * Time.
	 *
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/ExperimentalShippingRecommendation.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\Jetpack\Connection\Manager;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Internal\Jetpack\JetpackConnection;
⋮----
class ExperimentalShippingRecommendation extends Task {
⋮----
public function get_id() {
⋮----
public function get_title() {
⋮----
public function get_content() {
⋮----
/**
	 * Time.
	 *
	 * @return string
	 */
public function get_time() {
⋮----
/**
	 * Task completion.
	 *
	 * @return bool
	 */
public function is_complete() {
return self::has_plugins_active() && self::has_jetpack_connected();
⋮----
... (27 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/ExtendStore.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
⋮----
class ExtendStore extends Task {
⋮----
public function get_id() {
⋮----
public function get_title() {
⋮----
public function get_content() {
⋮----
/**
	 * Additional info.
	 *
	 * @return string
	 */
public function get_additional_info() {
⋮----
/**
	 * Time.
	 *
	 * @return string
	 */
public function get_time() {
⋮----
/**
	 * Task completion.
	 *
	 * @return bool
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/GetMobileApp.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\Jetpack\Connection\Manager;
⋮----
class GetMobileApp extends Task {
⋮----
public function get_id() {
⋮----
public function get_title() {
⋮----
public function get_content() {
⋮----
/**
	 * Time.
	 *
	 * @return string
	 */
public function get_time() {
⋮----
/**
	 * Task completion.
	 *
	 * @return bool
	 */
public function is_complete() {
⋮----
public function can_view() {
$jetpack_can_be_installed                        = current_user_can( 'manage_woocommerce' ) && current_user_can( 'install_plugins' ) && ! self::is_jetpack_connected();
$jetpack_is_installed_and_current_user_connected = self::is_current_user_connected();
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/LaunchYourStore.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
⋮----
class LaunchYourStore extends Task {
⋮----
public function __construct( $task_list ) {
parent::__construct( $task_list );
⋮----
public function get_id() {
⋮----
public function get_image_url() {
return WC()->plugin_url() . '/assets/images/task_list/launch-your-store-illustration.svg';
⋮----
public function get_image_alt() {
⋮----
public function get_title() {
⋮----
public function get_content() {
⋮----
public function get_time() {
⋮----
/**
	 * Action URL.
	 *
	 * @return string
	 */
public function get_action_url() {
⋮----
public function is_complete() {
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Marketing.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
⋮----
class Marketing extends Task {
⋮----
public function __construct( $task_list ) {
parent::__construct( $task_list );
⋮----
public function on_activated_plugin( $plugin ) {
⋮----
private $is_complete_result = null;
⋮----
public function get_id() {
⋮----
public function get_image_url() {
return WC()->plugin_url() . '/assets/images/task_list/sales-illustration.svg';
⋮----
public function get_image_alt() {
⋮----
public function get_title() {
⋮----
public function get_content() {
⋮----
public function get_time() {
⋮----
public function can_view() {
⋮----
public function is_dismissable() {
⋮----
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Payments.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Internal\Admin\Settings\Payments as SettingsPaymentsService;
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\DefaultPaymentGateways;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
use Automattic\WooCommerce\Internal\Admin\Suggestions\PaymentsExtensionSuggestions;
use WC_Gateway_BACS;
use WC_Gateway_Cheque;
use WC_Gateway_COD;
⋮----
class Payments extends Task {
⋮----
private $is_complete_result = null;
⋮----
public function get_id() {
⋮----
public function get_image_url() {
return WC()->plugin_url() . '/assets/images/task_list/payment-illustration.svg';
⋮----
public function get_image_alt() {
⋮----
public function get_title() {
⋮----
public function get_content() {
⋮----
public function get_time() {
⋮----
public function is_complete() {
⋮----
... (88 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Products.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskList;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
⋮----
class Products extends Task {
⋮----
private static $revert_scheduled = false;
⋮----
public function __construct( $task_list ) {
parent::__construct( $task_list );
⋮----
if ( ! $this->is_complete() ) {
⋮----
public function highlight_add_product_menu( $submenu_file ) {
⋮----
$tutorial = wc_clean( wp_unslash( $_GET['tutorial'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
⋮----
if ( ! $this->is_active() || ! wc_string_to_bool( $tutorial ) || ! $screen || 'post' !== $screen->base || 'product' !== $screen->post_type ) {
⋮----
public function get_id() {
⋮----
public function get_image_url() {
return WC()->plugin_url() . '/assets/images/task_list/sales-section-illustration.svg';
⋮----
public function get_image_alt() {
... (60 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/ReviewShippingOptions.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
⋮----
class ReviewShippingOptions extends Task {
⋮----
public function get_id() {
⋮----
public function get_title() {
⋮----
public function get_content() {
⋮----
/**
	 * Time.
	 *
	 * @return string
	 */
public function get_time() {
⋮----
/**
	 * Task completion.
	 *
	 * @return bool
	 */
public function is_complete() {
⋮----
public function can_view() {
⋮----
public function is_dismissable() {
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Shipping.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use WC_Data_Store;
⋮----
class Shipping extends Task {
⋮----
public function __construct( $task_list = null ) {
parent::__construct( $task_list );
⋮----
public function get_id() {
⋮----
public function get_image_url() {
return WC()->plugin_url() . '/assets/images/task_list/shipping-illustration.svg';
⋮----
public function get_image_alt() {
⋮----
public function get_title() {
⋮----
public function get_content() {
⋮----
public function get_time() {
⋮----
public function is_complete() {
return self::has_shipping_zones();
⋮----
public function can_view() {
⋮----
if ( self::is_selling_digital_type_only() ) {
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/StoreCreation.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Admin\Features\Onboarding;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
⋮----
class StoreCreation extends Task {
⋮----
public function get_id() {
⋮----
public function get_title() {
⋮----
public function get_content() {
⋮----
/**
	 * Time.
	 *
	 * @return string
	 */
public function get_time() {
⋮----
public function get_action_url() {
⋮----
public function is_complete() {
⋮----
public function is_disabled() {
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/StoreDetails.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
⋮----
class StoreDetails extends Task {
⋮----
public function get_id() {
⋮----
public function get_image_url() {
return WC()->plugin_url() . '/assets/images/task_list/store-details-illustration.png';
⋮----
public function get_image_alt() {
⋮----
public function get_title() {
if ( true === $this->get_parent_option( 'use_completed_title' ) ) {
if ( $this->is_complete() ) {
⋮----
public function get_content() {
⋮----
public function get_time() {
⋮----
public function get_action_url() {
return ! $this->is_complete() ? admin_url( 'admin.php?page=wc-settings&tab=general&tutorial=true' ) : admin_url( 'admin.php?page=wc-settings&tab=general' );
⋮----
public function is_complete() {
$country        = WC()->countries->get_base_country();
$country_locale = WC()->countries->get_country_locale();
⋮----
// Mark as completed if the store address, city and postcode are set. We don't need to check the country because it's set by default.
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Tax.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Taxes\Stats\DataStore as TaxDataStore;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
⋮----
class Tax extends Task {
⋮----
private $is_complete_result = null;
⋮----
public function __construct( $task_list ) {
parent::__construct( $task_list );
⋮----
public function possibly_add_return_notice_script() {
$page = isset( $_GET['page'] ) ? $_GET['page'] : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Values are used only in strict comparisons and never reach a sink.
$tab  = isset( $_GET['tab'] ) ? $_GET['tab'] : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Values are used only in strict comparisons and never reach a sink.
⋮----
if ( ! $this->is_active() || $this->is_complete() ) {
⋮----
WCAdminAssets::register_script( 'wp-admin-scripts', 'onboarding-tax-notice', true );
⋮----
public function get_id() {
⋮----
public function get_image_url() {
return WC()->plugin_url() . '/assets/images/task_list/tax-illustration.svg';
⋮----
public function get_image_alt() {
⋮----
... (42 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/TourInAppMarketplace.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
⋮----
class TourInAppMarketplace extends Task {
⋮----
public function get_id() {
⋮----
public function get_title() {
⋮----
public function get_content() {
⋮----
/**
	 * Time.
	 *
	 * @return string
	 */
public function get_time() {
⋮----
/**
	 * Task completion.
	 *
	 * @return bool
	 */
public function is_complete() {
⋮----
public function get_action_url() {
⋮----
public function get_record_view_event(): bool {
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/WooCommercePayments.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
⋮----
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\Init as Suggestions;
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\DefaultPaymentGateways;
use Automattic\WooCommerce\Internal\Admin\WcPayWelcomePage;
use WC_Gateway_BACS;
use WC_Gateway_Cheque;
use WC_Gateway_COD;
⋮----
class WooCommercePayments extends Task {
⋮----
private $is_complete_result = null;
⋮----
public function get_id() {
⋮----
public function get_image_url() {
return WC()->plugin_url() . '/assets/images/task_list/payment-illustration.svg';
⋮----
public function get_image_alt() {
⋮----
public function get_title() {
⋮----
public function get_badge() {
⋮----
/**
	 * Content.
	 *
... (61 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/DeprecatedExtendedTask.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
⋮----
class DeprecatedExtendedTask extends Task {
⋮----
public $id = '';
⋮----
/**
	 * Additional info.
	 *
	 * @var string|null
	 */
public $additional_info = '';
⋮----
/**
	 * Content.
	 *
	 * @var string
	 */
public $content = '';
⋮----
/**
	 * Whether the task is complete or not.
	 *
	 * @var boolean
	 */
public $is_complete = false;
⋮----
/**
	 * Snoozeable.
	 *
... (86 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/DeprecatedOptions.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\TaskList;
use WC_Install;
⋮----
class DeprecatedOptions {
⋮----
final public static function init(): void {
⋮----
public static function get_deprecated_options( $pre_option, $option ) {
⋮----
public static function update_deprecated_options( $value, $old_value, $option ) {
⋮----
$task_list = TaskLists::get_list( 'setup' );
⋮----
$update = 'yes' === $value ? $task_list->hide() : $task_list->unhide();
⋮----
$task_list = TaskLists::get_list( 'extended' );
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Init.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\DeprecatedOptions;
⋮----
class Init {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
DeprecatedOptions::init();
TaskLists::init();
⋮----
public static function get_settings() {
⋮----
$wc_payments_gateway = \WC_Payments::get_gateway();
⋮----
? $wc_payments_gateway->is_connected()
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/Task.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
⋮----
use Automattic\WooCommerce\Internal\Admin\WCAdminUser;
⋮----
abstract class Task {
⋮----
protected $task_list;
⋮----
protected $duration_to_ms = array(
⋮----
public function __construct( $task_list = null ) {
⋮----
abstract public function get_id();
⋮----
abstract public function get_title();
⋮----
abstract public function get_content();
⋮----
abstract public function get_time();
⋮----
public function get_parent_id() {
⋮----
return $this->task_list->get_list_id();
⋮----
/**
	 * Get task list options.
	 *
	 * @return array
	 */
public function get_parent_options() {
... (209 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/TaskList.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
⋮----
class TaskList {
⋮----
public $id = '';
⋮----
/**
	 * ID.
	 *
	 * @var string
	 */
public $hidden_id = '';
⋮----
/**
	 * ID.
	 *
	 * @var boolean
	 */
public $display_progress_header = false;
⋮----
/**
	 * Title.
	 *
	 * @var string
	 */
public $title = '';
⋮----
/**
... (162 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/TaskLists.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\ReviewShippingOptions;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class TaskLists {
⋮----
protected static $instance = null;
⋮----
protected static $lists = array();
⋮----
protected static $default_tasks_loaded = false;
⋮----
final public static function instance() {
⋮----
public static function init() {
self::init_default_lists();
⋮----
public static function is_experiment_treatment( $name ) {
⋮----
$abtest         = new \WooCommerce\Admin\Experimental_Abtest(
⋮----
$date = new \DateTime();
$date->setTimeZone( new \DateTimeZone( 'UTC' ) );
⋮----
$date->format( 'Y' ),
$date->format( 'm' )
⋮----
return $abtest->get_variation( $experiment_name ) === 'treatment';
⋮----
... (73 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/TaskListSection.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
⋮----
class TaskListSection {
⋮----
public $id = '';
⋮----
/**
	 * Title.
	 *
	 * @var string
	 */
public $title = '';
⋮----
/**
	 * Description.
	 *
	 * @var string
	 */
public $description = '';
⋮----
/**
	 * Image.
	 *
	 * @var string
	 */
public $image = '';
⋮----
/**
	 * Tasks.
	 *
... (28 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/OnboardingTasks/TaskTraits.php">
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
⋮----
trait TaskTraits {
⋮----
public function record_tracks_event( $event_name, $args = array() ) {
if ( ! $this->get_list_id() ) {
⋮----
$prefixed_event_name = $this->prefix_event( $event_name );
⋮----
public function get_list_id() {
⋮----
? $this->get_parent_id()
</file>

<file path="plugins/woocommerce/src/Admin/Features/PaymentGatewaySuggestions/DefaultPaymentGateways.php">
namespace Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions;
⋮----
use WC_Gateway_BACS;
use WC_Gateway_COD;
⋮----
class DefaultPaymentGateways {
⋮----
private static $recommendation_priority = array(
⋮----
public static function get_all() {
⋮----
self::get_rules_for_countries(
⋮----
self::get_rules_for_wcpay_activated( false ),
self::get_rules_for_wcpay_connected( false ),
⋮----
self::get_rules_for_countries( array( 'GB', 'AT', 'BE', 'EE', 'FR', 'DE', 'GR', 'IE', 'IT', 'NL', 'PL', 'PT', 'AU', 'NZ', 'HK', 'SG', 'CN' ) ),
⋮----
self::get_rules_for_cbd( false ),
⋮----
self::get_rules_for_countries( self::get_wcpay_countries() ),
⋮----
self::get_rules_for_countries( array( 'ZA' ) ),
⋮----
self::get_rules_for_countries( array( 'ZA', 'GH', 'NG' ) ),
⋮----
self::get_rules_for_countries( array( 'US' ) ),
self::get_rules_for_cbd( true ),
⋮----
self::get_rules_for_selling_venues( array( 'brick-mortar', 'brick-mortar-other' ) ),
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/PaymentGatewaySuggestions/EvaluateSuggestion.php">
namespace Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
⋮----
class EvaluateSuggestion {
⋮----
protected static $memo = array();
⋮----
public static function evaluate( $spec, $logger_args = array() ) {
⋮----
// If the suggestion has no ID, use the title to generate a slug.
⋮----
$is_visible = $rule_evaluator->evaluate(
⋮----
public static function evaluate_specs( $specs, $logger_args = array() ) {
$specs_key = self::get_memo_key( $specs );
⋮----
$suggestion = self::evaluate( $spec, $logger_args );
⋮----
self::reset_memo();
⋮----
public static function reset_memo() {
⋮----
private static function get_memo_key( $specs ) {
</file>

<file path="plugins/woocommerce/src/Admin/Features/PaymentGatewaySuggestions/Init.php">
namespace Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\RemoteSpecsEngine;
⋮----
class Init extends RemoteSpecsEngine {
⋮----
public function __construct() {
PaymentGatewaysController::init();
⋮----
public static function get_suggestions( ?array $specs = null ) {
⋮----
$specs           = is_array( $specs ) ? $specs : self::get_specs();
$results         = EvaluateSuggestion::evaluate_specs( $specs );
⋮----
$specs_to_save   = DefaultPaymentGateways::get_all();
$specs_to_return = EvaluateSuggestion::evaluate_specs( $specs_to_save )['suggestions'];
⋮----
self::log_errors( $results['errors'] );
⋮----
PaymentGatewaySuggestionsDataSourcePoller::get_instance()->set_specs_transient( array( $locale => $specs_to_save ), 3 * HOUR_IN_SECONDS );
⋮----
public static function get_cached_or_default_suggestions() {
⋮----
? DefaultPaymentGateways::get_all()
: PaymentGatewaySuggestionsDataSourcePoller::get_instance()->get_cached_specs();
⋮----
$specs = DefaultPaymentGateways::get_all();
⋮----
$results = EvaluateSuggestion::evaluate_specs( $specs );
⋮----
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/PaymentGatewaySuggestions/PaymentGatewaysController.php">
namespace Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions;
⋮----
use Automattic\WooCommerce\Admin\Features\TransientNotices;
⋮----
class PaymentGatewaysController {
⋮----
public static function init() {
⋮----
public static function extend_response( $response, $gateway, $request ) {
$data = $response->get_data();
⋮----
$data['needs_setup']          = $gateway->needs_setup();
$data['post_install_scripts'] = self::get_post_install_scripts( $gateway );
⋮----
? $gateway->get_settings_url()
⋮----
? $gateway->get_connection_url( $return_url )
⋮----
? $gateway->get_setup_help_text()
⋮----
? $gateway->get_required_settings_keys()
⋮----
$response->set_data( $data );
⋮----
public static function get_post_install_scripts( $gateway ) {
⋮----
? $gateway->get_post_install_script_handles()
⋮----
public static function possibly_do_connection_return_action() {
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/PaymentGatewaySuggestions/PaymentGatewaySuggestionsDataSourcePoller.php">
namespace Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller;
use WC_Helper;
⋮----
class PaymentGatewaySuggestionsDataSourcePoller extends DataSourcePoller {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
self::$instance = new self( self::ID, self::get_data_sources() );
⋮----
public static function get_data_sources() {
⋮----
WC_Helper::get_woocommerce_com_base_url() . 'wp-json/wccom/payment-gateway-suggestions/2.0/suggestions.json',
</file>

<file path="plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/GroupInterface.php">
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor\ProductTemplates;
⋮----
interface GroupInterface {}
</file>

<file path="plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/ProductFormTemplateInterface.php">
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor\ProductTemplates;
⋮----
interface ProductFormTemplateInterface {}
</file>

<file path="plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/SectionInterface.php">
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor\ProductTemplates;
⋮----
interface SectionInterface {}
</file>

<file path="plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/SubsectionInterface.php">
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor\ProductTemplates;
⋮----
interface SubsectionInterface {}
</file>

<file path="plugins/woocommerce/src/Admin/Features/ProductBlockEditor/BlockRegistry.php">
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor;
⋮----
class BlockRegistry {
⋮----
/**
	 * Product fields blocks directory.
	 */
⋮----
/**
	 * Array of all available generic blocks.
	 */
⋮----
/**
	 * Array of all available product fields blocks.
	 */
⋮----
/**
	 * Singleton instance.
	 *
	 * @var BlockRegistry|null
	 */
private static $instance = null;
⋮----
/**
	 * Whether the removal warning has already been logged for the current request.
	 *
	 * @var bool
	 */
private static $removal_warning_logged = false;
⋮----
... (58 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplate.php">
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor;
⋮----
class ProductTemplate {
⋮----
private static $removal_warning_logged = false;
⋮----
public function __construct( array $data ) {
⋮----
self::maybe_log_removal_warning();
⋮----
public function get_id() {
⋮----
/**
	 * Get the template title.
	 *
	 * @return string
	 */
public function get_title() {
⋮----
/**
	 * Get the layout template ID.
	 *
	 * @return string|null
	 */
public function get_layout_template_id() {
⋮----
/**
	 * Set the layout template ID.
	 *
	 * @param string $layout_template_id The layout template ID.
... (77 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/ProductBlockEditor/README.md">
# Product Block Editor compatibility shims

This folder contains temporary compatibility shims for PHP classes and interfaces that were part of the removed Product Block Editor.

The Product Editor extension APIs were deprecated in WooCommerce 10.9.0, and the Product Block Editor was removed in WooCommerce 11.0.0 with no replacement. These classes remain only to avoid fatal errors in extensions or custom code that still reference the old PHP symbols during the transition period.

Do not add new Product Block Editor behavior here. Any code in this folder should be limited to compatibility with the removed APIs, should avoid reintroducing the removed editor, and may be removed in a future WooCommerce version.
</file>

<file path="plugins/woocommerce/src/Admin/Features/ShippingPartnerSuggestions/DefaultShippingPartners.php">
namespace Automattic\WooCommerce\Admin\Features\ShippingPartnerSuggestions;
⋮----
class DefaultShippingPartners {
⋮----
public static function get_all() {
$asset_base_url         = WC()->plugin_url() . '/assets/images/shipping_partners/';
⋮----
self::get_rules_for_countries( array( 'US', 'AU', 'NZ', 'CA', 'GB' ) ),
⋮----
self::get_rules_for_countries( array() ),
⋮----
self::get_rules_for_countries( array( 'MX', 'CO', 'CL', 'AR', 'PE', 'BR', 'UY', 'GT' ) ),
⋮----
self::get_rules_for_countries( array( 'SG', 'HK', 'AU', 'NZ' ) ),
⋮----
self::get_rules_for_countries( array( 'FR', 'DE', 'ES', 'IT', 'NL', 'AT', 'BE', 'IE', 'PT' ) ),
⋮----
self::get_rules_for_countries( array( 'US' ) ),
⋮----
public static function get_rules_for_countries( $countries ) {
</file>

<file path="plugins/woocommerce/src/Admin/Features/ShippingPartnerSuggestions/ShippingPartnerSuggestions.php">
namespace Automattic\WooCommerce\Admin\Features\ShippingPartnerSuggestions;
⋮----
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\EvaluateSuggestion;
use Automattic\WooCommerce\Admin\RemoteSpecs\RemoteSpecsEngine;
⋮----
class ShippingPartnerSuggestions extends RemoteSpecsEngine {
⋮----
public static function get_suggestions( ?array $specs = null ) {
⋮----
$specs           = is_array( $specs ) ? $specs : self::get_specs();
$results         = EvaluateSuggestion::evaluate_specs( $specs, array( 'source' => 'wc-shipping-partner-suggestions' ) );
⋮----
$specs_to_save   = DefaultShippingPartners::get_all();
$specs_to_return = EvaluateSuggestion::evaluate_specs( $specs_to_save, array( 'source' => 'wc-shipping-partner-suggestions' ) )['suggestions'];
⋮----
ShippingPartnerSuggestionsDataSourcePoller::get_instance()->set_specs_transient( array( $locale => $specs_to_save ), 3 * HOUR_IN_SECONDS );
⋮----
return self::sort_by_primary( $specs_to_return );
⋮----
private static function sort_by_primary( array $suggestions ) {
⋮----
// Attach original indices to preserve input order for equal-priority items
// (usort is not stable on PHP < 8.0).
⋮----
/**
	 * Get specs or fetch remotely if they don't exist.
	 */
public static function get_specs() {
⋮----
return apply_filters( 'woocommerce_admin_shipping_partner_suggestions_specs', DefaultShippingPartners::get_all() );
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/ShippingPartnerSuggestions/ShippingPartnerSuggestionsDataSourcePoller.php">
namespace Automattic\WooCommerce\Admin\Features\ShippingPartnerSuggestions;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller;
use WC_Helper;
⋮----
class ShippingPartnerSuggestionsDataSourcePoller extends DataSourcePoller {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
self::$instance = new self( self::ID, self::get_data_sources() );
⋮----
public static function get_data_sources() {
⋮----
WC_Helper::get_woocommerce_com_base_url() . 'wp-json/wccom/shipping-partner-suggestions/2.0/suggestions.json',
</file>

<file path="plugins/woocommerce/src/Admin/Features/Features.php">
namespace Automattic\WooCommerce\Admin\Features;
⋮----
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Internal\Admin\Analytics;
use Automattic\WooCommerce\Internal\Admin\Loader;
use Automattic\WooCommerce\Internal\Admin\RemoteInboxNotifications;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class Features {
⋮----
protected static $instance = null;
⋮----
private static $retired_feature_compatibility_versions = array(
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
$this->register_internal_class_aliases();
⋮----
if ( ! self::should_load_features() ) {
⋮----
public static function get_features() {
⋮----
public static function get_optional_feature_options() {
⋮----
public static function exists( $feature ) {
$is_legacy_compatibility_feature = self::is_legacy_compatibility_feature( $feature );
⋮----
... (105 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/LaunchYourStore.php">
namespace Automattic\WooCommerce\Admin\Features;
⋮----
use Automattic\WooCommerce\Admin\WCAdminHelper;
use Automattic\WooCommerce\Internal\Admin\WCAdminUser;
⋮----
class LaunchYourStore {
⋮----
public function __construct() {
⋮----
public function save_site_visibility_options() {
⋮----
public function append_coming_soon_global_tracks( $event_properties ) {
⋮----
public function preload_settings( $settings ) {
⋮----
private function is_manager_or_admin() {
⋮----
public function maybe_add_coming_soon_banner_on_frontend() {
⋮----
$has_dismissed_banner = WCAdminUser::get_user_data_field( $current_user_id, self::BANNER_DISMISS_USER_META_KEY )
⋮----
if ( ! $this->is_manager_or_admin() ) {
⋮----
if ( $store_pages_only && ! WCAdminHelper::is_current_page_store_page() ) {
⋮----
public function register_launch_your_store_user_meta_fields() {
⋮----
public function add_user_data_fields( $user_data_fields ) {
⋮----
public function reset_woocommerce_coming_soon_banner_dismissed( $user_login, $user ) {
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Features/Onboarding.php">
namespace Automattic\WooCommerce\Admin\Features;
⋮----
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
⋮----
class Onboarding extends DeprecatedClassFacade {
⋮----
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\Features\Onboarding';
⋮----
protected static $deprecated_in_version = '6.3.0';
⋮----
public function __construct() {
⋮----
public static function get_allowed_industries() {
⋮----
return \Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingIndustries::get_allowed_industries();
⋮----
public static function get_allowed_product_types() {
⋮----
return \Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProducts::get_allowed_product_types();
⋮----
public static function get_themes() {
⋮----
public static function get_theme_data( $theme ) {
⋮----
public static function get_allowed_themes() {
⋮----
public static function get_product_data( $product_types ) {
</file>

<file path="plugins/woocommerce/src/Admin/Features/TransientNotices.php">
namespace Automattic\WooCommerce\Admin\Features;
⋮----
use Automattic\WooCommerce\Internal\Admin\Loader;
⋮----
class TransientNotices {
⋮----
public function __construct() {
⋮----
public static function get_queue() {
⋮----
public static function get_queue_by_user( $user_id ) {
$notices = self::get_queue();
⋮----
public static function get( $notice_id ) {
$queue = self::get_queue();
⋮----
public static function add( $notice ) {
⋮----
public static function remove( $notice_id ) {
⋮----
public function preload_options( $options ) {
</file>

<file path="plugins/woocommerce/src/Admin/Marketing/InstalledExtensions.php">
namespace Automattic\WooCommerce\Admin\Marketing;
⋮----
use Automattic\WooCommerce\Admin\PluginsHelper;
⋮----
class InstalledExtensions {
⋮----
public static function get_data() {
⋮----
$automatewoo   = self::get_automatewoo_extension_data();
$aw_referral   = self::get_aw_referral_extension_data();
$aw_birthdays  = self::get_aw_birthdays_extension_data();
$mailchimp     = self::get_mailchimp_extension_data();
$facebook      = self::get_facebook_extension_data();
$pinterest     = self::get_pinterest_extension_data();
$google        = self::get_google_extension_data();
$amazon_ebay   = self::get_amazon_ebay_extension_data();
$mailpoet      = self::get_mailpoet_extension_data();
$klaviyo       = self::get_klaviyo_extension_data();
$creative_mail = self::get_creative_mail_extension_data();
$tiktok        = self::get_tiktok_extension_data();
$jetpack_crm   = self::get_jetpack_crm_extension_data();
$zapier        = self::get_zapier_extension_data();
$salesforce    = self::get_salesforce_extension_data();
$vimeo         = self::get_vimeo_extension_data();
$trustpilot    = self::get_trustpilot_extension_data();
⋮----
public static function get_allowed_plugins() {
⋮----
protected static function get_automatewoo_extension_data() {
⋮----
... (64 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Marketing/MarketingCampaign.php">
namespace Automattic\WooCommerce\Admin\Marketing;
⋮----
class MarketingCampaign {
⋮----
protected $id;
⋮----
protected $type;
⋮----
protected $title;
⋮----
protected $manage_url;
⋮----
protected $cost;
⋮----
protected $sales;
⋮----
public function __construct( string $id, MarketingCampaignType $type, string $title, string $manage_url, ?Price $cost = null, ?Price $sales = null ) {
⋮----
public function get_id(): string {
⋮----
public function get_type(): MarketingCampaignType {
⋮----
public function get_title(): string {
⋮----
public function get_manage_url(): string {
⋮----
public function get_cost(): ?Price {
⋮----
public function get_sales(): ?Price {
</file>

<file path="plugins/woocommerce/src/Admin/Marketing/MarketingCampaignType.php">
namespace Automattic\WooCommerce\Admin\Marketing;
⋮----
class MarketingCampaignType {
⋮----
protected $id;
⋮----
protected $channel;
⋮----
protected $name;
⋮----
protected $description;
⋮----
protected $create_url;
⋮----
protected $icon_url;
⋮----
public function __construct( string $id, MarketingChannelInterface $channel, string $name, string $description, string $create_url, string $icon_url ) {
⋮----
public function get_id(): string {
⋮----
public function get_channel(): MarketingChannelInterface {
⋮----
public function get_name(): string {
⋮----
public function get_description(): string {
⋮----
public function get_create_url(): string {
⋮----
public function get_icon_url(): string {
</file>

<file path="plugins/woocommerce/src/Admin/Marketing/MarketingChannelInterface.php">
namespace Automattic\WooCommerce\Admin\Marketing;
⋮----
interface MarketingChannelInterface {
⋮----
public function get_slug(): string;
⋮----
public function get_name(): string;
⋮----
public function get_description(): string;
⋮----
public function get_icon_url(): string;
⋮----
public function is_setup_completed(): bool;
⋮----
public function get_setup_url(): string;
⋮----
public function get_product_listings_status(): string;
⋮----
public function get_errors_count(): int;
⋮----
public function get_supported_campaign_types(): array;
⋮----
public function get_campaigns(): array;
</file>

<file path="plugins/woocommerce/src/Admin/Marketing/MarketingChannels.php">
namespace Automattic\WooCommerce\Admin\Marketing;
⋮----
use Exception;
⋮----
class MarketingChannels {
⋮----
private $registered_channels = [];
⋮----
public function register( MarketingChannelInterface $channel ): void {
if ( isset( $this->registered_channels[ $channel->get_slug() ] ) ) {
⋮----
$this->registered_channels[ $channel->get_slug() ] = $channel;
⋮----
public function unregister_all(): void {
⋮----
public function get_registered_channels(): array {
</file>

<file path="plugins/woocommerce/src/Admin/Marketing/Price.php">
namespace Automattic\WooCommerce\Admin\Marketing;
⋮----
class Price {
⋮----
protected $value;
⋮----
protected $currency;
⋮----
public function __construct( string $value, string $currency ) {
⋮----
public function get_value(): string {
⋮----
public function get_currency(): string {
</file>

<file path="plugins/woocommerce/src/Admin/Notes/DataStore.php">
namespace Automattic\WooCommerce\Admin\Notes;
⋮----
class DataStore extends \WC_Data_Store_WP implements \WC_Object_Data_Store_Interface {
⋮----
/**
	 * Method to create a new note in the database.
	 *
	 * @param Note $note Admin note.
	 */
public function create( &$note ) {
⋮----
$note->set_date_created( $date_created );
⋮----
'name'         => $note->get_name(),
'type'         => $note->get_type(),
'locale'       => $note->get_locale(),
'title'        => $note->get_title(),
'content'      => $note->get_content(),
'status'       => $note->get_status(),
'source'       => $note->get_source(),
'is_snoozable' => (int) $note->get_is_snoozable(),
⋮----
'is_deleted'   => (int) $note->get_is_deleted(),
'is_read'      => (int) $note->get_is_read(),
⋮----
$note_to_be_inserted['content_data']  = wp_json_encode( $note->get_content_data() );
⋮----
$wpdb->insert( $wpdb->prefix . 'wc_admin_notes', $note_to_be_inserted );
⋮----
$note->set_id( $note_id );
... (167 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Notes/DeprecatedNotes.php">
namespace Automattic\WooCommerce\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
⋮----
class WC_Admin_Note extends DeprecatedClassFacade {
⋮----
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\Notes\Note';
⋮----
protected static $deprecated_in_version = '4.8.0';
⋮----
public function __construct( $data = '' ) {
⋮----
/**
 * WC_Admin_Notes.
 *
 * @deprecated since 4.8.0, use Notes
 */
class WC_Admin_Notes extends DeprecatedClassFacade {
/**
	 * The name of the non-deprecated class that this facade covers.
	 *
	 * @var string
	 */
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\Notes\Notes';
⋮----
class WC_Admin_Notes_Customize_Store_With_Blocks extends DeprecatedClassFacade {
⋮----
protected static $facade_over_classname = 'Automattic\WooCommerce\Internal\Admin\Notes\CustomizeStoreWithBlocks';
⋮----
class WC_Admin_Notes_Edit_Products_On_The_Move extends DeprecatedClassFacade {
... (87 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Notes/Note.php">
namespace Automattic\WooCommerce\Admin\Notes;
⋮----
class Note extends \WC_Data {
⋮----
protected $object_type = 'admin-note';
⋮----
protected $cache_group = 'admin-note';
⋮----
public function __construct( $data = '' ) {
// Set default data here to allow `content_data` to be an object.
⋮----
'content_data'  => new \stdClass(),
⋮----
parent::__construct( $data );
⋮----
$this->set_id( absint( $data->get_id() ) );
⋮----
$this->set_id( $data );
⋮----
$this->set_id( $data->note_id );
⋮----
$this->set_props( (array) $data );
$this->set_object_read( true );
⋮----
$this->data_store = Notes::load_data_store();
if ( $this->get_id() > 0 ) {
$this->data_store->read( $this );
⋮----
public function apply_changes() {
⋮----
... (171 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Notes/Notes.php">
namespace Automattic\WooCommerce\Admin\Notes;
⋮----
use WC_Site_Tracking;
⋮----
class Notes {
⋮----
public static function init() {
⋮----
public static function get_notes( $context = 'edit', $args = array() ) {
$data_store = self::load_data_store();
$raw_notes  = $data_store->get_notes( $args );
⋮----
$note_id                            = $note->get_id();
$notes[ $note_id ]                  = $note->get_data();
$notes[ $note_id ]['name']          = $note->get_name( $context );
$notes[ $note_id ]['type']          = $note->get_type( $context );
$notes[ $note_id ]['locale']        = $note->get_locale( $context );
$notes[ $note_id ]['title']         = $note->get_title( $context );
$notes[ $note_id ]['content']       = $note->get_content( $context );
$notes[ $note_id ]['content_data']  = $note->get_content_data( $context );
$notes[ $note_id ]['status']        = $note->get_status( $context );
$notes[ $note_id ]['source']        = $note->get_source( $context );
$notes[ $note_id ]['date_created']  = $note->get_date_created( $context );
$notes[ $note_id ]['date_reminder'] = $note->get_date_reminder( $context );
$notes[ $note_id ]['actions']       = $note->get_actions( $context );
⋮----
$notes[ $note_id ]['is_deleted']    = $note->get_is_deleted( $context );
⋮----
public static function get_note( $note_id ) {
⋮----
... (103 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Notes/NotesUnavailableException.php">
namespace Automattic\WooCommerce\Admin\Notes;
⋮----
class NotesUnavailableException extends \WC_Data_Exception {}
</file>

<file path="plugins/woocommerce/src/Admin/Notes/NoteTraits.php">
namespace Automattic\WooCommerce\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\WCAdminHelper;
⋮----
trait NoteTraits {
⋮----
private static function wc_admin_active_for( $seconds ) {
return WCAdminHelper::is_wc_admin_active_for( $seconds );
⋮----
private static function is_wc_admin_active_in_date_range( $range, $custom_start = null ) {
return WCAdminHelper::is_wc_admin_active_in_date_range( $range, $custom_start );
⋮----
public static function note_exists(): bool {
⋮----
$data_store = Notes::load_data_store();
$note_ids   = $data_store->get_notes_with_name( self::NOTE_NAME );
⋮----
public static function can_be_added(): bool {
$note = self::get_note();
⋮----
if ( self::note_exists() ) {
⋮----
Note::E_WC_ADMIN_NOTE_MARKETING === $note->get_type()
⋮----
public static function possibly_add_note(): void {
⋮----
if ( ! self::can_be_added() ) {
⋮----
$note->save();
⋮----
... (44 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Overrides/Order.php">
namespace Automattic\WooCommerce\Admin\Overrides;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore as CustomersDataStore;
use Automattic\WooCommerce\Admin\API\Reports\Orders\Stats\DataStore as OrdersStatsDataStore;
use Automattic\WooCommerce\Enums\OrderItemType;
⋮----
class Order extends \WC_Order {
⋮----
protected $refunded_line_items;
⋮----
public $customer_id = null;
⋮----
public function get_data_without_line_items() {
⋮----
'id' => $this->get_id(),
⋮----
'number'    => $this->get_order_number(),
'meta_data' => $this->get_meta_data(),
⋮----
public function get_line_item_data( $type ) {
⋮----
return $this->get_items( $type_to_items[ $type ] );
⋮----
public static function add_filters() {
⋮----
public static function order_class_name( $classname, $order_type, $order_id ) {
⋮----
public function get_report_customer_id() {
⋮----
$this->customer_id = CustomersDataStore::get_or_create_customer_from_order( $this );
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Overrides/OrderRefund.php">
namespace Automattic\WooCommerce\Admin\Overrides;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore as CustomersDataStore;
⋮----
class OrderRefund extends \WC_Order_Refund {
⋮----
public $customer_id = null;
⋮----
public static function add_filters() {
⋮----
public static function order_class_name( $classname, $order_type, $order_id ) {
⋮----
public function get_report_customer_id() {
⋮----
$parent_order = \wc_get_order( $this->get_parent_id() );
⋮----
? CustomersDataStore::get_or_create_customer_from_order( $parent_order )
⋮----
public function is_returning_customer() {
</file>

<file path="plugins/woocommerce/src/Admin/Overrides/OrderTraits.php">
namespace Automattic\WooCommerce\Admin\Overrides;
⋮----
use Automattic\WooCommerce\Enums\OrderItemType;
⋮----
trait OrderTraits {
⋮----
public function get_item_shipping_amount( $item, $order_items_count = null, $shipping_amount = null ) {
⋮----
$product_qty = $item->get_quantity( 'edit' );
⋮----
$order_items = null !== $order_items_count ? $order_items_count : $this->get_item_count();
⋮----
$total_shipping_amount = null !== $shipping_amount ? $shipping_amount : (float) $this->get_shipping_total();
⋮----
public function get_item_shipping_tax_amount( $item, $order_items_count = null, $shipping_tax_amount = null ) {
⋮----
$order_taxes         = $this->get_taxes();
$line_items_shipping = $this->get_items( OrderItemType::SHIPPING );
⋮----
$tax_data = $shipping_item->get_taxes();
⋮----
$tax_item_id                = $tax_item->get_rate_id();
⋮----
public function get_item_coupon_amount( $item ) {
return floatval( $item->get_subtotal( 'edit' ) - $item->get_total( 'edit' ) );
⋮----
public function get_item_cart_tax_amount( $item ) {
$order_taxes     = $this->get_taxes();
$tax_data        = $item->get_taxes();
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Overrides/ThemeUpgrader.php">
namespace Automattic\WooCommerce\Admin\Overrides;
⋮----
class ThemeUpgrader extends \Theme_Upgrader {
⋮----
public function install( $package, $args = array() ) {
⋮----
$this->init();
$this->install_strings();
⋮----
$result = $this->run(
</file>

<file path="plugins/woocommerce/src/Admin/Overrides/ThemeUpgraderSkin.php">
namespace Automattic\WooCommerce\Admin\Overrides;
⋮----
class ThemeUpgraderSkin extends \Theme_Upgrader_Skin {
⋮----
public $api;
⋮----
public function header() {}
⋮----
public function footer() {}
⋮----
public function feedback( $string, ...$args ) {}
⋮----
public function after() {}
</file>

<file path="plugins/woocommerce/src/Admin/PluginsInstallLoggers/AsyncPluginsInstallLogger.php">
namespace Automattic\WooCommerce\Admin\PluginsInstallLoggers;
⋮----
class AsyncPluginsInstallLogger implements PluginsInstallLogger {
⋮----
private $option_name;
⋮----
public function __construct( string $option_name ) {
⋮----
$option           = $this->get();
⋮----
$this->update( $option );
⋮----
private function update( array $data ) {
⋮----
private function get() {
⋮----
public function install_requested( string $plugin_name ) {
$option = $this->get();
⋮----
public function installed( string $plugin_name, int $duration ) {
⋮----
public function activated( string $plugin_name ) {
⋮----
public function add_error( string $plugin_name, ?string $error_message = null ) {
⋮----
'extension'     => $this->get_plugin_track_key( $plugin_name ),
⋮----
public function complete( $data = array() ) {
⋮----
$this->track( $data );
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/PluginsInstallLoggers/PluginsInstallLogger.php">
namespace Automattic\WooCommerce\Admin\PluginsInstallLoggers;
⋮----
interface PluginsInstallLogger {
⋮----
public function install_requested( string $plugin_name );
⋮----
public function installed( string $plugin_name, int $duration);
⋮----
public function activated( string $plugin_name );
⋮----
public function add_error( string $plugin_name, ?string $error_message = null);
⋮----
public function complete( $data = array() );
</file>

<file path="plugins/woocommerce/src/Admin/PluginsProvider/PluginsProvider.php">
namespace Automattic\WooCommerce\Admin\PluginsProvider;
⋮----
use Automattic\WooCommerce\Admin\PluginsProvider\PluginsProviderInterface;
use Automattic\WooCommerce\Admin\PluginsHelper;
⋮----
class PluginsProvider implements PluginsProviderInterface {
⋮----
private static $deactivated_plugin_slug = '';
⋮----
/**
	 * Get an array of active plugin slugs.
	 *
	 * @return array
	 */
public function get_active_plugin_slugs() {
⋮----
PluginsHelper::get_active_plugin_slugs(),
⋮----
/**
	 * Set the deactivated plugin. This is needed because the deactivated_plugin
	 * hook happens before the option is updated which means that getting the
	 * active plugins includes the deactivated plugin.
	 *
	 * @param string $plugin_path The path to the plugin being deactivated.
	 */
public static function set_deactivated_plugin( $plugin_path ) {
⋮----
/**
	 * Get plugin data.
	 *
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/PluginsProvider/PluginsProviderInterface.php">
namespace Automattic\WooCommerce\Admin\PluginsProvider;
⋮----
interface PluginsProviderInterface {
⋮----
public function get_active_plugin_slugs();
⋮----
public function get_plugin_data( $plugin );
⋮----
public function get_plugin_path_from_slug( $slug );
</file>

<file path="plugins/woocommerce/src/Admin/RemoteInboxNotifications/README.md">
# Remote Inbox Notifications

This is a remote inbox notifications engine in WooCommerce admin, which polls some JSON feeds (see `DataSourcePoller.php`) containing specifications of remote inbox notifications, including rules that, when satisfied, display the notification in the WooCommerce Admin screens.

The interesting entry points are the poller (`DataSourcePoller.php`) which fetches the rule specifications from a number of feeds, and the engine (`RemoteInboxNotificationsEngine.php`), both of which run daily as part of the `wc-admin-daily` cron task.

During the fetching of the specifications, each specification and the rules within the specification are validated. If a specification fails validation it is not imported or processed.

Following is the structure of the JSON feed, including the different rules that can be used to build up an inbox notification specification.

## JSON file

```json
[
	<spec>,
	...
]
```

## Spec

```json
{
	"slug": "ad-for-automate-woo-2020-04-20",
	"type": "info",
	"status": "unactioned",
	"is_snoozable": 0,
	"source": "woo.com",
	"locales": [
		<Locale>,
... (110 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/RemoteInboxNotifications/RemoteInboxNotificationsDataSourcePoller.php">
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\GetRuleProcessor;
use WC_Helper;
⋮----
class RemoteInboxNotificationsDataSourcePoller extends DataSourcePoller {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
self::get_data_sources(),
⋮----
protected function validate_spec( $spec, $url ) {
$logger         = self::get_logger();
⋮----
$logger->error(
⋮----
$logger->error( print_r( $spec, true ), $logger_context );
⋮----
if ( null === SpecRunner::get_locale( $spec->locales ) ) {
⋮----
if ( ! $this->validate_action( $action, $url ) ) {
⋮----
$logger->error( print_r( $rule, true ), $logger_context );
⋮----
$processor = GetRuleProcessor::get_processor( $rule->type );
⋮----
if ( ! $processor->validate( $rule ) ) {
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/RemoteInboxNotifications/RemoteInboxNotificationsEngine.php">
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
⋮----
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Admin\PluginsProvider\PluginsProvider;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\RemoteSpecs\RemoteSpecsEngine;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\StoredStateSetupForProducts;
⋮----
class RemoteInboxNotificationsEngine extends RemoteSpecsEngine {
⋮----
public static function init() {
⋮----
$next_hook = WC()->queue()->get_next(
⋮----
WC()->queue()->schedule_single(
⋮----
public static function update_profile_option( $old_value, $new_value ) {
⋮----
self::run();
⋮----
public static function on_admin_init() {
⋮----
StoredStateSetupForProducts::admin_init();
⋮----
self::get_stored_state();
⋮----
public static function on_init() {
StoredStateSetupForProducts::init();
⋮----
... (53 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/RemoteInboxNotifications/RuleProcessorInterface.php">
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
⋮----
interface RuleProcessorInterface {
⋮----
public function process( $rule, $stored_state );
⋮----
public function validate( $rule );
</file>

<file path="plugins/woocommerce/src/Admin/RemoteInboxNotifications/SpecRunner.php">
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\EvaluateAndGetStatus;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
⋮----
class SpecRunner {
⋮----
public static function run_spec( $spec, $stored_state ) {
$data_store = Notes::load_data_store();
⋮----
$existing_note_ids = $data_store->get_notes_with_name( $spec->slug );
⋮----
$note->set_status( Note::E_WC_ADMIN_NOTE_PENDING );
⋮----
$note = Notes::get_note( $existing_note_ids[0] );
⋮----
$previous_status = $note->get_status();
⋮----
$status = EvaluateAndGetStatus::evaluate(
⋮----
$note->set_date_created( time() );
⋮----
$locale = self::get_locale( $spec->locales );
⋮----
$note->set_title( $locale->title );
$note->set_content( $locale->content );
$note->set_content_data( isset( $spec->content_data ) ? $spec->content_data : (object) array() );
$note->set_status( $status );
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/RemoteInboxNotifications/TransformerInterface.php">
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
⋮----
use stdClass;
⋮----
interface TransformerInterface {
⋮----
public function transform( $value, ?stdClass $arguments = null, $default_value = null );
⋮----
public function validate( ?stdClass $arguments = null );
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/Transformers/ArrayColumn.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
use InvalidArgumentException;
use stdClass;
⋮----
class ArrayColumn implements TransformerInterface {
⋮----
public function transform( $value, ?stdClass $arguments = null, $default_value = array() ) {
⋮----
public function validate( ?stdClass $arguments = null ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/Transformers/ArrayFlatten.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
use stdClass;
⋮----
class ArrayFlatten implements TransformerInterface {
⋮----
public function transform( $value, ?stdClass $arguments = null, $default_value = array() ) {
⋮----
public function validate( ?stdClass $arguments = null ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/Transformers/ArrayKeys.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
use stdClass;
⋮----
class ArrayKeys implements TransformerInterface {
⋮----
public function transform( $value, ?stdClass $arguments = null, $default_value = array() ) {
⋮----
public function validate( ?stdClass $arguments = null ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/Transformers/ArraySearch.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
use InvalidArgumentException;
use stdClass;
⋮----
class ArraySearch implements TransformerInterface {
⋮----
public function transform( $value, ?stdClass $arguments = null, $default_value = null ) {
⋮----
public function validate( ?stdClass $arguments = null ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/Transformers/ArrayValues.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
use stdClass;
⋮----
class ArrayValues implements TransformerInterface {
⋮----
public function transform( $value, ?stdClass $arguments = null, $default_value = array() ) {
⋮----
public function validate( ?stdClass $arguments = null ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/Transformers/Count.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
use stdClass;
⋮----
class Count implements TransformerInterface {
⋮----
public function transform( $value, ?stdClass $arguments = null, $default_value = null ) {
⋮----
public function validate( ?stdClass $arguments = null ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/Transformers/DotNotation.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
use InvalidArgumentException;
use stdClass;
⋮----
class DotNotation implements TransformerInterface {
⋮----
public function transform( $value, ?stdclass $arguments = null, $default_value = null ) {
⋮----
return $this->get( $value, $arguments->path, $default_value );
⋮----
public function get( $array_to_search, $path, $default_value = null ) {
⋮----
public function validate( ?stdClass $arguments = null ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/Transformers/PrepareUrl.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
use stdClass;
⋮----
class PrepareUrl implements TransformerInterface {
⋮----
public function transform( $value, ?stdClass $arguments = null, $default_value = null ) {
⋮----
public function validate( ?stdClass $arguments = null ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/Transformers/README.md">
<!-- markdownlint-disable MD024 -->

# Option Transformer

An option transformer is a class that transforms the given option value into a different value for the comparison operation.

Transformers run in the order in which they are defined, and each transformer passes down the value it transformed to the next transformer for consumption.

**Definition example**: transformers are always used with `option` rule.

```js
  {
    "slug": "test-note",
     ...
    ],
    "rules": [
      {
        "type": "option",
        "transformers": [
            {
                "use": "dot_notation",
                "arguments": {
                    "path": "industry"
                }
            },
            {
                "use": "array_column",
                "arguments": {
                    "key": "slug"
                }
... (375 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/Transformers/TransformerInterface.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
⋮----
use stdClass;
⋮----
interface TransformerInterface {
⋮----
public function transform( $value, ?stdClass $arguments = null, $default_value = null );
⋮----
public function validate( ?stdClass $arguments = null );
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/Transformers/TransformerService.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
⋮----
use InvalidArgumentException;
use stdClass;
⋮----
class TransformerService {
⋮----
public static function create_transformer( $name ) {
⋮----
return new $classname();
⋮----
/**
	 * Apply transformers to the given value.
	 *
	 * @param mixed  $target_value a value to transform.
	 * @param array  $transformer_configs transform configuration.
	 * @param bool   $is_default_set flag on is default value set.
	 * @param string $default_value default value.
	 *
	 * @throws InvalidArgumentException Throws when one of the required arguments is missing.
	 * @return mixed|null
	 */
public static function apply( $target_value, array $transformer_configs, $is_default_set, $default_value ) {
⋮----
$transformer = self::create_transformer( $transformer_config->use );
⋮----
$target_value = $transformer->transform( $target_value, $transformer_config->arguments, $is_default_set ? $default_value : null );
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/BaseLocationCountryRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
⋮----
class BaseLocationCountryRuleProcessor implements RuleProcessorInterface {
⋮----
public function process( $rule, $stored_state ) {
⋮----
if ( $is_address_default && OnboardingProfile::needs_completion() && ! $is_store_country_set ) {
⋮----
return ComparisonOperation::compare(
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/BaseLocationStateRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class BaseLocationStateRuleProcessor implements RuleProcessorInterface {
⋮----
public function process( $rule, $stored_state ) {
⋮----
return ComparisonOperation::compare(
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/ComparisonOperation.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class ComparisonOperation {
⋮----
public static function compare( $left_operand, $right_operand, $operation ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/ContextPluginsRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class ContextPluginsRuleProcessor implements RuleProcessorInterface {
⋮----
private array $plugins;
⋮----
public function __construct( array $plugins ) {
⋮----
public function process( $rule, $stored_state ) {
⋮----
if ( ComparisonOperation::compare( $plugin->{$rule->name}, $rule->value, $rule->operation ) ) {
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/EvaluateAndGetStatus.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
⋮----
class EvaluateAndGetStatus {
⋮----
public static function evaluate( $spec, $current_status, $stored_state, $rule_evaluator ) {
⋮----
$evaluated_result = $rule_evaluator->evaluate(
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/EvaluateOverrides.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class EvaluateOverrides {
⋮----
public function evaluate( array $spec, array $context = array() ) {
⋮----
if ( $rule_evaluator->evaluate( $override->rules ) ) {
⋮----
$this->set_value_with_dot_notation( $spec_item, $override->field, $override->value );
⋮----
public function set_value_with_dot_notation( &$data, $path, $new_value ) {
⋮----
$data[ $key ] = new \stdClass();
⋮----
$data->$key = new \stdClass();
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/EvaluationLogger.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class EvaluationLogger {
⋮----
private $slug;
⋮----
private $results = array();
⋮----
private $logger;
⋮----
private $source = '';
⋮----
/**
	 * EvaluationLogger constructor.
	 *
	 * @param string                    $slug   Slug/ID of a spec that is being evaluated.
	 * @param string|null               $source Logger source.
	 * @param \WC_Logger_Interface|null $logger Logger class to use. Default to using the WC logger.
	 */
public function __construct( $slug, $source = null, ?\WC_Logger_Interface $logger = null ) {
⋮----
/**
	 * Add evaluation result of a rule.
	 *
	 * @param string  $rule_type Name of the rule being tested.
	 * @param boolean $result    Result of a given rule.
	 */
public function add_result( $rule_type, $result ) {
⋮----
public function log() {
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/FailRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class FailRuleProcessor implements RuleProcessorInterface {
⋮----
public function process( $rule, $stored_state ) {
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/GetRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class GetRuleProcessor {
⋮----
public static function get_processor( $rule_type ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/GetRuleProcessorForContext.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class GetRuleProcessorForContext {
⋮----
protected array $context;
⋮----
public function __construct( array $context = array() ) {
⋮----
public function get_processor( $rule_type ) {
⋮----
return GetRuleProcessor::get_processor( $rule_type );
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/IsEcommerceRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class IsEcommerceRuleProcessor implements RuleProcessorInterface {
⋮----
public function process( $rule, $stored_state ) {
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/IsWooExpressRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class IsWooExpressRuleProcessor implements RuleProcessorInterface {
⋮----
public function process( $rule, $stored_state ) {
⋮----
return $fn() === $rule->value;
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/NoteStatusRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
use Automattic\WooCommerce\Admin\Notes\Notes;
⋮----
class NoteStatusRuleProcessor implements RuleProcessorInterface {
⋮----
public function process( $rule, $stored_state ) {
$status = Notes::get_note_status( $rule->note_name );
⋮----
return ComparisonOperation::compare(
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/NotRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class NotRuleProcessor implements RuleProcessorInterface {
⋮----
protected $rule_evaluator;
⋮----
public function __construct( $rule_evaluator = null ) {
⋮----
public function process( $rule, $stored_state ) {
$evaluated_operand = $this->rule_evaluator->evaluate(
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/OnboardingProfileRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class OnboardingProfileRuleProcessor implements RuleProcessorInterface {
⋮----
public function process( $rule, $stored_state ) {
⋮----
return ComparisonOperation::compare(
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/OptionRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerService;
⋮----
class OptionRuleProcessor implements RuleProcessorInterface {
⋮----
public function process( $rule, $stored_state ) {
⋮----
$option_value                    = $this->get_option_value( $rule, $default_value, $is_contains );
⋮----
$option_value = TransformerService::apply( $option_value, $rule->transformers, $is_default_set, $default_value );
⋮----
return ComparisonOperation::compare(
⋮----
private function get_option_value( $rule, $default_value, $is_contains ) {
⋮----
$logger->warning(
⋮----
public function validate( $rule ) {
⋮----
$transformer = TransformerService::create_transformer( $transform_args->use );
if ( ! $transformer->validate( $transform_args->arguments ) ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/OrderCountRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class OrderCountRuleProcessor implements RuleProcessorInterface {
⋮----
protected $orders_provider;
⋮----
public function __construct( $orders_provider = null ) {
⋮----
public function process( $rule, $stored_state ) {
$count = $this->orders_provider->get_order_count();
⋮----
return ComparisonOperation::compare(
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/OrdersProvider.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class OrdersProvider {
⋮----
protected $allowed_statuses = array(
⋮----
public function get_order_count() {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/OrRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class OrRuleProcessor implements RuleProcessorInterface {
⋮----
private $rule_evaluator;
⋮----
public function __construct( $rule_evaluator = null ) {
⋮----
public function process( $rule, $stored_state ) {
⋮----
$evaluated_operand = $this->rule_evaluator->evaluate(
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/PassRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class PassRuleProcessor implements RuleProcessorInterface {
⋮----
public function process( $rule, $stored_state ) {
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/PluginsActivatedRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
use Automattic\WooCommerce\Admin\PluginsProvider\PluginsProvider;
⋮----
class PluginsActivatedRuleProcessor implements RuleProcessorInterface {
⋮----
protected $plugins_provider;
⋮----
public function __construct( $plugins_provider = null ) {
⋮----
public function process( $rule, $stored_state ) {
⋮----
$active_plugin_slugs = $this->plugins_provider->get_active_plugin_slugs();
⋮----
$logger->warning(
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/PluginVersionRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
use Automattic\WooCommerce\Admin\PluginsProvider\PluginsProvider;
⋮----
class PluginVersionRuleProcessor implements RuleProcessorInterface {
⋮----
private $plugins_provider;
⋮----
public function __construct( $plugins_provider = null ) {
⋮----
public function process( $rule, $stored_state ) {
$active_plugin_slugs = $this->plugins_provider->get_active_plugin_slugs();
⋮----
$plugin_data = $this->plugins_provider->get_plugin_data( $plugin_name );
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/ProductCountRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
use Automattic\WooCommerce\Enums\ProductStatus;
⋮----
class ProductCountRuleProcessor implements RuleProcessorInterface {
⋮----
protected $product_query;
⋮----
public function __construct( $product_query = null ) {
⋮----
? new \WC_Product_Query(
⋮----
public function process( $rule, $stored_state ) {
$products = $this->product_query->get_products();
⋮----
return ComparisonOperation::compare(
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/PublishAfterTimeRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
use Automattic\WooCommerce\Admin\DateTimeProvider\CurrentDateTimeProvider;
⋮----
class PublishAfterTimeRuleProcessor implements RuleProcessorInterface {
⋮----
protected $date_time_provider;
⋮----
public function __construct( $date_time_provider = null ) {
⋮----
public function process( $rule, $stored_state ) {
return $this->date_time_provider->get_now() >= new \DateTime( $rule->publish_after );
⋮----
public function validate( $rule ) {
⋮----
new \DateTime( $rule->publish_after );
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/PublishBeforeTimeRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
use Automattic\WooCommerce\Admin\DateTimeProvider\CurrentDateTimeProvider;
⋮----
class PublishBeforeTimeRuleProcessor implements RuleProcessorInterface {
⋮----
protected $date_time_provider;
⋮----
public function __construct( $date_time_provider = null ) {
⋮----
public function process( $rule, $stored_state ) {
return $this->date_time_provider->get_now() <= new \DateTime( $rule->publish_before );
⋮----
public function validate( $rule ) {
⋮----
new \DateTime( $rule->publish_before );
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/README.md">
# Rule

Rules in an array are executed as an AND operation. If there are no rules in the array the result is false and the specified notification is not shown.

## Operations

Some rule types support an `operation` value, which is used to compare two
values. The following operations are implemented:

- `=`
- `<`
- `<=`
- `>`
- `>=`
- `!=`
- `contains`
- `!contains`
- `in` (Added in WooCommerce 8.2.0)
- `!in` (Added in WooCommerce 8.2.0)
- `range` (Added in WooCommerce 8.8.0)

### contains and !contains

`contains` and `!contains` allow checking if the provided value is present (or
not present) in the haystack value. An example of this is using the
`onboarding_profile` rule to match on a value in the `product_types` array -
this rule matches if `physical` was selected as a product type in the
onboarding profile:

```json
... (450 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/RuleEvaluator.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class RuleEvaluator {
⋮----
private $get_rule_processor;
⋮----
public function __construct( $get_rule_processor = null ) {
⋮----
public function evaluate( $rules, $stored_state = null, $logger_args = array() ) {
⋮----
throw new \InvalidArgumentException( 'Missing required field: slug in $logger_args.' );
⋮----
$evaluation_logger && $evaluation_logger->add_result( 'rule not an object', false );
$evaluation_logger && $evaluation_logger->log();
⋮----
$processor        = $this->get_rule_processor->get_processor( $rule->type );
$processor_result = $processor->process( $rule, $stored_state );
$evaluation_logger && $evaluation_logger->add_result( $rule->type, $processor_result );
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/RuleProcessorInterface.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
interface RuleProcessorInterface {
⋮----
public function process( $rule, $stored_state );
⋮----
public function validate( $rule );
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/StoredStateRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class StoredStateRuleProcessor implements RuleProcessorInterface {
⋮----
public function process( $rule, $stored_state ) {
⋮----
return ComparisonOperation::compare(
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/StoredStateSetupForProducts.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsEngine;
⋮----
class StoredStateSetupForProducts {
⋮----
public static function admin_init() {
⋮----
final public static function init() {
⋮----
public static function run_remote_notifications() {
RemoteInboxNotificationsEngine::run();
⋮----
public static function init_stored_state( $stored_state ) {
$stored_state->there_were_no_products = ! self::are_there_products();
⋮----
private static function are_there_products() {
$query    = new \WC_Product_Query(
⋮----
$products = $query->get_products();
⋮----
public static function run_on_product_importer() {
⋮----
self::update_stored_state_and_possibly_run_remote_notifications();
⋮----
public static function run_on_transition_post_status( $new_status, $old_status, $post ) {
⋮----
private static function update_stored_state_and_possibly_run_remote_notifications() {
$stored_state = RemoteInboxNotificationsEngine::get_stored_state();
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/TotalPaymentsVolumeProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Revenue\Query as RevenueQuery;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
use Automattic\WooCommerce\Admin\DateTimeProvider\CurrentDateTimeProvider;
use Automattic\WooCommerce\Admin\DateTimeProvider\DateTimeProviderInterface;
⋮----
class TotalPaymentsVolumeProcessor implements RuleProcessorInterface {
⋮----
protected $date_time_provider;
⋮----
public function __construct( $date_time_provider = null ) {
⋮----
public function process( $rule, $stored_state ) {
⋮----
$now   = ( new \DateTime( '@' . $this->date_time_provider->get_now()->getTimestamp() ) )->setTimezone( wp_timezone() );
$dates = TimeInterval::get_timeframe_dates( $rule->timeframe, $now );
⋮----
$reports_revenue = $this->get_reports_query(
⋮----
$report_data     = $reports_revenue->get_data();
⋮----
return ComparisonOperation::compare(
⋮----
public function validate( $rule ) {
⋮----
protected function get_reports_query( $args ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/WCAdminActiveForProvider.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
use Automattic\WooCommerce\Admin\WCAdminHelper;
⋮----
class WCAdminActiveForProvider {
⋮----
public function get_wcadmin_active_for_in_seconds() {
return WCAdminHelper::get_wcadmin_active_for_in_seconds();
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/WCAdminActiveForRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
class WCAdminActiveForRuleProcessor implements RuleProcessorInterface {
⋮----
protected $wcadmin_active_for_provider;
⋮----
public function __construct( $wcadmin_active_for_provider = null ) {
⋮----
public function process( $rule, $stored_state ) {
$active_for_seconds = $this->wcadmin_active_for_provider->get_wcadmin_active_for_in_seconds();
⋮----
return ComparisonOperation::compare(
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RuleProcessors/WooCommerceAdminUpdatedRuleProcessor.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
⋮----
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsEngine;
⋮----
class WooCommerceAdminUpdatedRuleProcessor implements RuleProcessorInterface {
⋮----
public function process( $rule, $stored_state ) {
⋮----
public function validate( $rule ) {
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/DataSourcePoller.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs;
⋮----
abstract class DataSourcePoller {
⋮----
abstract public static function get_instance();
⋮----
protected $id = array();
⋮----
protected $data_sources = array();
⋮----
protected $args = array();
⋮----
protected static $logger = null;
⋮----
public function __construct( $id, $data_sources = array(), $args = array() ) {
⋮----
protected static function get_logger() {
⋮----
protected function get_spec_key( $spec ) {
⋮----
public function get_specs_from_data_sources() {
⋮----
$this->read_specs_from_data_sources();
⋮----
public function get_cached_specs() {
⋮----
public function read_specs_from_data_sources() {
⋮----
$specs_from_data_source = self::read_data_source( $url );
$this->merge_specs( $specs_from_data_source, $specs, $url );
... (27 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/RemoteSpecs/RemoteSpecsEngine.php">
namespace Automattic\WooCommerce\Admin\RemoteSpecs;
⋮----
abstract class RemoteSpecsEngine {
⋮----
public static function log_errors( $errors = array() ) {
⋮----
$error_messages[] = $error->getMessage();
⋮----
$logger->error(
</file>

<file path="plugins/woocommerce/src/Admin/Schedulers/SchedulerTraits.php">
namespace Automattic\WooCommerce\Admin\Schedulers;
⋮----
trait SchedulerTraits {
⋮----
public static $group = 'wc-admin-data';
⋮----
protected static $queue = null;
⋮----
public static function init() {
foreach ( self::get_actions() as $action_name => $action_hook ) {
$method = new \ReflectionMethod( static::class, $action_name );
add_action( $action_hook, array( static::class, 'do_action_or_reschedule' ), 10, $method->getNumberOfParameters() );
⋮----
public static function queue() {
⋮----
self::$queue = WC()->queue();
⋮----
public static function set_queue( $queue ) {
⋮----
public static function get_default_scheduler_actions() {
⋮----
public static function get_scheduler_actions() {
⋮----
public static function get_actions() {
⋮----
static::get_default_scheduler_actions(),
static::get_scheduler_actions()
⋮----
public static function get_action( $action_name ) {
$actions = static::get_actions();
... (72 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Settings/AGENTS.md">
# Settings UI

These classes power the Settings UI renderer for classic `wc-settings` pages. They are autoloaded modern code, but they are called from legacy code (`includes/admin/settings/`, `includes/admin/views/html-admin-settings.php`) that runs on every settings request.

## Mid-update fatal guard (required for every change)

During a plugin update, a request can pair new files on disk with stale cached classes (or the reverse). The settings surface renders wp-admin, so one unguarded call in that window white-screens the settings page. The 10.9.1 release was reverted on WP Cloud for exactly this bug class.

Rules for this package and its call sites:

- Code reachable from `includes/`, templates, or hook callbacks must call `SettingsUIRequestContext` (and the other classes here) either through methods that exist since WooCommerce 10.9, or inside a `class_exists` check plus `try/catch (\Throwable)` that falls back to legacy rendering. 10.9.x is the oldest release shipping these classes, so it is the version a stale class can be. Methods added after 10.9 include `is_drill_down()`, `get_settings_page()`, `has_script_handle_loading_failed()`, `enqueue_script_handles()`, and `get_schema_failure_reason()`; calls to these methods must stay inside the guarded fallback boundary.
- Public and protected method signatures are additive only. Never remove or change one; deprecate and keep it working.
- Never delete or rename a class file that has shipped in a release. A stale classmap entry pointing at a missing file fatals inside the autoloader, where no guard can catch it.
- Never add a required method to an interface here. Stale implementers fail at class-link time, uncatchably. Add a concrete default to the `SettingsSection` base class instead, the way `SettingsSectionUIPageProviderInterface` was introduced.

Guarded call sites to copy from: `includes/admin/views/html-admin-settings.php`, `WC_Settings_Page::add_settings_ui_body_class()`, `Settings::add_settings_ui_schema()`, `WCAdminAssets::get_settings_ui_script_dependencies()`.
</file>

<file path="plugins/woocommerce/src/Admin/Settings/LegacySettingsPageAdapter.php">
namespace Automattic\WooCommerce\Admin\Settings;
⋮----
class LegacySettingsPageAdapter extends \Automattic\WooCommerce\Internal\Admin\Settings\LegacySettingsPageAdapter {}
</file>

<file path="plugins/woocommerce/src/Admin/Settings/SettingsSection.php">
namespace Automattic\WooCommerce\Admin\Settings;
⋮----
abstract class SettingsSection implements SettingsSectionInterface, SettingsSectionUIPageProviderInterface {
⋮----
public function get_settings_ui_page( \WC_Settings_Page $parent_page ): ?SettingsUIPageInterface {
⋮----
public function get_script_handles( \WC_Settings_Page $parent_page ): array {
⋮----
public function get_save_adapter( \WC_Settings_Page $parent_page ): string {
</file>

<file path="plugins/woocommerce/src/Admin/Settings/SettingsSectionInterface.php">
namespace Automattic\WooCommerce\Admin\Settings;
⋮----
interface SettingsSectionInterface {
⋮----
public function get_parent_page_id(): string;
⋮----
public function get_id(): string;
⋮----
public function get_label(): string;
⋮----
public function get_settings( \WC_Settings_Page $parent_page ): array;
⋮----
public function get_script_handles( \WC_Settings_Page $parent_page ): array;
⋮----
public function get_save_adapter( \WC_Settings_Page $parent_page ): string;
</file>

<file path="plugins/woocommerce/src/Admin/Settings/SettingsSectionRegistry.php">
namespace Automattic\WooCommerce\Admin\Settings;
⋮----
final class SettingsSectionRegistry {
⋮----
private static ?SettingsSectionRegistry $instance = null;
⋮----
private array $sections = array();
⋮----
private bool $initialized = false;
⋮----
public static function get_instance(): SettingsSectionRegistry {
⋮----
public function register( SettingsSectionInterface $section ): bool {
$parent_page_id = $this->normalize_id( $section->get_parent_page_id() );
$section_id     = $this->normalize_id( $section->get_id() );
⋮----
if ( $this->is_reserved_checkout_section_id( $parent_page_id, $section_id ) ) {
⋮----
public function get_registered( string $parent_page_id, string $section_id ): ?SettingsSectionInterface {
$this->initialize();
⋮----
$parent_page_id = $this->normalize_id( $parent_page_id );
$section_id     = $this->normalize_id( $section_id );
⋮----
public function get_sections_for_page( string $parent_page_id ): array {
⋮----
$sections[ $section_id ] = $section->get_label();
⋮----
public function unregister_all(): void {
⋮----
... (20 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/Settings/SettingsSectionUIPageProviderInterface.php">
namespace Automattic\WooCommerce\Admin\Settings;
⋮----
interface SettingsSectionUIPageProviderInterface {
⋮----
public function get_settings_ui_page( \WC_Settings_Page $parent_page ): ?SettingsUIPageInterface;
</file>

<file path="plugins/woocommerce/src/Admin/Settings/SettingsUIPageInterface.php">
namespace Automattic\WooCommerce\Admin\Settings;
⋮----
interface SettingsUIPageInterface {
⋮----
public function get_page_id(): string;
⋮----
public function get_schema( string $section ): array;
⋮----
public function get_script_handles( string $section ): array;
⋮----
public function get_save_adapter( string $section ): string;
</file>

<file path="plugins/woocommerce/src/Admin/Settings/SettingsUISchema.php">
namespace Automattic\WooCommerce\Admin\Settings;
⋮----
class SettingsUISchema extends \Automattic\WooCommerce\Internal\Admin\Settings\SettingsUISchema {}
</file>

<file path="plugins/woocommerce/src/Admin/DataSourcePoller.php">
namespace Automattic\WooCommerce\Admin;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller as RemoteSpecsDataSourcePoller;
⋮----
abstract class DataSourcePoller extends RemoteSpecsDataSourcePoller {
⋮----
private static function log_deprecation() {
⋮----
public function __construct( $id, $data_sources = array(), $args = array() ) {
self::log_deprecation();
parent::__construct( $id, $data_sources, $args );
⋮----
public function get_specs_from_data_sources() {
⋮----
return parent::get_specs_from_data_sources();
⋮----
public function read_specs_from_data_sources() {
⋮----
return parent::read_specs_from_data_sources();
⋮----
public function delete_specs_transient() {
⋮----
return parent::delete_specs_transient();
⋮----
public function set_specs_transient( $specs, $expiration = 0 ) {
⋮----
return parent::set_specs_transient( $specs, $expiration );
</file>

<file path="plugins/woocommerce/src/Admin/DeprecatedClassFacade.php">
namespace Automattic\WooCommerce\Admin;
⋮----
class DeprecatedClassFacade {
⋮----
protected $instance;
⋮----
protected static $facade_over_classname = '';
⋮----
/**
	 * The version that this class was deprecated in.
	 *
	 * @var string
	 */
protected static $deprecated_in_version = '';
⋮----
/**
	 * Static array of logged messages.
	 *
	 * @var array
	 */
private static $logged_messages = array();
⋮----
/**
	 * Constructor.
	 */
public function __construct() {
⋮----
/**
	 * Log a deprecation to the error log.
	 *
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/FeaturePlugin.php">
namespace Automattic\WooCommerce\Admin;
⋮----
class FeaturePlugin extends DeprecatedClassFacade {
⋮----
protected static $facade_over_classname = 'Automattic\WooCommerce\Internal\Admin\FeaturePlugin';
⋮----
protected static $deprecated_in_version = '6.4.0';
⋮----
protected function __construct() {}
⋮----
final public static function instance() {
⋮----
public function init() {}
</file>

<file path="plugins/woocommerce/src/Admin/Loader.php">
namespace Automattic\WooCommerce\Admin;
⋮----
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
⋮----
class Loader extends DeprecatedClassFacade {
⋮----
protected static $facade_over_classname = 'Automattic\WooCommerce\Internal\Admin\Loader';
⋮----
protected static $deprecated_in_version = '6.3.0';
⋮----
public static function is_feature_enabled( $feature ) {
⋮----
return Features::is_enabled( $feature );
⋮----
public static function is_admin_or_embed_page() {
⋮----
return PageController::is_admin_or_embed_page();
⋮----
public static function is_admin_page() {
⋮----
return PageController::is_admin_page();
⋮----
public static function is_embed_page() {
⋮----
return PageController::is_embed_page();
⋮----
public static function should_use_minified_js_file( $script_debug ) {
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/PageController.php">
namespace Automattic\WooCommerce\Admin;
⋮----
use Automattic\WooCommerce\Internal\Admin\Loader;
⋮----
use WC_Gateway_BACS;
use WC_Gateway_Cheque;
use WC_Gateway_COD;
use WC_Gateway_Paypal;
⋮----
class PageController {
⋮----
private static $instance = false;
⋮----
private $current_page = null;
⋮----
private $pages = array();
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
public function connect_page( $options ) {
⋮----
/**
	 * Determine the current page ID, if it was registered with this controller.
	 */
public function determine_current_page() {
⋮----
$current_screen_id = $this->get_current_screen_id();
⋮----
... (50 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/PluginsHelper.php">
namespace Automattic\WooCommerce\Admin;
⋮----
use ActionScheduler;
use ActionScheduler_DBStore;
use ActionScheduler_QueueRunner;
use Automatic_Upgrader_Skin;
use Automattic\WooCommerce\Admin\PluginsInstallLoggers\AsyncPluginsInstallLogger;
use Automattic\WooCommerce\Admin\PluginsInstallLoggers\PluginsInstallLogger;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
use Automattic\WooCommerce\Utilities\PluginUtil;
use Plugin_Upgrader;
use WC_Helper;
use WC_Helper_Updater;
use WP_Error;
use WP_Upgrader;
⋮----
class PluginsHelper {
⋮----
public static $subscription_usage_notices_already_shown = false;
⋮----
public static function init() {
⋮----
public static function get_plugin_path_from_slug( $slug ) {
⋮----
public static function get_installed_plugin_slugs() {
⋮----
public static function get_installed_plugins_paths() {
⋮----
public static function get_active_plugin_slugs() {
⋮----
... (269 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/PluginsInstaller.php">
namespace Automattic\WooCommerce\Admin;
⋮----
use Automattic\WooCommerce\Admin\API\Plugins;
use Automattic\WooCommerce\Admin\Features\TransientNotices;
⋮----
class PluginsInstaller {
⋮----
public static function init() {
⋮----
public static function possibly_install_activate_plugins() {
⋮----
$install_result = $plugins_api->install_plugins( array( 'plugins' => $plugins ) );
⋮----
$activate_result = $plugins_api->activate_plugins( array( 'plugins' => $plugins ) );
⋮----
$install_result  = $plugins_api->install_plugins( array( 'plugins' => $plugins ) );
$activate_result = $plugins_api->activate_plugins( array( 'plugins' => implode( ',', $install_result['data']['installed'] ) ) );
⋮----
self::cache_results( $plugins, $install_result, $activate_result );
self::redirect_to_referer();
⋮----
public static function cache_results( $plugins, $install_result, $activate_result ) {
⋮----
$message = $activate_result ? $activate_result->get_error_message() : $install_result->get_error_message();
⋮----
TransientNotices::add(
⋮----
public static function redirect_to_referer() {
</file>

<file path="plugins/woocommerce/src/Admin/ReportCSVEmail.php">
namespace Automattic\WooCommerce\Admin;
⋮----
class ReportCSVEmail extends \WC_Email {
⋮----
protected $report_labels;
⋮----
protected $report_type;
⋮----
protected $download_url;
⋮----
protected $report_date_range = '';
⋮----
/**
	 * Constructor.
	 */
public function __construct() {
⋮----
$this->template_base  = WC()->plugin_path() . '/includes/react-admin/emails/';
⋮----
parent::__construct();
⋮----
public function init_form_fields() {}
⋮----
public function init_settings() {}
⋮----
public function get_email_type() {
⋮----
public function get_default_heading() {
⋮----
public function get_default_subject() {
... (50 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/ReportCSVExporter.php">
namespace Automattic\WooCommerce\Admin;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\ExportableInterface;
⋮----
class ReportCSVExporter extends \WC_CSV_Batch_Exporter {
⋮----
protected $report_type;
⋮----
protected $report_args;
⋮----
protected $controller;
⋮----
protected $download_suffix = '';
⋮----
/**
	 * Constructor.
	 *
	 * @param string $type Report type. E.g. 'customers'.
	 * @param array  $args Report parameters.
	 */
public function __construct( $type = false, $args = array() ) {
parent::__construct();
⋮----
self::maybe_create_directory();
⋮----
$this->set_report_type( $type );
$this->set_column_names( $this->get_report_columns() );
⋮----
$this->set_report_args( $args );
⋮----
... (105 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/ReportExporter.php">
namespace Automattic\WooCommerce\Admin;
⋮----
use Automattic\WooCommerce\Admin\Schedulers\SchedulerTraits;
use Automattic\WooCommerce\Utilities\TimeUtil;
⋮----
class ReportExporter {
⋮----
public static $name = 'report_exporter';
⋮----
public static function get_scheduler_actions() {
⋮----
public static function get_dependencies() {
⋮----
'email_report_download_link' => self::get_action( 'export_report' ),
⋮----
public static function init() {
⋮----
self::scheduler_init();
⋮----
self::init_export_files();
⋮----
public static function init_export_files() {
⋮----
public static function delete_expired_exports() {
⋮----
$paths = glob( ReportCSVExporter::get_reports_directory() . '*.csv*' );
⋮----
public static function queue_report_export( $export_id, $report_type, $report_args = array(), $send_email = false ) {
⋮----
$exporter->prepare_data_to_export();
... (85 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/ReportsSync.php">
namespace Automattic\WooCommerce\Admin;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
use Automattic\WooCommerce\Internal\Admin\Schedulers\CustomersScheduler;
use Automattic\WooCommerce\Internal\Admin\Schedulers\OrdersScheduler;
use Automattic\WooCommerce\Internal\Admin\Schedulers\ImportScheduler;
⋮----
class ReportsSync {
⋮----
public static function init() {
⋮----
foreach ( self::get_schedulers() as $scheduler ) {
$scheduler::init();
⋮----
public static function get_schedulers() {
⋮----
throw new \Exception( __( 'Report sync schedulers should be derived from the Automattic\WooCommerce\Internal\Admin\Schedulers\ImportScheduler class.', 'woocommerce' ) );
⋮----
public static function is_importing() {
⋮----
if ( $scheduler::is_importing() ) {
⋮----
public static function regenerate_report_data( $days, $skip_existing ) {
if ( self::is_importing() ) {
return new \WP_Error( 'wc_admin_import_in_progress', __( 'An import is already in progress. Please allow the previous import to complete before beginning a new one.', 'woocommerce' ) );
⋮----
self::reset_import_stats( $days, $skip_existing );
⋮----
OrdersScheduler::reset_failed_order_imports_overflow();
⋮----
... (32 lines truncated)
</file>

<file path="plugins/woocommerce/src/Admin/WCAdminHelper.php">
namespace Automattic\WooCommerce\Admin;
⋮----
class WCAdminHelper {
⋮----
public static function get_wcadmin_active_for_in_seconds() {
⋮----
public static function is_wc_admin_active_for( $seconds ) {
$wc_admin_active_for = self::get_wcadmin_active_for_in_seconds();
⋮----
public static function is_wc_admin_active_in_date_range( $range, $custom_start = null ) {
⋮----
throw new \InvalidArgumentException(
⋮----
public static function is_site_fresh() {
⋮----
$date      = new \DateTime( $current_userdata->user_registered );
$month_ago = new \DateTime( '-1 month' );
⋮----
public static function is_current_page_store_page() {
⋮----
$url = self::get_url_from_wp( $wp );
⋮----
public static function is_store_page( $url = '' ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
⋮----
return self::is_current_page_store_page();
⋮----
private static function get_url_from_wp( \WP $wp ) {
⋮----
$wp->parse_request();
</file>

<file path="plugins/woocommerce/src/Blocks/AI/Configuration.php">
namespace Automattic\WooCommerce\Blocks\AI;
⋮----
class Configuration {}
</file>

<file path="plugins/woocommerce/src/Blocks/AI/Connection.php">
namespace Automattic\WooCommerce\Blocks\AI;
⋮----
class Connection {}
</file>

<file path="plugins/woocommerce/src/Blocks/AIContent/ContentProcessor.php">
namespace Automattic\WooCommerce\Blocks\AIContent;
⋮----
class ContentProcessor {}
</file>

<file path="plugins/woocommerce/src/Blocks/AIContent/PatternsDictionary.php">
namespace Automattic\WooCommerce\Blocks\AIContent;
⋮----
class PatternsDictionary {}
</file>

<file path="plugins/woocommerce/src/Blocks/AIContent/PatternsHelper.php">
namespace Automattic\WooCommerce\Blocks\AIContent;
⋮----
class PatternsHelper {}
</file>

<file path="plugins/woocommerce/src/Blocks/AIContent/UpdatePatterns.php">
namespace Automattic\WooCommerce\Blocks\AIContent;
⋮----
class UpdatePatterns {
</file>

<file path="plugins/woocommerce/src/Blocks/AIContent/UpdateProducts.php">
namespace Automattic\WooCommerce\Blocks\AIContent;
⋮----
class UpdateProducts {
</file>

<file path="plugins/woocommerce/src/Blocks/Assets/Api.php">
namespace Automattic\WooCommerce\Blocks\Assets;
⋮----
use Automattic\WooCommerce\Blocks\Domain\Package;
use Exception;
use Automattic\Jetpack\Constants;
⋮----
class Api {
⋮----
public $wc_version;
⋮----
private $inline_scripts = [];
⋮----
private $disable_cache = false;
⋮----
private $script_data = null;
⋮----
private $script_data_modified = false;
⋮----
private $script_data_hash;
⋮----
private $script_data_transient_key = 'woocommerce_blocks_asset_api_script_data';
⋮----
private $package;
⋮----
public function __construct( Package $package ) {
⋮----
$this->wc_version    = 'wc-' . Constants::get_constant( 'WC_VERSION' );
⋮----
$this->script_data_hash = $this->get_script_data_hash();
⋮----
... (57 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Assets/AssetDataRegistry.php">
namespace Automattic\WooCommerce\Blocks\Assets;
⋮----
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use Automattic\WooCommerce\Blocks\Domain\Services\Hydration;
use Automattic\WooCommerce\Internal\Logging\RemoteLogger;
use Automattic\WooCommerce\Internal\Utilities\PriceSeparators;
use Exception;
use InvalidArgumentException;
⋮----
class AssetDataRegistry {
⋮----
private $data = [];
⋮----
private $preloaded_api_requests = [];
⋮----
private $lazy_data = [];
⋮----
private $handle = 'wc-settings';
⋮----
private $api;
⋮----
public function __construct( Api $asset_api ) {
⋮----
$this->init();
⋮----
protected function init() {
⋮----
protected function get_core_data() {
... (106 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Accordion/AccordionGroup.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Accordion;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
⋮----
class AccordionGroup extends AbstractBlock {
⋮----
protected $block_name = 'accordion-group';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$p = new \WP_HTML_Tag_Processor( $content );
⋮----
if ( $p->next_tag( array( 'class_name' => 'wp-block-woocommerce-accordion-group' ) ) ) {
⋮----
$p->set_attribute( 'data-wp-interactive', 'woocommerce/accordion' );
$p->set_attribute( 'data-wp-context', wp_json_encode( $interactivity_context, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP ) );
⋮----
$content = $p->get_updated_html();
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Accordion/AccordionHeader.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Accordion;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
⋮----
class AccordionHeader extends AbstractBlock {
⋮----
protected $block_name = 'accordion-header';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Accordion/AccordionItem.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Accordion;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
⋮----
class AccordionItem extends AbstractBlock {
⋮----
protected $block_name = 'accordion-item';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$p         = new \WP_HTML_Tag_Processor( $content );
⋮----
if ( $p->next_tag( array( 'class_name' => 'wp-block-woocommerce-accordion-item' ) ) ) {
⋮----
$p->set_attribute( 'data-wp-context', wp_json_encode( $interactivity_context, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP ) );
$p->set_attribute( 'data-wp-class--is-open', 'state.isOpen' );
$p->set_attribute( 'data-wp-init', 'callbacks.initIsOpen' );
⋮----
if ( $p->next_tag( array( 'class_name' => 'accordion-item__toggle' ) ) ) {
$p->set_attribute( 'data-wp-on--click', 'actions.toggle' );
$p->set_attribute( 'id', $unique_id );
$p->set_attribute( 'aria-controls', $unique_id . '-panel' );
$p->set_attribute( 'data-wp-bind--aria-expanded', 'state.isOpen' );
⋮----
if ( $p->next_tag( array( 'class_name' => 'wp-block-woocommerce-accordion-panel' ) ) ) {
$p->set_attribute( 'id', $unique_id . '-panel' );
$p->set_attribute( 'aria-labelledby', $unique_id );
$p->set_attribute( 'role', 'region' );
$p->set_attribute( 'data-wp-bind--inert', '!state.isOpen' );
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Accordion/AccordionPanel.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Accordion;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
⋮----
class AccordionPanel extends AbstractBlock {
⋮----
protected $block_name = 'accordion-panel';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/AddToCartWithOptions.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Blocks\Utils\Utils as BlocksUtils;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
use Automattic\WooCommerce\Internal\ShopperLists\ShopperListsController;
⋮----
class AddToCartWithOptions extends AbstractBlock {
⋮----
protected $block_name = 'add-to-cart-with-options';
⋮----
protected function get_template_part_path( $product_type ) {
⋮----
return Package::get_path() . 'templates/' . BlockTemplateUtils::DIRECTORY_NAMES['TEMPLATE_PARTS'] . '/' . $product_type . '-product-add-to-cart-with-options.html';
⋮----
private function get_product_type_for_add_to_cart_template( \WC_Product $product ): string {
return ProductType::VARIATION === $product->get_type() ? ProductType::SIMPLE : $product->get_type();
⋮----
protected function enqueue_assets( $attributes, $content, $block ) {
⋮----
$product_type       = $this->get_product_type_for_add_to_cart_template( $rendered_product );
$template_part_path = $this->get_template_part_path( $product_type );
⋮----
parent::enqueue_assets( $attributes, $content, $block );
⋮----
protected function enqueue_data( array $attributes = array() ): void {
... (85 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/GroupedProductItem.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
use WP_Block;
⋮----
class GroupedProductItem extends AbstractBlock {
⋮----
protected $block_name = 'add-to-cart-with-options-grouped-product-item';
⋮----
public function set_is_descendant_of_grouped_product_selector_context( $context, $block ) {
⋮----
private function get_product_row( $product_id, $attributes, $block ): string {
⋮----
$block_content = $new_block->render( array( 'dynamic' => false ) );
⋮----
protected function render( $attributes, $content, $block ): string {
⋮----
// No need to prime post caches here, children are already cached at this point.
$children = array_filter( array_map( 'wc_get_product', $product->get_children() ), 'wc_products_array_filter_visible_grouped' );
⋮----
$content .= $this->get_product_row( $child->get_id(), $attributes, $block );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/GroupedProductItemLabel.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
use Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions\Utils as AddToCartWithOptionsUtils;
use WP_Block;
⋮----
class GroupedProductItemLabel extends AbstractBlock {
⋮----
protected $block_name = 'add-to-cart-with-options-grouped-product-item-label';
⋮----
protected function render( $attributes, $content, $block ): string {
$product = AddToCartWithOptionsUtils::get_product_from_context( $block, $GLOBALS['product'] );
⋮----
$title              = $product->get_name();
⋮----
if ( ! $product->is_purchasable() || $product->has_options() || ! $product->is_in_stock() ) {
⋮----
// Checkbox.
⋮----
esc_attr( 'quantity_' . $product->get_id() ),
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/GroupedProductItemSelector.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
use Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions\Utils as AddToCartWithOptionsUtils;
use WP_Block;
⋮----
class GroupedProductItemSelector extends AbstractBlock {
⋮----
protected $block_name = 'add-to-cart-with-options-grouped-product-item-selector';
⋮----
public function set_quantity_input_type() {
⋮----
private function get_quantity_selector_markup( $product ) {
⋮----
$min_value = $product->get_min_purchase_quantity();
$max_value = $product->get_max_purchase_quantity();
⋮----
'input_name'  => 'quantity[' . $product->get_id() . ']',
'input_id'    => 'quantity_' . $product->get_id(),
'input_value' => isset( $_POST['quantity'][ $product->get_id() ] ) ? wc_stock_amount( wc_clean( wp_unslash( $_POST['quantity'][ $product->get_id() ] ) ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing
⋮----
$quantity_html = $this->remove_quantity_label( $quantity_html );
⋮----
$product_name = $product->get_name();
⋮----
$quantity_html = AddToCartWithOptionsUtils::add_quantity_steppers( $quantity_html, $product_name );
$quantity_html = AddToCartWithOptionsUtils::add_quantity_stepper_classes( $quantity_html );
⋮----
$quantity_html = AddToCartWithOptionsUtils::make_quantity_input_interactive( $quantity_html, array(), array(), $context, true );
... (54 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/GroupedProductSelector.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class GroupedProductSelector extends AbstractBlock {
⋮----
protected $block_name = 'add-to-cart-with-options-grouped-product-selector';
⋮----
protected function render( $attributes, $content, $block ): string {
⋮----
if ( $product instanceof \WC_Product && $product->is_type( ProductType::GROUPED ) ) {
⋮----
$p = new \WP_HTML_Tag_Processor( $content );
⋮----
if ( $p->next_tag( array( 'class_name' => 'wp-block-woocommerce-add-to-cart-with-options-grouped-product-selector' ) ) ) {
$p->set_attribute( 'data-wp-init', 'callbacks.validateQuantities' );
⋮----
return $p->get_updated_html();
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/QuantitySelector.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
use Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions\Utils as AddToCartWithOptionsUtils;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class QuantitySelector extends AbstractBlock {
⋮----
protected $block_name = 'add-to-cart-with-options-quantity-selector';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$product = AddToCartWithOptionsUtils::get_product_from_context( $block, $previous_product );
⋮----
if ( AddToCartWithOptionsUtils::is_not_purchasable_product( $product ) ) {
⋮----
$is_external_product_with_url        = $product instanceof \WC_Product_External && $product->get_product_url();
$can_only_be_purchased_one_at_a_time = $product->is_sold_individually();
$managing_stock                      = $product->managing_stock();
$stock_quantity                      = $product->get_stock_quantity();
$allows_backorders                   = $product->backorders_allowed();
⋮----
if ( AddToCartWithOptionsUtils::is_min_max_quantity_same( $product ) ) {
⋮----
'min_value'   => $product->get_min_purchase_quantity(),
'max_value'   => $product->get_max_purchase_quantity(),
'input_value' => isset( $_POST['quantity'] ) ? wc_stock_amount( wp_unslash( $_POST['quantity'] ) ) : $product->get_min_purchase_quantity(),
⋮----
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/Utils.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions;
⋮----
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class Utils {
⋮----
public static function has_visible_quantity_input( $html_content ) {
$processor = new \WP_HTML_Tag_Processor( $html_content );
⋮----
while ( $processor->next_tag() ) {
⋮----
$processor->get_tag() === 'INPUT' &&
$processor->has_class( 'qty' ) &&
$processor->get_attribute( 'type' ) !== 'hidden'
⋮----
public static function add_quantity_steppers( $quantity_html, $product_name ) {
⋮----
// Add the plus button AFTER the matched <input> element.
⋮----
/* translators: %s refers to the item name in the cart. */
⋮----
/**
	 * Add classes to the Quantity Selector needed for the stepper style.
	 *
	 * @param string $quantity_html The Quantity Selector HTML.
	 *
	 * @return string The Quantity Selector HTML with classes added.
	 */
public static function add_quantity_stepper_classes( $quantity_html ) {
$processor = new \WP_HTML_Tag_Processor( $quantity_html );
... (67 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/VariationDescription.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
⋮----
class VariationDescription extends AbstractBlock {
⋮----
protected $block_name = 'add-to-cart-with-options-variation-description';
⋮----
protected function render( $attributes, $content, $block ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/VariationSelector.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class VariationSelector extends AbstractBlock {
⋮----
protected $block_name = 'add-to-cart-with-options-variation-selector';
⋮----
protected function render( $attributes, $content, $block ): string {
⋮----
if ( $product instanceof \WC_Product && $product->is_type( ProductType::VARIABLE ) && ! Utils::is_not_purchasable_product( $product ) ) {
$p = new \WP_HTML_Tag_Processor( $content );
⋮----
if ( $p->next_tag( array( 'class_name' => 'wp-block-woocommerce-add-to-cart-with-options-variation-selector' ) ) ) {
$p->set_attribute( 'data-wp-watch', 'callbacks.setSelectedVariationId' );
$p->set_attribute( 'data-wp-watch--validate', 'callbacks.validateVariation' );
⋮----
return $p->get_updated_html();
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/VariationSelectorAttribute.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
use Automattic\WooCommerce\Internal\ProductAttributes\VisualAttributeTermMeta;
use WP_Block;
⋮----
class VariationSelectorAttribute extends AbstractBlock {
⋮----
protected $block_name = 'add-to-cart-with-options-variation-selector-attribute';
⋮----
protected function enqueue_data( array $attributes = array() ): void {
parent::enqueue_data( $attributes );
⋮----
$this->asset_data_registry->add(
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$product_attributes            = $product->get_variation_attributes();
$available_values_by_attribute = $this->get_available_variation_values_by_attribute_slug();
⋮----
$content .= $this->render_attribute_row( $product_attribute_name, $product_attribute_terms, $block, $attributes, $available_values_by_attribute );
⋮----
/**
	 * Get attribute row HTML.
	 *
	 * @param string   $attribute_name Product Attribute Name.
	 * @param array    $product_attribute_terms Product Attribute Terms.
	 * @param WP_Block $block The Block.
	 * @param array    $attributes Template block attributes (displayStyle, autoselect, etc.).
... (47 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/VariationSelectorAttributeName.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class VariationSelectorAttributeName extends AbstractBlock {
⋮----
protected $block_name = 'add-to-cart-with-options-variation-selector-attribute-name';
⋮----
protected function render( $attributes, $content, $block ): string {
⋮----
$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes, array(), array( 'extra_classes' ) );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/AbstractOrderConfirmationBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
abstract class AbstractOrderConfirmationBlock extends AbstractBlock {
⋮----
protected function get_hook_content( $hook, $args ) {
⋮----
protected function render( $attributes, $content, $block ) {
$order              = $this->get_order();
$permission         = $this->get_view_order_permissions( $order );
$block_content      = $order ? $this->render_content( $order, $permission, $attributes, $content ) : $this->render_content_fallback();
$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes );
⋮----
/**
	 * This renders the content of the block within the wrapper. The permission determines what data can be shown under
	 * the given context.
	 *
	 * @param \WC_Order    $order Order object.
	 * @param string|false $permission If the current user can view the order details or not.
	 * @param array        $attributes Block attributes.
	 * @param string       $content Original block content.
	 * @return string
	 */
abstract protected function render_content( $order, $permission = false, $attributes = [], $content = '' );
⋮----
/**
	 * This is what gets rendered when the order does not exist. Renders nothing by default, but can be overridden by
	 * child classes.
... (67 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/AdditionalFields.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
⋮----
class AdditionalFields extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-additional-fields';
⋮----
protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) {
⋮----
/**
		 * Service class managing checkout fields and its related extensibility points.
		 *
		 * @var CheckoutFields $controller
		 */
$controller = Package::container()->get( CheckoutFields::class );
$content   .= $this->render_additional_fields(
$controller->filter_fields_for_order_confirmation(
⋮----
$controller->get_order_additional_fields_with_values( $order, 'contact', 'other', 'view' ),
$controller->get_order_additional_fields_with_values( $order, 'order', 'other', 'view' ),
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/AdditionalFieldsWrapper.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
⋮----
class AdditionalFieldsWrapper extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-additional-fields-wrapper';
⋮----
protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) {
⋮----
// Contact and additional fields are currently grouped in this section.
// If none of the additional fields for contact or order have values then the "Additional fields' section should
⋮----
Package::container()->get( CheckoutFields::class )->get_order_additional_fields_with_values( $order, 'contact' ),
Package::container()->get( CheckoutFields::class )->get_order_additional_fields_with_values( $order, 'order' )
⋮----
/**
	 * Extra data passed through from server to client for block.
	 *
	 * @param array $attributes  Any attributes that currently are available from the block.
	 *                           Note, this will be empty in the editor context when the block is
	 *                           not in the post content on editor load.
	 */
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
$this->asset_data_registry->add( 'additionalFields', Package::container()->get( CheckoutFields::class )->get_fields_for_location( 'order' ) );
$this->asset_data_registry->add( 'additionalContactFields', Package::container()->get( CheckoutFields::class )->get_fields_for_location( 'contact' ) );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/AdditionalInformation.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
class AdditionalInformation extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-additional-information';
⋮----
protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) {
⋮----
$this->remove_core_hooks();
$content .= $this->get_hook_content( 'woocommerce_thankyou_' . $order->get_payment_method(), [ $order->get_id() ] );
$content .= $this->get_hook_content( 'woocommerce_thankyou', [ $order->get_id() ] );
$this->restore_core_hooks();
⋮----
protected function remove_core_hooks() {
⋮----
protected function restore_core_hooks() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/BillingAddress.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
⋮----
class BillingAddress extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-billing-address';
⋮----
protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) {
if ( ! $permission || ! $order->has_billing_address() ) {
⋮----
$address = '<address>' . wp_kses_post( $order->get_formatted_billing_address() ) . '</address>';
$phone   = $order->get_billing_phone() ? '<p class="woocommerce-customer-details--phone">' . esc_html( $order->get_billing_phone() ) . '</p>' : '';
⋮----
$controller = Package::container()->get( CheckoutFields::class );
$custom     = $this->render_additional_fields(
$controller->filter_fields_for_order_confirmation(
$controller->get_order_additional_fields_with_values( $order, 'address', 'billing', 'view' ),
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
$this->asset_data_registry->add( 'additionalAddressFields', Package::container()->get( CheckoutFields::class )->get_fields_for_location( 'address' ) );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/BillingWrapper.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
class BillingWrapper extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-billing-wrapper';
⋮----
protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) {
if ( ! $order || ! $order->has_billing_address() || ! $permission ) {
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/CreateAccount.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
use Automattic\WooCommerce\StoreApi\Utilities\OrderController;
use Automattic\WooCommerce\Admin\Features\Features;
⋮----
class CreateAccount extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-create-account';
⋮----
protected function initialize() {
parent::initialize();
⋮----
if ( $this->is_feature_enabled() ) {
$this->initialize_hooks();
⋮----
protected function initialize_hooks() {
⋮----
if ( ! str_contains( $context->content, '<!-- wp:' . $this->get_full_block_name() ) ) {
$hooked_block_types[] = $this->get_full_block_name();
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
'path'         => $this->asset_api->get_block_asset_build_path( 'order-confirmation-create-account-frontend' ),
⋮----
protected function is_feature_enabled() {
⋮----
protected function process_form_post( $order ) {
⋮----
return new \WP_Error( 'invalid_nonce', __( 'Unable to create account. Please try again.', 'woocommerce' ) );
⋮----
... (57 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/Downloads.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class Downloads extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-downloads';
⋮----
protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) {
$show_downloads = $order && $order->has_downloadable_item() && $order->is_download_permitted();
$downloads      = $order ? $order->get_downloadable_items() : [];
⋮----
return $this->render_content_fallback();
⋮----
$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes, [ 'border_color', 'border_radius', 'border_width', 'border_style', 'background_color', 'text_color' ] );
⋮----
' . $this->render_order_downloads_column_headers() . '
⋮----
' . $this->render_order_downloads( $order, $downloads ) . '
⋮----
protected function get_inline_styles( array $attributes ) {
$link_classes_and_styles       = StyleAttributesUtils::get_link_color_class_and_style( $attributes );
$link_hover_classes_and_styles = StyleAttributesUtils::get_link_hover_color_class_and_style( $attributes );
$border_classes_and_styles     = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes, [ 'border_color', 'border_radius', 'border_width', 'border_style' ] );
⋮----
protected function enqueue_assets( array $attributes, $content, $block ) {
parent::enqueue_assets( $attributes, $content, $block );
⋮----
$styles = $this->get_inline_styles( $attributes );
⋮----
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/DownloadsWrapper.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
class DownloadsWrapper extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-downloads-wrapper';
⋮----
protected function store_has_downloadable_products() {
⋮----
$has_downloadable_products = (bool) $wpdb->get_var(
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
⋮----
$this->asset_data_registry->add( 'storeHasDownloadableProducts', $this->store_has_downloadable_products() );
⋮----
protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) {
$show_downloads = $order && $order->has_downloadable_item() && $order->is_download_permitted();
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/ShippingAddress.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
⋮----
class ShippingAddress extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-shipping-address';
⋮----
protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) {
if ( ! $permission || ! $order->needs_shipping_address() || ! $order->has_shipping_address() ) {
return $this->render_content_fallback();
⋮----
$address = '<address>' . wp_kses_post( $order->get_formatted_shipping_address() ) . '</address>';
$phone   = $order->get_shipping_phone() ? '<p class="woocommerce-customer-details--phone">' . esc_html( $order->get_shipping_phone() ) . '</p>' : '';
⋮----
$controller = Package::container()->get( CheckoutFields::class );
$custom     = $this->render_additional_fields(
$controller->filter_fields_for_order_confirmation(
$controller->get_order_additional_fields_with_values( $order, 'address', 'shipping', 'view' ),
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
$this->asset_data_registry->add( 'additionalAddressFields', Package::container()->get( CheckoutFields::class )->get_fields_for_location( 'address' ) );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/ShippingWrapper.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
class ShippingWrapper extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-shipping-wrapper';
⋮----
protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) {
if ( ! $order || ! $order->has_shipping_address() || ! $order->needs_shipping_address() || ! $permission ) {
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/Status.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class Status extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-status';
⋮----
protected function render( $attributes, $content, $block ) {
$order     = $this->get_order();
$classname = StyleAttributesUtils::get_classes_by_attributes( $attributes, array( 'extra_classes' ) );
⋮----
$block = parent::render( $attributes, $content, $block );
⋮----
$additional_content = $this->render_confirmation_notice( $order );
⋮----
/**
	 * This renders the content of the block within the wrapper.
	 *
	 * @param \WC_Order    $order Order object.
	 * @param string|false $permission If the current user can view the order details or not.
	 * @param array        $attributes Block attributes.
	 * @param string       $content Original block content.
	 * @return string
	 */
protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) {
⋮----
// phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
⋮----
$content = $this->get_hook_content( 'woocommerce_before_thankyou', [ $order->get_id() ] );
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/Summary.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
class Summary extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-summary';
⋮----
protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) {
⋮----
$content .= $this->render_summary_row( __( 'Order
$content .= $this->render_summary_row( __( 'Date:', 'woocommerce' ), wc_format_datetime( $order->get_date_created() ) );
$content .= $this->render_summary_row( __( 'Total:', 'woocommerce' ), $order->get_formatted_order_total() );
$content .= $this->render_summary_row( __( 'Email:', 'woocommerce' ), $order->get_billing_email() );
$content .= $this->render_summary_row( __( 'Payment:', 'woocommerce' ), $order->get_payment_method_title() );
⋮----
protected function render_summary_row( $name, $value ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/Totals.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Enums\OrderItemType;
⋮----
class Totals extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-totals';
⋮----
protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) {
⋮----
return $this->render_content_fallback();
⋮----
$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes, [ 'border_color', 'border_radius', 'border_width', 'border_style', 'background_color', 'text_color' ] );
⋮----
return $this->get_hook_content( 'woocommerce_order_details_before_order_table', [ $order ] ) . '
⋮----
' . $this->get_hook_content( 'woocommerce_order_details_before_order_table_items', [ $order ] ) . '
' . $this->render_order_details_table_items( $order ) . '
' . $this->get_hook_content( 'woocommerce_order_details_after_order_table_items', [ $order ] ) . '
⋮----
' . $this->render_order_details_table_totals( $order ) . '
⋮----
' . $this->render_order_details_customer_note( $order ) . '
' . $this->get_hook_content( 'woocommerce_order_details_after_order_table', [ $order ] ) . '
' . $this->get_hook_content( 'woocommerce_after_order_details', [ $order ] ) . '
⋮----
protected function get_inline_styles( array $attributes ) {
$link_classes_and_styles       = StyleAttributesUtils::get_link_color_class_and_style( $attributes );
$link_hover_classes_and_styles = StyleAttributesUtils::get_link_hover_color_class_and_style( $attributes );
... (52 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/TotalsWrapper.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation;
⋮----
class TotalsWrapper extends AbstractOrderConfirmationBlock {
⋮----
protected $block_name = 'order-confirmation-totals-wrapper';
⋮----
protected function render_content( $order, $permission = false, $attributes = [], $content = '' ) {
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/Controller.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
use WP_Query;
⋮----
class Controller extends AbstractBlock {
⋮----
protected $block_name = 'product-collection';
⋮----
protected $collection_handler_registry;
⋮----
protected $query_builder;
⋮----
protected $renderer;
⋮----
protected function initialize() {
parent::initialize();
⋮----
$this->register_core_collections_and_set_handler_store();
⋮----
public function add_product_title_click_event_directives( $block_content, $block, $instance ) {
⋮----
$p = new \WP_HTML_Tag_Processor( $block_content );
$p->next_tag( array( 'class_name' => 'wp-block-post-title' ) );
$is_anchor = $p->next_tag( array( 'tag_name' => 'a' ) );
⋮----
$p->set_attribute( 'data-wp-on--click', 'woocommerce/product-collection::actions.viewProduct' );
⋮----
$block_content = $p->get_updated_html();
... (64 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/HandlerRegistry.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection;
⋮----
use Automattic\WooCommerce\Enums\OrderItemType;
use InvalidArgumentException;
⋮----
class HandlerRegistry {
⋮----
protected $collection_handler_store = [];
⋮----
public function register_collection_handlers( $collection_name, $build_query, $frontend_args = null, $editor_args = null, $preview_query = null ) {
⋮----
public function register_core_collections() {
$this->register_collection_handlers(
⋮----
$product_reference = $request->get_param( 'productReference' );
⋮----
$related_by                   = $request->get_param( 'relatedBy' );
⋮----
$product->get_upsell_ids()
⋮----
$product_references = $this->get_product_ids_from_order( $location['sourceData']['orderId'] ?? 0 );
⋮----
$product->get_cross_sell_ids()
⋮----
return $this->get_recent_product_ids_query();
⋮----
$collection_args['cartProductIds'] = $this->get_cart_product_ids( null );
⋮----
$collection_args['cartProductIds'] = $this->get_cart_product_ids( $request );
⋮----
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/NoResults.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductCollectionUtils;
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
⋮----
class NoResults extends AbstractBlock {
⋮----
protected $block_name = 'product-collection-no-results';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$query = ProductCollectionUtils::prepare_and_execute_query( $block );
⋮----
// If the query has products, don't render the block.
⋮----
// Update the anchor tag URLs.
$updated_html_content = $this->modify_anchor_tag_urls( trim( $content ) );
⋮----
/**
	 * Get the frontend script handle for this block type.
	 *
	 * @param string $key Data to get, or default to everything.
	 */
protected function get_block_type_script( $key = null ) {
⋮----
/**
	 * Get the frontend style handle for this block type.
	 *
	 * @return null
	 */
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/QueryBuilder.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AttributeFilter;
use Automattic\WooCommerce\Blocks\BlockTypes\PriceFilter;
use Automattic\WooCommerce\Blocks\BlockTypes\RatingFilter;
use Automattic\WooCommerce\Blocks\BlockTypes\StockFilter;
use WP_Query;
use WC_Tax;
use Automattic\WooCommerce\Enums\CatalogSortOrder;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
⋮----
class QueryBuilder {
⋮----
protected $valid_query_vars;
⋮----
protected $custom_order_opts = array( 'popularity', 'rating', 'post__in', 'price', 'sales', 'menu_order', 'random' );
⋮----
protected $attributes_filter_query_args = array();
⋮----
protected $collection_handler_store = array();
⋮----
public function __construct() {
$this->valid_query_vars = $this->get_valid_query_vars();
⋮----
public function set_collection_handler_store( $collection_handler_store ) {
⋮----
public function set_collection_handler( $collection_name, $handlers ) {
⋮----
... (164 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/Renderer.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductCollectionUtils;
use WP_HTML_Tag_Processor;
⋮----
class Renderer {
⋮----
private $render_state = array(
⋮----
protected $parsed_block;
⋮----
public function __construct() {
if ( ! $this->should_handle_frontend_rendering() ) {
⋮----
private function should_handle_frontend_rendering() {
return ! is_admin() && ! \WC()->is_rest_api_request();
⋮----
public function set_parsed_block( $block ) {
⋮----
public function handle_rendering( $block_content, $block ) {
if ( $this->should_prevent_render() ) {
return ''; // Prevent rendering.
⋮----
// Reset the render state for the next render.
$this->reset_render_state();
⋮----
return $this->enhance_product_collection_with_interactivity( $block_content, $block );
⋮----
/**
	 * Check if the block should be prevented from rendering.
... (68 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/Utils.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection;
⋮----
use WP_Query;
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
⋮----
class Utils {
⋮----
public static function prepare_and_execute_query( $block ) {
⋮----
public static function get_random_order_seed( $query_id, $query_context = array() ) {
⋮----
/**
	 * Helper function that constructs a WP_Query args array from
	 * a Product Collection or global query.
	 *
	 * @param WP_Block $block Block instance.
	 * @param int      $page  Current query's page.
	 *
	 * @return array Returns the constructed WP_Query arguments.
	 */
public static function get_query_vars( $block, $page ) {
⋮----
public static function remove_query_array( $queries, $key, $value ) {
⋮----
$queries[ $query_key ] = self::remove_query_array( $query, $key, $value );
⋮----
return self::remove_empty_array_recursive( $queries );
⋮----
public static function parse_frontend_location_context() {
⋮----
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Reviews/ProductReviewAuthorName.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Reviews;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
⋮----
class ProductReviewAuthorName extends AbstractBlock {
⋮----
protected $block_name = 'product-review-author-name';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
protected function get_block_type_script( $key = null ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Reviews/ProductReviewContent.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Reviews;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
⋮----
class ProductReviewContent extends AbstractBlock {
⋮----
protected $block_name = 'product-review-content';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
/**
		 * This filter is documented in wp-includes/comment-template.php
		 *
		 * @since 1.2.0
		 */
⋮----
protected function get_block_type_script( $key = null ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Reviews/ProductReviewDate.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Reviews;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
⋮----
class ProductReviewDate extends AbstractBlock {
⋮----
protected $block_name = 'product-review-date';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
protected function get_block_type_script( $key = null ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Reviews/ProductReviewForm.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Reviews;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
⋮----
class ProductReviewForm extends AbstractBlock {
⋮----
protected $block_name = 'product-review-form';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$product_has_reviews = $product->get_review_count() > 0;
⋮----
if ( ! wc_customer_bought_product( '', get_current_user_id(), $product->get_id() ) ) {
⋮----
'title_reply'         => $product->get_review_count() > 0 ? esc_html__( 'Add a review', 'woocommerce' ) : sprintf( esc_html__( 'Be the first to review &ldquo;%s&rdquo;', 'woocommerce' ), esc_html( get_the_title( $block->context['postId'] ) ) ),
⋮----
'<p role="radiogroup" aria-labelledby="comment-form-rating-label" class="stars-wrapper" data-wp-init="callbacks.showRatingStars" hidden data-wp-bind--aria-invalid="state.hasRatingError"' . ( wc_review_ratings_required() ? ' aria-required="true"' : '' ) . ' aria-describedby="rating-error">' . $this->render_stars() .
⋮----
$p = new \WP_HTML_Tag_Processor( $form );
⋮----
if ( $p->next_tag( 'form' ) ) {
$p->set_attribute( 'data-wp-on--submit', 'actions.handleSubmit' );
⋮----
return $p->get_updated_html();
⋮----
private function render_stars() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Reviews/ProductReviewRating.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Reviews;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
⋮----
class ProductReviewRating extends AbstractBlock {
⋮----
protected $block_name = 'product-review-rating';
⋮----
protected function get_block_type_style() {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
// translators: %s: Rating.
⋮----
protected function get_block_type_script( $key = null ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Reviews/ProductReviews.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Reviews;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Blocks\BlockTypes\EnableBlockJsonAssetsTrait;
⋮----
class ProductReviews extends AbstractBlock {
⋮----
protected $block_name = 'product-reviews';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
return $this->render_legacy_block( $attributes, $content, $block );
⋮----
$p = new \WP_HTML_Tag_Processor( $content );
$p->next_tag();
$p->set_attribute( 'data-wp-interactive', $this->get_full_block_name() );
$p->set_attribute( 'data-wp-router-region', $this->get_full_block_name() );
⋮----
return $p->get_updated_html();
⋮----
protected function render_legacy_block( $attributes, $content, $block ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Reviews/ProductReviewsPagination.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Reviews;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
⋮----
class ProductReviewsPagination extends AbstractBlock {
⋮----
protected $block_name = 'product-reviews-pagination';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$p = new \WP_HTML_Tag_Processor( $content );
while ( $p->next_tag( 'a' ) ) {
$p->set_attribute( 'data-wp-on--click', 'actions.navigate' );
⋮----
$p->get_updated_html()
⋮----
protected function get_block_type_script( $key = null ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Reviews/ProductReviewsPaginationNext.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Reviews;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
⋮----
class ProductReviewsPaginationNext extends AbstractBlock {
⋮----
protected $block_name = 'product-reviews-pagination-next';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$max_page         = ( new \WP_Comment_Query( $comment_vars ) )->max_num_pages;
⋮----
$pagination_arrow = $this->get_pagination_arrow( $block );
⋮----
/**
	 * Get the pagination arrow.
	 *
	 * @param \WP_Block $block Block instance.
	 * @return string|null
	 */
protected function get_pagination_arrow( $block ) {
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Reviews/ProductReviewsPaginationNumbers.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Reviews;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
⋮----
class ProductReviewsPaginationNumbers extends AbstractBlock {
⋮----
protected $block_name = 'product-reviews-pagination-numbers';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$total   = ( new \WP_Comment_Query( $comment_vars ) )->max_num_pages;
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Reviews/ProductReviewsPaginationPrevious.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Reviews;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
⋮----
class ProductReviewsPaginationPrevious extends AbstractBlock {
⋮----
protected $block_name = 'product-reviews-pagination-previous';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$pagination_arrow = $this->get_pagination_arrow( $block );
⋮----
/**
	 * Get the pagination arrow.
	 *
	 * @param \WP_Block $block Block instance.
	 * @return string|null
	 */
protected function get_pagination_arrow( $block ) {
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Reviews/ProductReviewsTitle.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Reviews;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
⋮----
class ProductReviewsTitle extends AbstractBlock {
⋮----
protected $block_name = 'product-reviews-title';
⋮----
private function get_reviews_title( $attributes, $product ) {
⋮----
$reviews_count      = $product->get_review_count();
⋮----
? sprintf( __( 'One review for %s', 'woocommerce' ), $product->get_title() )
⋮----
$product->get_title()
⋮----
? sprintf( __( 'Review for %s', 'woocommerce' ), $product->get_title() )
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$reviews_title = $this->get_reviews_title( $attributes, $product );
⋮----
protected function get_block_type_script( $key = null ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Reviews/ProductReviewTemplate.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes\Reviews;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use WP_Comment_Query;
use WP_Block;
use WP_Comment;
⋮----
class ProductReviewTemplate extends AbstractBlock {
⋮----
protected $block_name = 'product-review-template';
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function block_product_review_template_render_comments( array $comments, WP_Block $block ): string {
⋮----
$block_content = ( new WP_Block( $block->parsed_block ) )->render( array( 'dynamic' => false ) );
⋮----
$children = $comment->get_children();
⋮----
// If the comment has children, recurse to create the HTML for the nested comments.
⋮----
$inner_content  = $this->block_product_review_template_render_comments(
⋮----
/**
	 * Render the block.
	 *
	 * @param array    $attributes Block attributes.
	 * @param string   $content Block content.
	 * @param WP_Block $block Block instance.
	 * @return string Rendered block content.
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AbstractBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Blocks\Assets\Api as AssetApi;
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
use Automattic\WooCommerce\Blocks\Integrations\IntegrationRegistry;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Internal\Features\BlockEditorUnifiedAssets;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use WP_Block;
⋮----
abstract class AbstractBlock {
⋮----
protected $namespace = 'woocommerce';
⋮----
protected $block_name = '';
⋮----
/**
	 * Tracks if assets have been enqueued.
	 *
	 * @var boolean
	 */
protected $enqueued_assets = false;
⋮----
/**
	 * Instance of the asset API.
	 *
	 * @var AssetApi
	 */
protected $asset_api;
... (198 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AbstractDynamicBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
abstract class AbstractDynamicBlock extends AbstractBlock {
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function get_block_type_attributes() {
⋮----
protected function get_schema_align() {
⋮----
protected function get_schema_list_ids() {
⋮----
protected function get_schema_boolean( $default = true ) {
⋮----
protected function get_schema_number( $default ) {
⋮----
protected function get_schema_string( $default = '' ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AbstractInnerBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
abstract class AbstractInnerBlock extends AbstractBlock {
⋮----
protected $is_lazy_loaded = true;
⋮----
protected function register_block_type() {
⋮----
'render_callback' => $this->get_block_type_render_callback(),
'editor_style'    => $this->get_block_type_editor_style(),
'style'           => $this->get_block_type_style(),
⋮----
$metadata_path = $this->asset_api->get_block_metadata_path( $this->block_name, 'inner-blocks/' );
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
return parent::get_block_type_script( $key );
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AbstractProductGrid.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\BlocksWpQuery;
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\StoreApi;
use Automattic\WooCommerce\Enums\ProductStockStatus;
⋮----
abstract class AbstractProductGrid extends AbstractDynamicBlock {
⋮----
protected $attributes = array();
⋮----
protected $content = '';
⋮----
/**
	 * Query args.
	 *
	 * @var array
	 */
protected $query_args = array();
⋮----
/**
	 * Meta query args.
	 *
	 * @var array
	 */
protected $meta_query = array();
⋮----
/**
	 * Get a set of attributes shared across most of the grid blocks.
	 *
... (201 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ActiveFilters.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ActiveFilters extends AbstractBlock {
⋮----
protected $block_name = 'active-filters';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AddToCartForm.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Blocks\Utils\Utils as BlocksUtils;
use Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions\Utils;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class AddToCartForm extends AbstractBlock {
⋮----
protected $block_name = 'add-to-cart-form';
⋮----
private function parse_attributes( $attributes ) {
⋮----
protected function enqueue_assets( $attributes, $content, $block ) {
$parsed_attributes = $this->parse_attributes( $attributes );
⋮----
parent::enqueue_assets( $attributes, $content, $block );
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
$this->asset_data_registry->add( 'isBlockTheme', wp_is_block_theme() );
⋮----
private function add_steppers( $product_html, $product_name ) {
⋮----
// Add the plus button AFTER the matched <input> element.
⋮----
/* translators: %s refers to the item name in the cart. */
⋮----
/**
	 * Add classes to the Add to Cart form input needed for the stepper style.
... (70 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AddToWishlistButton.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\BlocksSharedState;
use Automattic\WooCommerce\Internal\ShopperLists\ShopperListRenderer;
⋮----
final class AddToWishlistButton extends AbstractBlock {
⋮----
protected $block_name = 'add-to-wishlist-button';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
wp_enqueue_script_module( $this->get_full_block_name() );
⋮----
BlocksSharedState::load_store_config( $consent );
⋮----
$items = $this->prefetch_items();
⋮----
'addLabel'           => $this->get_add_label(),
'savedLabel'         => $this->get_saved_label(),
'selectOptionsLabel' => $this->get_select_options_label(),
⋮----
$is_variable            = $product->is_type( 'variable' );
$initial_is_in_wishlist = $this->is_initial_in_wishlist( $items, $product );
⋮----
? $this->get_select_options_label()
: ( $initial_is_in_wishlist ? $this->get_saved_label() : $this->get_add_label() );
⋮----
'productId'      => $product->get_id(),
⋮----
<?php echo ShopperListRenderer::get_star_empty_svg(); ?>
... (31 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AllProducts.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class AllProducts extends AbstractBlock {
⋮----
protected $block_name = 'all-products';
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
⋮----
$this->asset_data_registry->add( 'hasFilterableProducts', true );
$this->asset_data_registry->add( 'minColumns', wc_get_theme_support( 'product_blocks::min_columns', 1 ) );
$this->asset_data_registry->add( 'maxColumns', wc_get_theme_support( 'product_blocks::max_columns', 6 ) );
$this->asset_data_registry->add( 'defaultColumns', wc_get_theme_support( 'product_blocks::default_columns', 3 ) );
$this->asset_data_registry->add( 'minRows', wc_get_theme_support( 'product_blocks::min_rows', 1 ) );
$this->asset_data_registry->add( 'maxRows', wc_get_theme_support( 'product_blocks::max_rows', 6 ) );
$this->asset_data_registry->add( 'defaultRows', wc_get_theme_support( 'product_blocks::default_rows', 3 ) );
$this->asset_data_registry->add( 'thumbnailAspectRatio', $this->get_store_thumbnail_aspect_ratio() );
⋮----
if ( ! is_admin() && ! WC()->is_rest_api_request() ) {
$this->asset_data_registry->hydrate_api_request( '/wc/store/v1/cart' );
⋮----
protected function register_block_type_assets() {
parent::register_block_type_assets();
$this->register_chunk_translations( [ $this->block_name ] );
⋮----
private function get_store_thumbnail_aspect_ratio() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AllReviews.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class AllReviews extends AbstractBlock {
⋮----
protected $block_name = 'all-reviews';
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
'path'         => $this->asset_api->get_block_asset_build_path( 'reviews-frontend' ),
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
$this->asset_data_registry->add( 'reviewRatingsEnabled', wc_review_ratings_enabled() );
$this->asset_data_registry->add( 'showAvatars', '1' === get_option( 'show_avatars' ) );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AtomicBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class AtomicBlock extends AbstractBlock {
⋮----
protected function get_block_type_editor_script( $key = null ) {
⋮----
protected function get_block_type_editor_style() {
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/AttributeFilter.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class AttributeFilter extends AbstractBlock {
⋮----
protected $block_name             = 'attribute-filter';
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
$this->asset_data_registry->add( 'attributes', array_values( wc_get_attribute_taxonomies() ) );
⋮----
$this->asset_data_registry->add( 'queryState', $query_state );
⋮----
protected function get_block_type_style() {
return array_merge( parent::get_block_type_style(), [ 'wc-blocks-packages-style' ] );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Breadcrumbs.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use WP_Block;
⋮----
class Breadcrumbs extends AbstractBlock {
⋮----
protected $block_name = 'breadcrumbs';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes, array(), array( 'font_size' ) );
⋮----
$font_size_classes_and_styles  = $this->get_font_size_classes_and_styles( $attributes, $block );
⋮----
/**
	 * Get the frontend script handle for this block type.
	 *
	 * @param string $key Data to get, or default to everything.
	 */
protected function get_block_type_script( $key = null ) {
⋮----
/**
	 * Gets font size classes and styles for the breadcrumbs block.
	 *
	 * @param array    $attributes The block attributes.
	 * @param WP_Block $block      The block instance.
	 * @return array The font size classes and styles.
	 */
private function get_font_size_classes_and_styles( array $attributes, $block ) {
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Cart.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
⋮----
class Cart extends AbstractBlock {
⋮----
protected $block_name = 'cart';
⋮----
protected $chunks_folder = 'cart-blocks';
⋮----
protected function initialize() {
parent::initialize();
⋮----
public function disable_wp_emoji() {
if ( has_block( $this->get_full_block_name() ) ) {
⋮----
public function dequeue_woocommerce_core_scripts() {
⋮----
public function register_patterns() {
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
'path'         => $this->asset_api->get_block_asset_build_path( $this->block_name . '-frontend' ),
⋮----
protected function get_block_type_style() {
return array_merge( parent::get_block_type_style(), [ 'wc-blocks-packages-style' ] );
⋮----
protected function enqueue_assets( array $attributes, $content, $block ) {
⋮----
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartAcceptedPaymentMethodsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartAcceptedPaymentMethodsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-accepted-payment-methods-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartCrossSellsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartCrossSellsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-cross-sells-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartCrossSellsProductsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartCrossSellsProductsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-cross-sells-products-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartExpressPaymentBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartExpressPaymentBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-express-payment-block';
⋮----
protected $default_styles = null;
⋮----
protected $current_styles = null;
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartItemsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartItemsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-items-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartLineItemsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartLineItemsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-line-items-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartLink.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Blocks\Utils\MiniCartUtils;
⋮----
class CartLink extends AbstractBlock {
⋮----
protected $block_name = 'cart-link';
⋮----
protected function render( $attributes, $content, $block ) {
$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes );
$icon               = MiniCartUtils::get_svg_icon( $attributes['cartIcon'] ?? '' );
⋮----
protected function get_block_type_script( $key = null ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartOrderSummaryBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartOrderSummaryBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-order-summary-block';
⋮----
private function get_inner_block_content( $block_name, $content ) {
if ( preg_match( $this->inner_block_regex( $block_name ), $content, $matches ) ) {
⋮----
private function inner_block_regex( $block_name ) {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$inner_block_content = $this->get_inner_block_content( $block_name, $content );
⋮----
$content                       = preg_replace( $this->inner_block_regex( $block_name ), $order_summary_totals_content, $content );
⋮----
$content = preg_replace( $this->inner_block_regex( $block_name ), '', $content );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartOrderSummaryCouponFormBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartOrderSummaryCouponFormBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-order-summary-coupon-form-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartOrderSummaryDiscountBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartOrderSummaryDiscountBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-order-summary-discount-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartOrderSummaryFeeBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartOrderSummaryFeeBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-order-summary-fee-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartOrderSummaryHeadingBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartOrderSummaryHeadingBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-order-summary-heading-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartOrderSummaryShippingBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartOrderSummaryShippingBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-order-summary-shipping-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartOrderSummarySubtotalBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartOrderSummarySubtotalBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-order-summary-subtotal-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartOrderSummaryTaxesBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartOrderSummaryTaxesBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-order-summary-taxes-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartOrderSummaryTotalsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartOrderSummaryTotalsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-order-summary-totals-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CartTotalsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CartTotalsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'cart-totals-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CatalogSorting.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class CatalogSorting extends AbstractBlock {
⋮----
protected $block_name = 'catalog-sorting';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$processor = new \WP_HTML_Tag_Processor( $catalog_sorting );
⋮----
if ( $processor->next_tag( array( 'tag_name' => 'form' ) ) ) {
$processor->set_attribute( 'data-wp-interactive', 'woocommerce/catalog-sorting' );
$processor->set_attribute( 'data-wp-on--submit', 'actions.preventSubmit' );
⋮----
if ( $processor->next_tag( array( 'tag_name' => 'select' ) ) ) {
$processor->set_attribute( 'data-wp-on--change', 'actions.handleSortChange' );
⋮----
$catalog_sorting = $processor->get_updated_html();
⋮----
$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes, array(), array( 'extra_classes' ) );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CategoryDescription.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CategoryDescription extends AbstractBlock {
⋮----
protected $block_name = 'category-description';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CategoryTitle.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CategoryTitle extends AbstractBlock {
⋮----
protected $block_name = 'category-title';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
/**
	 * Register the context used by this block.
	 *
	 * @return array
	 */
protected function get_block_type_uses_context() {
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Checkout.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\Block_Scanner;
use Automattic\WooCommerce\StoreApi\Utilities\LocalPickupUtils;
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
use Automattic\WooCommerce\StoreApi\Utilities\PaymentUtils;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldsSchema\Validation;
use Automattic\WooCommerce\Internal\AddressProvider\AddressProviderController;
⋮----
class Checkout extends AbstractBlock {
⋮----
protected $block_name = 'checkout';
⋮----
protected $chunks_folder = 'checkout-blocks';
⋮----
protected function initialize() {
parent::initialize();
⋮----
public function disable_wp_emoji() {
if ( has_block( $this->get_full_block_name() ) ) {
⋮----
public function dequeue_woocommerce_core_scripts() {
⋮----
public function register_settings() {
⋮----
'default'      => CartCheckoutUtils::get_phone_field_visibility(),
⋮----
... (140 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutActionsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutActionsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-actions-block';
⋮----
protected function initialize() {
parent::initialize();
⋮----
public function register_style_variations() {
⋮----
$this->get_full_block_name(),
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutAdditionalInformationBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutAdditionalInformationBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-additional-information-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutBillingAddressBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutBillingAddressBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-billing-address-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutContactInformationBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutContactInformationBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-contact-information-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutExpressPaymentBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Exception;
⋮----
class CheckoutExpressPaymentBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-express-payment-block';
⋮----
protected $default_styles = null;
⋮----
protected $current_styles = null;
⋮----
protected function initialize() {
parent::initialize();
⋮----
public function sync_express_payment_attrs( $post_id, $post ) {
⋮----
$attrs = CartCheckoutUtils::find_express_checkout_attributes( $post->post_content, $cart_or_checkout );
⋮----
$this->update_other_page_with_express_payment_attrs( $other_page, $updated_attrs );
⋮----
wc_get_logger()->log( 'error', 'Error updating express payment attributes: ' . $e->getMessage() );
⋮----
private function update_other_page_with_express_payment_attrs( $cart_or_checkout, $updated_attrs ) {
⋮----
CartCheckoutUtils::update_blocks_with_new_attrs( $blocks, $cart_or_checkout, $updated_attrs );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutFieldsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutFieldsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-fields-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutOrderNoteBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutOrderNoteBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-order-note-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutOrderSummaryBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutOrderSummaryBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-order-summary-block';
⋮----
private function get_inner_block_content( $block_name, $content ) {
if ( preg_match( $this->inner_block_regex( $block_name ), $content, $matches ) ) {
⋮----
private function inner_block_regex( $block_name ) {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$inner_block_content = $this->get_inner_block_content( $block_name, $content );
⋮----
$content                       = preg_replace( $this->inner_block_regex( $block_name ), $order_summary_totals_content, $content );
⋮----
$content = preg_replace( $this->inner_block_regex( $block_name ), '', $content );
⋮----
// Remove empty lines.
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutOrderSummaryCartItemsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutOrderSummaryCartItemsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-order-summary-cart-items-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutOrderSummaryCouponFormBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutOrderSummaryCouponFormBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-order-summary-coupon-form-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutOrderSummaryDiscountBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutOrderSummaryDiscountBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-order-summary-discount-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutOrderSummaryFeeBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutOrderSummaryFeeBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-order-summary-fee-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutOrderSummaryShippingBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutOrderSummaryShippingBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-order-summary-shipping-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutOrderSummarySubtotalBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutOrderSummarySubtotalBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-order-summary-subtotal-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutOrderSummaryTaxesBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutOrderSummaryTaxesBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-order-summary-taxes-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutOrderSummaryTotalsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutOrderSummaryTotalsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-order-summary-totals-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutPaymentBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutPaymentBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-payment-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutPickupOptionsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutPickupOptionsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-pickup-options-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutShippingAddressBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutShippingAddressBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-shipping-address-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutShippingMethodBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutShippingMethodBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-shipping-method-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutShippingMethodsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutShippingMethodsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-shipping-methods-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutTermsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutTermsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-terms-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CheckoutTotalsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class CheckoutTotalsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'checkout-totals-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ClassicShortcode.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use WC_Shortcode_Cart;
use WC_Shortcode_Checkout;
use WC_Frontend_Scripts;
⋮----
class ClassicShortcode extends AbstractDynamicBlock {
⋮----
protected $block_name = 'classic-shortcode';
⋮----
protected $api_version = '3';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$frontend_scripts::load_scripts();
⋮----
return $this->render_cart( $attributes );
⋮----
return $this->render_checkout( $attributes );
⋮----
protected function get_container_classes( $attributes = array() ) {
⋮----
protected function render_cart( $attributes ) {
⋮----
echo '<div class="' . esc_attr( $this->get_container_classes( $attributes ) ) . '">';
WC_Shortcode_Cart::output( array() );
⋮----
/**
	 * Render method for rendering the checkout shortcode.
	 *
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ClassicTemplate.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Templates\ProductAttributeTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductCatalogTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductCategoryTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductTagTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductSearchResultsTemplate;
use Automattic\WooCommerce\Blocks\Templates\OrderConfirmationTemplate;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use WC_Shortcode_Checkout;
use WC_Frontend_Scripts;
⋮----
class ClassicTemplate extends AbstractDynamicBlock {
⋮----
protected $block_name = 'legacy-template';
⋮----
protected $api_version = '3';
⋮----
protected function initialize() {
parent::initialize();
⋮----
protected function enqueue_data( array $attributes = array() ) {
parent::enqueue_data( $attributes );
⋮----
public function enqueue_block_assets() {
⋮----
$styles           = $frontend_scripts::get_styles();
⋮----
protected function enqueue_assets( $attributes, $content, $block ) {
parent::enqueue_assets( $attributes, $content, $block );
... (37 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ComingSoon.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\Jetpack\Constants;
⋮----
class ComingSoon extends AbstractBlock {
⋮----
protected $block_name = 'coming-soon';
⋮----
protected function register_block_type_assets() {
parent::register_block_type_assets();
$this->register_chunk_translations( [ $this->block_name ] );
⋮----
public function initialize() {
parent::initialize();
⋮----
protected function enqueue_assets( array $attributes, $content, $block ) {
parent::enqueue_assets( $attributes, $content, $block );
⋮----
WC()->plugin_url() . '/assets/css/coming-soon-entire-site-deprecated' . ( is_rtl() ? '-rtl' : '' ) . '.css',
⋮----
Constants::get_constant( 'WC_VERSION' )
⋮----
public function enqueue_block_assets() {
⋮----
protected function get_block_type_script( $key = null ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CouponCode.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\EmailEditor\Email_Editor_Container;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\ContentRenderer\Rendering_Context;
use Automattic\WooCommerce\EmailEditor\Engine\Theme_Controller;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper;
use Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper;
use WP_Block;
⋮----
class CouponCode extends AbstractBlock {
⋮----
protected $block_name = 'coupon-code';
⋮----
protected function get_block_type_style() {
⋮----
protected function enqueue_data( array $attributes = array() ): void {
parent::enqueue_data( $attributes );
⋮----
if ( ! $this->asset_data_registry->exists( 'couponTypes' ) && function_exists( 'wc_get_coupon_types' ) ) {
$this->asset_data_registry->add( 'couponTypes', wc_get_coupon_types() );
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$attributes   = $this->get_block_attributes( $parsed_block, $attributes );
⋮----
$coupon_code = $this->get_coupon_code( $attributes );
⋮----
$rendering_context = $this->get_rendering_context( $block );
$coupon_html       = $this->build_coupon_html( $coupon_code, $attributes, $rendering_context );
⋮----
... (63 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/CustomerAccount.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Blocks\Utils\BlockHooksTrait;
⋮----
class CustomerAccount extends AbstractBlock {
⋮----
protected $block_name = 'customer-account';
⋮----
protected $hooked_block_placements = array(
⋮----
protected function initialize() {
parent::initialize();
⋮----
public function modify_hooked_block_attributes( $parsed_hooked_block, $hooked_block_type, $relative_position, $parsed_anchor_block, $context ) {
⋮----
protected function should_unhook_block( $hooked_blocks, $position, $anchor_block, $context ) {
⋮----
$active_theme   = wp_get_theme()->get( 'Name' );
⋮----
protected function render( $attributes, $content, $block ) {
$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes );
⋮----
$aria_label   = self::ICON_ONLY === $attributes['displayStyle'] ? ' aria-label="' . esc_attr( $this->render_label() ) . '"' : '';
$label_markup = self::ICON_ONLY === $attributes['displayStyle'] ? '' : '<span class="label">' . wp_kses( $this->render_label(), array() ) . '</span>';
⋮----
return $this->render_link( $attributes, $classes_and_styles, $account_link, $aria_label, $label_markup );
⋮----
return $this->render_dropdown( $attributes, $classes_and_styles, $aria_label, $label_markup );
⋮----
... (47 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Dropdown.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
final class Dropdown extends AbstractBlock {
⋮----
protected $block_name = 'dropdown';
⋮----
private function get_option_text( array $item ): string {
⋮----
/**
	 * Render the block.
	 *
	 * @param array     $attributes Block attributes.
	 * @param string    $content    Block content.
	 * @param \WP_Block $block      Block instance.
	 * @return string Rendered block type output.
	 */
protected function render( $attributes, $content, $block ) {
⋮----
$option_label = $this->get_option_text( $item );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/EmailContent.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AbstractBlock;
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
use Automattic\WooCommerce\Internal\Admin\EmailPreview\EmailPreview;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsManager;
⋮----
class EmailContent extends AbstractBlock {
⋮----
protected $block_name = 'email-content';
⋮----
protected function get_block_type_style() {
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function render_preview( $attributes ) {
⋮----
$email_preview = wc_get_container()->get( EmailPreview::class );
⋮----
$email_type_class_name = WCTransactionalEmailPostsManager::get_instance()->get_email_type_class_name_from_post_id( $attributes['postId'] );
⋮----
return $email_preview->generate_placeholder_content( $type_param );
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
return $this->render_preview( $attributes );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/EmptyCartBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class EmptyCartBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'empty-cart-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/EmptyMiniCartContentsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class EmptyMiniCartContentsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'empty-mini-cart-contents-block';
⋮----
protected function render( $attributes, $content, $block ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/EnableBlockJsonAssetsTrait.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
trait EnableBlockJsonAssetsTrait {
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function get_block_type_style() {
⋮----
protected function get_block_type_editor_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/FeaturedCategory.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class FeaturedCategory extends FeaturedItem {
⋮----
protected $block_name = 'featured-category';
⋮----
protected function get_block_type_attributes() {
⋮----
parent::get_block_type_attributes(),
⋮----
'textColor'  => $this->get_schema_string(),
'fontSize'   => $this->get_schema_string(),
'lineHeight' => $this->get_schema_string(),
⋮----
protected function get_item( $attributes ) {
⋮----
protected function get_item_title( $category ) {
⋮----
protected function get_item_image_id( $category ) {
⋮----
protected function get_item_image( $category, $size = 'full' ) {
$image_id = $this->get_item_image_id( $category );
⋮----
/**
	 * Renders the featured category attributes.
	 *
	 * @param \WP_Term $category Term object.
	 * @param array    $attributes Block attributes. Default empty array.
	 * @return string
	 */
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/FeaturedItem.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
abstract class FeaturedItem extends AbstractDynamicBlock {
⋮----
protected $block_name;
⋮----
protected $defaults = array(
⋮----
protected $global_style_wrapper = array(
⋮----
protected function initialize() {
parent::initialize();
⋮----
private $current_item = null;
⋮----
protected $featured_item_id = 0;
⋮----
protected $featured_item_inner_blocks_names = [];
⋮----
protected function extract_featured_item_inner_block_names( $block, &$result = [] ) {
⋮----
$this->extract_featured_item_inner_block_names( $inner_block, $result );
⋮----
protected function replace_post_for_featured_item_inner_block( $block, &$context ) {
⋮----
public function update_context( $context, $parsed_block, $parent_block ) {
⋮----
$item = $this->get_item( $parsed_block['attrs'] );
... (82 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/FeaturedProduct.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\ProductDescriptionUtils;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class FeaturedProduct extends FeaturedItem {
⋮----
protected $block_name = 'featured-product';
⋮----
protected function get_item( $attributes ) {
⋮----
if ( ! $product || ! $product->is_viewable() ) {
⋮----
protected function get_item_title( $product ) {
return $product->get_title();
⋮----
protected function get_item_image_id( $product ) {
$image_id = $product->get_image_id();
⋮----
if ( $product->get_parent_id() ) {
$parent_product = wc_get_product( $product->get_parent_id() );
⋮----
return (int) $parent_product->get_image_id();
⋮----
protected function get_item_image( $product, $size = 'full' ) {
$image_id = $this->get_item_image_id( $product );
⋮----
/**
	 * Renders the featured product attributes.
	 *
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/FilledCartBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class FilledCartBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'filled-cart-block';
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/FilledMiniCartContentsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\BlocksSharedState;
⋮----
class FilledMiniCartContentsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'filled-mini-cart-contents-block';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$notices = BlocksSharedState::get_cart_error_notices( $consent );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/FilterWrapper.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class FilterWrapper extends AbstractBlock {
⋮----
protected $block_name = 'filter-wrapper';
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/HandpickedProducts.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Enums\ProductStockStatus;
⋮----
class HandpickedProducts extends AbstractProductGrid {
⋮----
protected $block_name = 'handpicked-products';
⋮----
protected function set_block_query_args( &$query_args ) {
⋮----
protected function set_visibility_query_args( &$query_args ) {
⋮----
protected function get_block_type_attributes() {
⋮----
'align'             => $this->get_schema_align(),
'alignButtons'      => $this->get_schema_boolean( false ),
'className'         => $this->get_schema_string(),
'columns'           => $this->get_schema_number( wc_get_theme_support( 'product_blocks::default_columns', 3 ) ),
'orderby'           => $this->get_schema_orderby(),
'products'          => $this->get_schema_list_ids(),
'contentVisibility' => $this->get_schema_content_visibility(),
'isPreview'         => $this->get_schema_boolean( false ),
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/MiniCart.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
use Automattic\WooCommerce\Blocks\Assets\Api as AssetApi;
use Automattic\WooCommerce\Blocks\Integrations\IntegrationRegistry;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
use Automattic\WooCommerce\Blocks\Utils\Utils;
use Automattic\WooCommerce\Blocks\Utils\MiniCartUtils;
use Automattic\WooCommerce\Blocks\Utils\BlockHooksTrait;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
use Automattic\WooCommerce\Blocks\Utils\BlocksSharedState;
use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonHelper;
use Automattic\Block_Delimiter;
⋮----
class MiniCart extends AbstractBlock {
⋮----
protected $block_name = 'mini-cart';
⋮----
protected $tax_label = '';
⋮----
/**
	 *  Visibility of price including tax.
	 *
	 * @var string
	 */
protected $display_cart_prices_including_tax = false;
⋮----
... (195 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/MiniCartCartButtonBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class MiniCartCartButtonBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'mini-cart-cart-button-block';
⋮----
protected function render( $attributes, $content, $block ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/MiniCartCheckoutButtonBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class MiniCartCheckoutButtonBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'mini-cart-checkout-button-block';
⋮----
protected function render( $attributes, $content, $block ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/MiniCartContents.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class MiniCartContents extends AbstractBlock {
⋮----
protected $block_name = 'mini-cart-contents';
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function get_block_type_style() {
⋮----
protected function render( $attributes, $content, $block ) {
if ( is_admin() || WC()->is_rest_api_request() ) {
⋮----
protected function enqueue_assets( array $attributes, $content, $block ) {
parent::enqueue_assets( $attributes, $content, $block );
$text_color = StyleAttributesUtils::get_text_color_class_and_style( $attributes );
$bg_color   = StyleAttributesUtils::get_background_color_class_and_style( $attributes );
⋮----
public static function get_mini_cart_block_types() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/MiniCartFooterBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Enums\TaxDisplayMode;
⋮----
class MiniCartFooterBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'mini-cart-footer-block';
⋮----
protected function enqueue_data( array $attributes = array() ) {
parent::enqueue_data( $attributes );
$description = $this->get_totals_item_description();
⋮----
$this->asset_data_registry->add( 'miniCartFooterDescription', $description );
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$cart                             = $this->get_cart_instance();
⋮----
$other_costs_label                = $this->get_totals_item_description();
⋮----
$subtotal                         = $display_cart_price_including_tax ? $cart->get_subtotal_tax() : $cart->get_subtotal();
⋮----
$html                             = new \WP_HTML_Tag_Processor( wc_price( $subtotal ) );
⋮----
if ( $html->next_tag( 'bdi' ) ) {
while ( $html->next_token() ) {
if ( '#text' === $html->get_token_name() ) {
$formatted_subtotal .= $html->get_modifiable_text();
⋮----
$this->get_full_block_name(),
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/MiniCartItemsBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class MiniCartItemsBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'mini-cart-items-block';
⋮----
protected function render( $attributes, $content, $block ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/MiniCartProductsTableBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class MiniCartProductsTableBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'mini-cart-products-table-block';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$this->get_full_block_name(),
⋮----
'data-wp-interactive' => $this->get_full_block_name(),
⋮----
<?php echo $this->render_product_details_markup( 'item_data' ); ?>
<?php echo $this->render_product_details_markup( 'variation' ); ?>
⋮----
protected function render_product_details_markup( $property ) {
⋮----
<?php echo $this->render_product_details_item_markup( $is_item_data ); ?>
⋮----
private function render_product_details_item_markup( $is_item_data = false ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/MiniCartShoppingButtonBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class MiniCartShoppingButtonBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'mini-cart-shopping-button-block';
⋮----
protected function render( $attributes, $content, $block ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/MiniCartTitleBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class MiniCartTitleBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'mini-cart-title-block';
⋮----
protected function render( $attributes, $content, $block ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/MiniCartTitleItemsCounterBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class MiniCartTitleItemsCounterBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'mini-cart-title-items-counter-block';
⋮----
protected function render( $attributes, $content, $block ) {
$cart            = $this->get_cart_instance();
$cart_item_count = $cart ? $cart->get_cart_contents_count() : 0;
⋮----
$this->get_full_block_name(),
⋮----
protected function get_cart_instance() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/MiniCartTitleLabelBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class MiniCartTitleLabelBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'mini-cart-title-label-block';
⋮----
protected function render( $attributes, $content, $block ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/NextPreviousButtons.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\ProductGalleryUtils;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class NextPreviousButtons extends AbstractBlock {
⋮----
protected $block_name = 'product-gallery-large-image-next-previous';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes, array(), array( 'align' ) );
$vertical_alignment = StyleAttributesUtils::get_align_class_and_style( $attributes );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/PageContentWrapper.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class PageContentWrapper extends AbstractBlock {
⋮----
protected $block_name = 'page-content-wrapper';
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/PaymentMethodIcons.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use WP_Block;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class PaymentMethodIcons extends AbstractBlock {
⋮----
protected $block_name = 'payment-method-icons';
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function get_block_type_style() {
return array_merge( parent::get_block_type_style(), [ 'wc-blocks-packages-style' ] );
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
$this->asset_data_registry->add( 'availablePaymentMethods', $this->get_available_payment_methods() );
⋮----
protected function render( $attributes, $content, $block ) {
$payment_methods = $this->get_available_payment_methods();
⋮----
$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes );
⋮----
$output .= $this->render_payment_method_icons( $attributes );
⋮----
private function render_payment_method_icons( $attributes ) {
⋮----
$all_payment_methods = $this->get_available_payment_methods();
⋮----
$output        .= '<span class="wc-block-payment-method-icons__icon" style="background-image: url(\'' . \esc_url( $payment_method['icon'] ) . '\');" role="img" aria-label="' . \esc_attr( $payment_method['name'] ) . '"></span>';
... (37 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/PriceFilter.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class PriceFilter extends AbstractBlock {
⋮----
protected $block_name     = 'price-filter';
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
$this->asset_data_registry->add( 'attributes', array_values( wc_get_attribute_taxonomies() ) );
⋮----
$this->asset_data_registry->add( 'queryState', $query_state );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProceedToCheckoutBlock.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ProceedToCheckoutBlock extends AbstractInnerBlock {
⋮----
protected $block_name = 'proceed-to-checkout-block';
⋮----
protected function enqueue_data( array $attributes = [] ) {
$this->asset_data_registry->register_page_id( isset( $attributes['checkoutPageId'] ) ? $attributes['checkoutPageId'] : 0 );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductAverageRating.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class ProductAverageRating extends AbstractBlock {
⋮----
protected $block_name = 'product-average-rating';
⋮----
protected $api_version = '3';
⋮----
protected function register_block_type_assets() {
⋮----
protected function get_block_type_style() {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
if ( ! $product || ! $product->get_review_count() ) {
⋮----
$styles_and_classes            = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes, array(), array( 'extra_classes' ) );
$text_align_styles_and_classes = StyleAttributesUtils::get_text_align_class_and_style( $attributes );
⋮----
$product->get_average_rating()
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductBestSellers.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ProductBestSellers extends AbstractProductGrid {
⋮----
protected $block_name = 'product-best-sellers';
⋮----
protected function set_block_query_args( &$query_args ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductButton.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Blocks\BlockTypes\AddToCartWithOptions\Utils;
use Automattic\WooCommerce\Blocks\Utils\BlocksSharedState;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class ProductButton extends AbstractBlock {
⋮----
protected $block_name = 'product-button';
⋮----
private static $cart = null;
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function enqueue_assets( array $attributes, $content, $block ) {
parent::enqueue_assets( $attributes, $content, $block );
⋮----
public function dequeue_add_to_cart_scripts() {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
if ( $is_descendant_of_add_to_cart_form && Utils::is_not_purchasable_product( $product ) ) {
⋮----
BlocksSharedState::load_cart_state( 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WooCommerce' );
⋮----
$number_of_items_in_cart  = $this->get_cart_item_quantities_by_product_id( $product->get_id() );
$is_product_purchasable   = $this->is_product_purchasable( $product );
⋮----
... (59 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductCategories.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class ProductCategories extends AbstractDynamicBlock {
⋮----
protected $block_name = 'product-categories';
⋮----
protected $defaults = array(
⋮----
protected function get_block_type_attributes() {
⋮----
parent::get_block_type_attributes(),
⋮----
'align'            => $this->get_schema_align(),
'className'        => $this->get_schema_string(),
'hasCount'         => $this->get_schema_boolean( true ),
'hasImage'         => $this->get_schema_boolean( false ),
'hasEmpty'         => $this->get_schema_boolean( false ),
'isDropdown'       => $this->get_schema_boolean( false ),
'isHierarchical'   => $this->get_schema_boolean( true ),
'showChildrenOnly' => $this->get_schema_boolean( false ),
'textColor'        => $this->get_schema_string(),
'fontSize'         => $this->get_schema_string(),
'lineHeight'       => $this->get_schema_string(),
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$categories = $this->get_categories( $attributes );
⋮----
... (64 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductCategory.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ProductCategory extends AbstractProductGrid {
⋮----
protected $block_name = 'product-category';
⋮----
protected function set_block_query_args( &$query_args ) {}
⋮----
protected function get_block_type_attributes() {
⋮----
parent::get_block_type_attributes(),
⋮----
'className' => $this->get_schema_string(),
'orderby'   => $this->get_schema_orderby(),
'editMode'  => $this->get_schema_boolean( true ),
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductDescription.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\ProductDescriptionUtils;
⋮----
class ProductDescription extends AbstractBlock {
⋮----
protected $block_name = 'product-description';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$description = ProductDescriptionUtils::guarded_format(
⋮----
/**
				 * This filter is documented in wp-includes/post-template.php.
				 * We follow core/content block to replace ]]> with ]&gt;
				 */
// phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
return apply_filters( 'the_content', str_replace( ']]>', ']]&gt;', $product->get_description() ) );
⋮----
// Add wrapper with block attributes.
⋮----
protected function get_block_type_style() {
⋮----
protected function get_block_type_script( $key = null ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductDetails.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use WP_Block;
use WP_HTML_Tag_Processor;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class ProductDetails extends AbstractBlock {
⋮----
protected $block_name = 'product-details';
⋮----
protected function initialize() {
parent::initialize();
⋮----
foreach ( $this->validate_hooked_blocks( $hooked_blocks ) as $slug => $block ) {
$this->register_hooked_block( $slug, $block );
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
return $this->render_legacy_block( $attributes, $content, $block );
⋮----
$parsed_block = $this->hide_empty_accordion_items( $parsed_block, $block->context );
⋮----
$parsed_block = $this->inject_compatible_tabs( $parsed_block );
⋮----
$carry .= ( new \WP_Block( $parsed_inner_block, $block->context ) )->render();
⋮----
/**
	 * Inject compatible tabs.
... (74 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterActive.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
final class ProductFilterActive extends AbstractBlock {
⋮----
protected $block_name = 'product-filter-active';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
'data-wp-key'          => wp_unique_prefixed_id( $this->get_full_block_name() ),
⋮----
$carry .= ( new \WP_Block( $parsed_block, array( 'woocommerce/removableItems' => $filter_context ) ) )->render();
⋮----
protected function get_block_type_style() {
⋮----
protected function get_block_type_editor_style() {
⋮----
protected function get_block_type_script( $key = null ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterAttribute.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductCollectionUtils;
use Automattic\WooCommerce\Internal\ProductAttributes\VisualAttributeTermMeta;
use Automattic\WooCommerce\Internal\ProductFilters\FilterDataProvider;
use Automattic\WooCommerce\Internal\ProductFilters\QueryClauses;
⋮----
final class ProductFilterAttribute extends AbstractBlock {
⋮----
protected $block_name = 'product-filter-attribute';
⋮----
protected function initialize() {
parent::initialize();
⋮----
protected function enqueue_data( array $attributes = array() ) {
parent::enqueue_data( $attributes );
⋮----
$this->asset_data_registry->add( 'defaultProductFilterAttribute', $this->get_default_product_attribute() );
⋮----
public function delete_default_attribute_id_transient( $transient ) {
⋮----
public function prepare_selected_filters( $items, $params ) {
⋮----
protected function render( $block_attributes, $content, $block ) {
⋮----
$default_product_attribute       = $this->get_default_product_attribute();
⋮----
$attribute_counts = $this->get_attribute_counts( $block, $product_attribute->slug, $block_attributes['queryType'] );
⋮----
$is_visual_attribute = VisualAttributeTermMeta::is_visual_attribute_taxonomy( $product_attribute->slug );
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterCheckboxList.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Internal\ProductAttributes\VisualAttributeTermMeta;
⋮----
final class ProductFilterCheckboxList extends AbstractBlock {
⋮----
protected $block_name = 'product-filter-checkbox-list';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$tags = new \WP_HTML_Tag_Processor( $content );
if ( $tags->next_tag( array( 'class_name' => 'wc-block-product-filter-checkbox-list' ) ) ) {
$classes = $tags->get_attribute( 'class' );
$style   = $tags->get_attribute( 'style' );
⋮----
$has_visual_swatches = self::has_visual_swatches( $items );
⋮----
$swatch_style = $this->get_item_swatch_style( $item );
⋮----
private static function has_visual_swatches( array $items ): bool {
⋮----
private function get_item_swatch_style( array $item ): string {
⋮----
return VisualAttributeTermMeta::get_swatch_style( $visual );
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterChips.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Internal\ProductAttributes\VisualAttributeTermMeta;
⋮----
final class ProductFilterChips extends AbstractBlock {
⋮----
protected $block_name = 'product-filter-chips';
⋮----
protected function enqueue_data( array $attributes = array() ) {
parent::enqueue_data( $attributes );
⋮----
$this->asset_data_registry->add( 'globalStylesColors', wp_get_global_styles( array( 'color' ) ) );
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$tags    = new \WP_HTML_Tag_Processor( $content );
if ( $tags->next_tag( array( 'class_name' => 'wc-block-product-filter-chips' ) ) ) {
$saved_classes = $tags->get_attribute( 'class' );
$saved_style   = $tags->get_attribute( 'style' );
⋮----
$has_visual_swatches     = self::has_visual_swatches( $items );
⋮----
$swatch_style = $this->get_item_swatch_style( $item );
⋮----
private static function has_visual_swatches( array $items ): bool {
⋮----
private function get_item_swatch_style( array $item ): string {
⋮----
return VisualAttributeTermMeta::get_swatch_style( $visual );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterClearButton.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
final class ProductFilterClearButton extends AbstractBlock {
⋮----
protected $block_name = 'product-filter-clear-button';
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$p = new \WP_HTML_Tag_Processor( $content );
⋮----
if ( $p->next_tag( array( 'class_name' => 'wp-block-button__link' ) ) ) {
$p->set_attribute( 'data-wp-on--click', 'actions.removeAll' );
⋮----
$content = $p->get_updated_html();
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterPrice.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductCollectionUtils;
use Automattic\WooCommerce\Internal\ProductFilters\FilterDataProvider;
use Automattic\WooCommerce\Internal\ProductFilters\QueryClauses;
⋮----
final class ProductFilterPrice extends AbstractBlock {
⋮----
protected $block_name = 'product-filter-price';
⋮----
protected function initialize() {
parent::initialize();
⋮----
public function prepare_selected_filters( $items, $params ) {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$price_range   = $this->get_filtered_price( $block );
⋮----
'data-wp-key'         => wp_unique_prefixed_id( $this->get_full_block_name() ),
⋮----
$carry .= ( new \WP_Block( $parsed_block, array( 'woocommerce/rangeInput' => $filter_context ) ) )->render();
⋮----
/**
	 * Retrieve the price filter data for current block.
	 *
	 * @param WP_Block $block Block instance.
	 */
private function get_filtered_price( $block ) {
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterPriceSlider.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ProductFilterPriceSlider extends AbstractBlock {
⋮----
protected $block_name = 'product-filter-price-slider';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$tags = new \WP_HTML_Tag_Processor( $content );
if ( $tags->next_tag( array( 'class_name' => 'wc-block-product-filter-price-slider' ) ) ) {
$classes = $tags->get_attribute( 'class' );
$style   = $tags->get_attribute( 'style' );
⋮----
'data-wp-key'         => wp_unique_prefixed_id( $this->get_full_block_name() ),
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterRating.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductCollectionUtils;
use Automattic\WooCommerce\Internal\ProductFilters\FilterDataProvider;
use Automattic\WooCommerce\Internal\ProductFilters\QueryClauses;
⋮----
final class ProductFilterRating extends AbstractBlock {
⋮----
protected $block_name = 'product-filter-rating';
⋮----
protected function initialize() {
parent::initialize();
⋮----
public function prepare_selected_filters( $items, $params ) {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$rating_counts = $this->get_rating_counts( $block );
⋮----
'data-wp-key'         => wp_unique_prefixed_id( $this->get_full_block_name() ),
⋮----
$carry .= ( new \WP_Block( $parsed_block, array( 'woocommerce/selectableItems' => $filter_context ) ) )->render();
⋮----
/**
	 * Retrieve the rating filter data for current block.
	 *
	 * @param WP_Block $block Block instance.
	 */
private function get_rating_counts( $block ) {
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterRemovableChips.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
final class ProductFilterRemovableChips extends AbstractBlock {
⋮----
protected $block_name = 'product-filter-removable-chips';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$tags = new \WP_HTML_Tag_Processor( $content );
if ( $tags->next_tag( array( 'class_name' => 'wc-block-product-filter-removable-chips' ) ) ) {
$classes = $tags->get_attribute( 'class' );
$style   = $tags->get_attribute( 'style' );
⋮----
'data-wp-key'         => wp_unique_prefixed_id( $this->get_full_block_name() ),
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductFilters.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\BlocksSharedState;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Internal\Features\BlockEditorUnifiedAssets;
use Automattic\WooCommerce\Internal\ProductFilters\Params;
use WP_Block;
⋮----
class ProductFilters extends AbstractBlock {
⋮----
protected $block_name = 'product-filters';
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function enqueue_data( array $attributes = array() ) {
parent::enqueue_data( $attributes );
⋮----
$inline_style_handle = BlockEditorUnifiedAssets::is_enabled() && is_admin()
⋮----
: generate_block_asset_handle( $this->get_full_block_name(), 'style' );
⋮----
$this->get_responsive_styles()
⋮----
$this->asset_data_registry->add( 'globalStylesColors', wp_get_global_styles( array( 'color' ) ) );
⋮----
BlocksSharedState::load_store_config( 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WooCommerce' );
⋮----
private function get_overlay_breakpoint() {
⋮----
private function get_responsive_styles() {
... (50 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterStatus.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductCollectionUtils;
use Automattic\WooCommerce\Internal\ProductFilters\FilterDataProvider;
use Automattic\WooCommerce\Internal\ProductFilters\QueryClauses;
⋮----
final class ProductFilterStatus extends AbstractBlock {
⋮----
protected $block_name = 'product-filter-status';
⋮----
protected function initialize() {
parent::initialize();
⋮----
public function prepare_selected_filters( $items, $params ) {
⋮----
protected function enqueue_data( array $stock_statuses = array() ) {
parent::enqueue_data( $stock_statuses );
$this->asset_data_registry->add( 'stockStatusOptions', wc_get_product_stock_status_options() );
$this->asset_data_registry->add( 'hideOutOfStockItems', 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) );
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$stock_status_data       = $this->get_stock_status_counts( $block );
⋮----
'data-wp-key'         => wp_unique_prefixed_id( $this->get_full_block_name() ),
⋮----
$carry .= ( new \WP_Block( $parsed_block, array( 'woocommerce/selectableItems' => $filter_context ) ) )->render();
⋮----
/**
	 * Retrieve the status filter data for current block.
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductFilterTaxonomy.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductCollectionUtils;
use Automattic\WooCommerce\Internal\ProductFilters\FilterDataProvider;
use Automattic\WooCommerce\Internal\ProductFilters\QueryClauses;
use Automattic\WooCommerce\Internal\ProductFilters\TaxonomyHierarchyData;
⋮----
final class ProductFilterTaxonomy extends AbstractBlock {
⋮----
protected $block_name = 'product-filter-taxonomy';
⋮----
public function prepare_selected_filters( $items, $params ) {
⋮----
$params_handler = $container->get( \Automattic\WooCommerce\Internal\ProductFilters\Params::class );
⋮----
$taxonomy_params = $params_handler->get_param( 'taxonomy' );
⋮----
protected function initialize() {
parent::initialize();
⋮----
$this->register_taxonomy_menu_order_rest_field();
⋮----
private function register_taxonomy_menu_order_rest_field(): void {
⋮----
protected function enqueue_data( array $attributes = array() ) {
parent::enqueue_data( $attributes );
⋮----
$this->asset_data_registry->add( 'filterableProductTaxonomies', $this->get_taxonomies() );
⋮----
$this->asset_data_registry->add(
... (67 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductGallery.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\ProductGalleryUtils;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\ProductGallery\ProductMediaGallery;
⋮----
class ProductGallery extends AbstractBlock {
⋮----
protected $block_name = 'product-gallery';
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function render_dialog( $media_items ) {
⋮----
<?php echo $this->get_dialog_video_html( $media ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
⋮----
private function get_dialog_video_html( $media ) {
return ProductGalleryUtils::get_video_html(
ProductGalleryUtils::get_video_attributes( $media, 'dialog' )
⋮----
protected function inject_dialog( $gallery_html, $dialog_html ) {
⋮----
private function get_product_image_attributes( $inner_blocks ) {
⋮----
$found_attributes = $this->get_product_image_attributes( $inner_block->inner_blocks );
⋮----
private function get_store_thumbnail_aspect_ratio() {
⋮----
private function resolve_product_image_aspect_ratio( $block ) {
... (44 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductGalleryLargeImage.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\ProductGalleryUtils;
use WP_Block;
⋮----
class ProductGalleryLargeImage extends AbstractBlock {
⋮----
protected $block_name = 'product-gallery-large-image';
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function initialize() {
⋮----
parent::initialize();
⋮----
protected function enqueue_assets( array $attributes, $content, $block ) {
⋮----
parent::enqueue_assets( $attributes, $content, $block );
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$images_html .= $this->get_main_media_html( $block->context, $product, $inner_block );
⋮----
$product_gallery_media_count = ProductGalleryUtils::get_product_gallery_media_count( $product );
⋮----
)->render( array( 'dynamic' => true ) );
⋮----
private function update_single_image( $image_html, $context, $index ) {
$p = $this->get_product_image_processor( $image_html );
⋮----
... (58 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductGalleryThumbnails.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Blocks\Utils\ProductGalleryUtils;
⋮----
class ProductGalleryThumbnails extends AbstractBlock {
⋮----
protected $block_name = 'product-gallery-thumbnails';
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes );
⋮----
// We crop the images to square only if the aspect ratio is 1:1.
// Otherwise, we show the uncropped and use object-fit to crop them.
⋮----
$product_gallery_media = ProductGalleryUtils::get_product_gallery_media_data( $product, $image_size );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductImage.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\ProductGalleryUtils;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class ProductImage extends AbstractBlock {
⋮----
protected $block_name = 'product-image';
⋮----
protected $api_version = '3';
⋮----
protected function register_block_type_assets() {
⋮----
protected function get_block_type_uses_context() {
⋮----
private function parse_attributes( $attributes ) {
⋮----
private function render_on_sale_badge( $product, $attributes ) {
⋮----
! $product->is_on_sale()
⋮----
$block = new \WP_Block(
⋮----
'postId' => $product->get_id(),
⋮----
return $block->render();
⋮----
private function render_anchor( $product, $on_sale_badge, $product_image, $attributes, $inner_blocks_content ) {
$product_permalink = $product->get_permalink();
⋮----
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductImageGallery.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class ProductImageGallery extends AbstractBlock {
⋮----
protected $block_name = 'product-image-gallery';
⋮----
protected function register_block_type_assets() {
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function enqueue_assets( $attributes, $content, $block ) {
parent::enqueue_assets( $attributes, $content, $block );
⋮----
public function enqueue_legacy_assets() {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$classname = StyleAttributesUtils::get_classes_by_attributes( $attributes, array( 'extra_classes' ) );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductMeta.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ProductMeta extends AbstractBlock {
⋮----
protected $block_name = 'product-meta';
⋮----
protected function get_block_type_editor_script( $key = null ) {
⋮----
protected function get_block_type_editor_style() {
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function get_block_type_style() {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductNew.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ProductNew extends AbstractProductGrid {
⋮----
protected $block_name = 'product-new';
⋮----
protected function set_block_query_args( &$query_args ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductOnSale.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ProductOnSale extends AbstractProductGrid {
⋮----
protected $block_name = 'product-on-sale';
⋮----
protected function set_block_query_args( &$query_args ) {
⋮----
protected function get_block_type_attributes() {
⋮----
parent::get_block_type_attributes(),
⋮----
'className' => $this->get_schema_string(),
'orderby'   => $this->get_schema_orderby(),
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductPrice.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class ProductPrice extends AbstractBlock {
⋮----
protected $block_name = 'product-price';
⋮----
protected $api_version = '3';
⋮----
protected function get_block_type_style() {
⋮----
protected function register_block_type_assets() {
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$wrapper_class      = StyleAttributesUtils::get_classes_by_attributes( $attributes, array( 'extra_classes' ) );
$styles_and_classes = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes, array(), array( 'extra_classes', 'margin' ) );
⋮----
$is_interactive                            = ! $is_descendant_of_product_collection && ! $is_descendant_of_grouped_product_selector && $product->is_type( ProductType::VARIABLE );
⋮----
$prices_vary = $product->get_variation_sale_price( 'min' ) !== $product->get_variation_sale_price( 'max' )
|| $product->get_variation_regular_price( 'min' ) !== $product->get_variation_regular_price( 'max' );
⋮----
$product->get_price_html()
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductQuery.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Enums\ProductStatus;
use WP_Query;
use Automattic\WooCommerce\Blocks\Utils\Utils;
use Automattic\WooCommerce\Enums\ProductStockStatus;
⋮----
class ProductQuery extends AbstractBlock {
⋮----
protected $block_name = 'product-query';
⋮----
protected $parsed_block;
⋮----
protected $custom_order_opts = array( 'popularity', 'rating' );
⋮----
protected $attributes_filter_query_args = array();
⋮----
protected $is_custom_inherit_global_query_implementation_enabled = false;
⋮----
protected $valid_query_vars;
⋮----
protected function initialize() {
⋮----
parent::initialize();
⋮----
private function check_if_post_template_has_support_for_grid_view() {
if ( Utils::wp_version_compare( '6.3', '>=' ) ) {
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
... (144 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductRating.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class ProductRating extends AbstractBlock {
⋮----
protected $block_name = 'product-rating';
⋮----
protected $api_version = '3';
⋮----
private function parse_attributes( $attributes ) {
⋮----
protected function register_block_type_assets() {
⋮----
protected function get_block_type_style() {
return array_merge( parent::get_block_type_style(), [ 'wc-blocks-packages-style' ] );
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
parent::register_block_type_assets();
$this->register_chunk_translations( [ $this->block_name ] );
⋮----
if ( $product && $product->get_review_count() > 0
&& $product->get_reviews_allowed()
⋮----
$product_reviews_count                    = $product->get_review_count();
$product_rating                           = $product->get_average_rating();
$parsed_attributes                        = $this->parse_attributes( $attributes );
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductRatingCounter.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class ProductRatingCounter extends AbstractBlock {
⋮----
protected $block_name = 'product-rating-counter';
⋮----
protected $api_version = '3';
⋮----
private function parse_attributes( $attributes ) {
⋮----
protected function register_block_type_assets() {
⋮----
protected function get_block_type_style() {
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
parent::register_block_type_assets();
$this->register_chunk_translations( [ $this->block_name ] );
⋮----
if ( $product && $product->get_review_count() > 0 ) {
$product_reviews_count                    = $product->get_review_count();
$product_rating                           = $product->get_average_rating();
$parsed_attributes                        = $this->parse_attributes( $attributes );
⋮----
$styles_and_classes            = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes );
$text_align_styles_and_classes = StyleAttributesUtils::get_text_align_class_and_style( $attributes );
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductRatingStars.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class ProductRatingStars extends AbstractBlock {
⋮----
protected $block_name = 'product-rating-stars';
⋮----
protected $api_version = '3';
⋮----
protected function register_block_type_assets() {
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
parent::register_block_type_assets();
$this->register_chunk_translations( [ $this->block_name ] );
⋮----
$product_reviews_count = $product->get_review_count();
$product_rating        = $product->get_average_rating();
⋮----
$styles_and_classes            = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes );
$text_align_styles_and_classes = StyleAttributesUtils::get_text_align_class_and_style( $attributes );
⋮----
$rating_html = wc_get_rating_html( $product->get_average_rating() );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductResultsCount.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class ProductResultsCount extends AbstractBlock {
⋮----
protected $block_name = 'product-results-count';
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$p = new \WP_HTML_Tag_Processor( $product_results_count );
⋮----
$p->next_tag( 'div' );
$parsed_style_attributes = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes );
⋮----
$p->set_attribute( 'class', implode( ' ', $classes ) );
$p->set_attribute( 'style', $parsed_style_attributes['styles'] );
$p->set_attribute( 'data-wp-interactive', $this->get_full_block_name() );
$p->set_attribute(
⋮----
return $p->get_updated_html();
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductSaleBadge.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class ProductSaleBadge extends AbstractBlock {
⋮----
protected $block_name = 'product-sale-badge';
⋮----
protected $api_version = '3';
⋮----
protected function register_block_type_assets() {
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$is_on_sale = $product->is_on_sale();
⋮----
$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes, array(), array( 'extra_classes' ) );
⋮----
$classname = StyleAttributesUtils::get_classes_by_attributes( $attributes, array( 'extra_classes' ) );
⋮----
/**
		 * Filters the product sale badge text.
		 *
		 * @hook woocommerce_sale_badge_text
		 * @since 10.0.0
		 *
		 * @param string $sale_text The sale badge text.
		 * @param WC_Product $product The product object.
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductsByAttribute.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ProductsByAttribute extends AbstractProductGrid {
⋮----
protected $block_name = 'products-by-attribute';
⋮----
protected function set_block_query_args( &$query_args ) {
⋮----
protected function get_block_type_attributes() {
⋮----
'align'             => $this->get_schema_align(),
'alignButtons'      => $this->get_schema_boolean( false ),
⋮----
'className'         => $this->get_schema_string(),
'columns'           => $this->get_schema_number( wc_get_theme_support( 'product_blocks::default_columns', 3 ) ),
'contentVisibility' => $this->get_schema_content_visibility(),
'orderby'           => $this->get_schema_orderby(),
'rows'              => $this->get_schema_number( wc_get_theme_support( 'product_blocks::default_rows', 3 ) ),
'isPreview'         => $this->get_schema_boolean( false ),
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductSearch.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ProductSearch extends AbstractBlock {
⋮----
protected $block_name = 'product-search';
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$this->asset_api->add_inline_script(
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductSKU.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Enums\ProductType;
use WP_Block;
⋮----
class ProductSKU extends AbstractBlock {
⋮----
protected $block_name = 'product-sku';
⋮----
protected $api_version = '3';
⋮----
protected function register_block_type_assets() {
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
parent::register_block_type_assets();
$this->register_chunk_translations( [ $this->block_name ] );
⋮----
$product_sku = $product->get_sku();
⋮----
$is_interactive                      = ! $is_descendant_of_product_collection && $product->is_type( ProductType::VARIABLE );
⋮----
$styles_and_classes = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductSpecifications.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class ProductSpecifications extends AbstractBlock {
⋮----
protected $block_name = 'product-specifications';
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
// Get display settings with defaults.
⋮----
if ( $show_weight && $product->has_weight() ) {
⋮----
'value'     => wc_format_weight( $product->get_weight() ),
⋮----
if ( $show_dimensions && $product->has_dimensions() ) {
⋮----
'value'     => wc_format_dimensions( $product->get_dimensions( false ) ),
⋮----
$is_interactive = $product->is_type( ProductType::VARIABLE );
⋮----
foreach ( $product->get_attributes() as $attribute ) {
⋮----
if ( $attribute->is_taxonomy() ) {
$attribute_taxonomy = $attribute->get_taxonomy_object();
$attribute_values   = wc_get_product_terms( $product->get_id(), $attribute->get_name(), array( 'fields' => 'all' ) );
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductStockIndicator.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
use Automattic\WooCommerce\Blocks\Utils\ProductAvailabilityUtils;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class ProductStockIndicator extends AbstractBlock {
⋮----
protected $block_name = 'product-stock-indicator';
⋮----
protected $api_version = '3';
⋮----
protected function register_block_type_assets() {
⋮----
protected function get_block_type_uses_context() {
⋮----
protected function get_product_types_without_stock_indicator() {
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
⋮----
$this->asset_data_registry->add( 'productTypesWithoutStockIndicator', $this->get_product_types_without_stock_indicator() );
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
parent::register_block_type_assets();
$this->register_chunk_translations( [ $this->block_name ] );
⋮----
// Use the global product if the product to render can't be retrieved from the context.
⋮----
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductSummary.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\ProductDescriptionUtils;
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class ProductSummary extends AbstractBlock {
⋮----
protected $block_name = 'product-summary';
⋮----
protected $api_version = '3';
⋮----
protected function register_block_type_assets() {
⋮----
protected function get_block_type_uses_context() {
⋮----
private function get_source( $product, $show_description_if_empty ) {
$short_description = $product->get_short_description();
⋮----
$short_description = $GLOBALS['wp_embed']->run_shortcode( $short_description );
⋮----
$description = $product->get_description();
⋮----
$description = $GLOBALS['wp_embed']->run_shortcode( $description );
⋮----
/**
	 * Create anchor element based on input.
	 *
	 * @param WC_Product $product   Product object.
	 * @param string     $link_text Link text.
	 * @return string
... (43 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductTag.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ProductTag extends AbstractProductGrid {
⋮----
protected $block_name = 'product-tag';
⋮----
protected function set_block_query_args( &$query_args ) {
⋮----
protected function get_block_type_attributes() {
⋮----
'className'         => $this->get_schema_string(),
'columns'           => $this->get_schema_number( wc_get_theme_support( 'product_blocks::default_columns', 3 ) ),
'rows'              => $this->get_schema_number( wc_get_theme_support( 'product_blocks::default_rows', 3 ) ),
'contentVisibility' => $this->get_schema_content_visibility(),
'align'             => $this->get_schema_align(),
'alignButtons'      => $this->get_schema_boolean( false ),
'orderby'           => $this->get_schema_orderby(),
'tags'              => $this->get_schema_list_ids(),
⋮----
'isPreview'         => $this->get_schema_boolean( false ),
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
⋮----
$this->asset_data_registry->add( 'hasTags', $tag_count > 0 );
$this->asset_data_registry->add( 'limitTags', $tag_count > 100 );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductTemplate.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\ProductCollection\Utils as ProductCollectionUtils;
use WP_Block;
⋮----
class ProductTemplate extends AbstractBlock {
⋮----
protected $block_name = 'product-template';
⋮----
protected function initialize() {
⋮----
parent::initialize();
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function render( $attributes, $content, $block ) {
$query = ProductCollectionUtils::prepare_and_execute_query( $block );
⋮----
if ( ! $query->have_posts() ) {
⋮----
if ( $this->block_core_post_template_uses_featured_image( $block->inner_blocks ) ) {
⋮----
while ( $query->have_posts() ) {
$query->the_post();
⋮----
// Get an instance of the current Post Template block.
⋮----
// Set the block name to one that does not correspond to an existing registered block.
// This ensures that for the inner instances of the Post Template block, we do not render any block supports.
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductTitle.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ProductTitle extends AbstractBlock {
⋮----
protected $block_name = 'product-title';
⋮----
protected $api_version = '3';
⋮----
protected function register_block_type_assets() {
parent::register_block_type_assets();
$this->register_chunk_translations( [ $this->block_name ] );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ProductTopRated.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ProductTopRated extends AbstractProductGrid {
⋮----
protected $block_name = 'product-top-rated';
⋮----
protected function set_block_query_args( &$query_args ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/RatingFilter.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class RatingFilter extends AbstractBlock {
⋮----
protected $block_name  = 'rating-filter';
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
protected function get_block_type_style() {
return array_merge( parent::get_block_type_style(), [ 'wc-blocks-packages-style' ] );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/RelatedProducts.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Enums\ProductStatus;
⋮----
class RelatedProducts extends AbstractBlock {
⋮----
protected $block_name = 'related-products';
⋮----
protected $parsed_block;
⋮----
protected function initialize() {
parent::initialize();
⋮----
protected function register_block_type_assets() {
⋮----
protected function get_block_type_style() {
⋮----
public function update_query( $pre_render, $parsed_block ) {
⋮----
if ( ProductQuery::is_woocommerce_variation( $parsed_block ) && 'woocommerce/related-products' === $parsed_block['attrs']['namespace'] ) {
⋮----
public function build_query( $query, $block = null ) {
⋮----
if ( ! $this->is_related_products_block( $parsed_block, $block ) ) {
⋮----
$related_products_ids = $this->get_related_products_ids( $query['posts_per_page'] );
⋮----
public function render_block( string $content, array $block ) {
if ( ! $this->is_related_products_block( $block ) ) {
⋮----
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ReviewsByCategory.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ReviewsByCategory extends AbstractBlock {
⋮----
protected $block_name = 'reviews-by-category';
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
'path'         => $this->asset_api->get_block_asset_build_path( 'reviews-frontend' ),
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
$this->asset_data_registry->add( 'reviewRatingsEnabled', wc_review_ratings_enabled() );
$this->asset_data_registry->add( 'showAvatars', '1' === get_option( 'show_avatars' ) );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/ReviewsByProduct.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class ReviewsByProduct extends AbstractBlock {
⋮----
protected $block_name = 'reviews-by-product';
⋮----
protected function get_block_type_script( $key = null ) {
⋮----
'path'         => $this->asset_api->get_block_asset_build_path( 'reviews-frontend' ),
⋮----
protected function enqueue_data( array $attributes = [] ) {
parent::enqueue_data( $attributes );
$this->asset_data_registry->add( 'reviewRatingsEnabled', wc_review_ratings_enabled() );
$this->asset_data_registry->add( 'showAvatars', '1' === get_option( 'show_avatars' ) );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/SavedForLater.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\BlocksSharedState;
use Automattic\WooCommerce\Internal\ShopperLists\ShopperListRenderer;
use Automattic\WooCommerce\Internal\ShopperLists\ShopperListsController;
use Automattic\WooCommerce\Proxies\LegacyProxy;
⋮----
final class SavedForLater extends AbstractBlock {
⋮----
protected $block_name = 'saved-for-later';
⋮----
protected function initialize(): void {
⋮----
parent::initialize();
⋮----
public function disable_when_feature_off( $settings, $metadata ) {
if ( ! isset( $metadata['name'] ) || $this->get_full_block_name() !== $metadata['name'] || $this->is_feature_enabled() ) {
⋮----
private function is_feature_enabled(): bool {
return wc_get_container()->get( ShopperListsController::class )->is_enabled( 'saved-for-later' );
⋮----
public function set_hooked_block_attributes( $parsed_hooked_block, $hooked_block_type, $relative_position, $parsed_anchor_block ) {
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
if ( ! $this->is_feature_enabled() ) {
⋮----
// Guests have no personal list — bail before enqueuing assets or seeding state.
⋮----
// Set from render() (not Cart::enqueue_data via has_block()) so it works when this
... (112 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/SingleProduct.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\ProductDataUtils;
use Automattic\WooCommerce\Blocks\Utils\Utils as BlocksUtils;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class SingleProduct extends AbstractBlock {
⋮----
protected $block_name = 'single-product';
⋮----
protected $product_id = 0;
⋮----
protected $single_product_inner_blocks_names = [];
⋮----
protected function initialize() {
parent::initialize();
⋮----
public function restore_global_post( $block_content, $parsed_block, $block_instance ) {
⋮----
public function update_context( $context, $block, $parent_block ) {
⋮----
$this->extract_single_product_inner_block_names( $block )
⋮----
$this->replace_post_for_single_product_inner_block( $block, $context );
⋮----
protected function extract_single_product_inner_block_names( $block, &$result = [] ) {
⋮----
$this->extract_single_product_inner_block_names( $inner_block, $result );
⋮----
protected function replace_post_for_single_product_inner_block( $block, &$context ) {
... (29 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/StockFilter.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
class StockFilter extends AbstractBlock {
⋮----
protected $block_name        = 'stock-filter';
⋮----
protected function enqueue_data( array $stock_statuses = [] ) {
parent::enqueue_data( $stock_statuses );
$this->asset_data_registry->add( 'stockStatusOptions', wc_get_product_stock_status_options() );
$this->asset_data_registry->add( 'hideOutOfStockItems', 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) );
⋮----
public static function get_stock_status_query_var_values() {
⋮----
protected function get_block_type_style() {
return array_merge( parent::get_block_type_style(), [ 'wc-blocks-packages-style' ] );
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/StoreNotices.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\StyleAttributesUtils;
⋮----
class StoreNotices extends AbstractBlock {
⋮----
protected $block_name = 'store-notices';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
$classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes, array(), array( 'extra_classes' ) );
⋮----
protected function get_block_type_script( $key = null ) {
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypes/Wishlist.php">
namespace Automattic\WooCommerce\Blocks\BlockTypes;
⋮----
use Automattic\WooCommerce\Blocks\Utils\BlocksSharedState;
use Automattic\WooCommerce\Internal\ShopperLists\ShopperListRenderer;
⋮----
final class Wishlist extends AbstractBlock {
⋮----
protected $block_name = 'wishlist';
⋮----
protected function render( $attributes, $content, $block ) {
⋮----
// Clamp to the 2-6 range the SCSS `@for $i from 2 through 6` loop
// and the editor `RangeControl` both support. `absint()` first
// defends against a code-editor override (the attribute can be set
// to any JSON value there); the `min`/`max` then keep the value
// within the range where a `&.columns-#{$i}` rule actually exists.
⋮----
wp_enqueue_script_module( $this->get_full_block_name() );
⋮----
BlocksSharedState::load_store_config( $consent );
BlocksSharedState::load_placeholder_image( $consent );
⋮----
BlocksSharedState::load_cart_state( $consent );
⋮----
$items = $this->prefetch_items();
⋮----
'removeLabelTemplate' => $this->get_remove_label_template(),
⋮----
'pendingKeys' => new \stdClass(),
⋮----
... (82 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldsSchema/checkout-document-schema.json">
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "Cart and Checkout Document Object Schema",
    "description": "Document object schema for cart, checkout, and customer information, to be used for conditional visibility, requirement, and validation of fields.",
    "type": "object",
    "properties": {
        "cart": {
            "type": "object",
            "description": "Information about the shopping cart",
            "properties": {
                "coupons": {
                    "type": "array",
                    "description": "List of coupon codes applied to the cart",
                    "items": {
                        "type": "string"
                    }
                },
                "shipping_rates": {
                    "type": "array",
                    "description": "List of currently selected shipping rates",
                    "items": {
                        "type": "string",
                        "description": "Shipping rate identifier using the full shipping rate ID so method_id:instance_id, for example: flat_rate:1"
                    }
                },
                "items": {
                    "type": "array",
                    "description": "List of product IDs in the cart, IDs will be duplicated depending on the quantity of the product in the cart, so if you have 2 of product ID 1, the array will have 2 entries of product ID 1",
                    "items": {
                        "type": "integer"
... (177 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldsSchema/DocumentObject.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldsSchema;
⋮----
use WC_Cart;
use WC_Customer;
use Automattic\WooCommerce\StoreApi\StoreApi;
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Schemas\V1\CartSchema;
use Automattic\WooCommerce\StoreApi\Schemas\V1\BillingAddressSchema;
use Automattic\WooCommerce\StoreApi\Schemas\V1\ShippingAddressSchema;
use Automattic\WooCommerce\StoreApi\Utilities\LocalPickupUtils;
use Automattic\WooCommerce\StoreApi\Utilities\CartController;
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
class DocumentObject {
⋮----
protected $context = null;
⋮----
protected $valid_contexts = [
⋮----
protected $cart = null;
⋮----
protected $customer = null;
⋮----
protected $cart_controller;
⋮----
protected $schema_controller;
⋮----
protected $request_data = [];
⋮----
public function __construct( array $request_data = [] ) {
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldsSchema/json-schema-draft-07.json">
{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "http://json-schema.org/draft-07/schema#",
    "title": "Core schema meta-schema",
    "definitions": {
        "schemaArray": {
            "type": "array",
            "minItems": 1,
            "items": { "$ref": "#" }
        },
        "nonNegativeInteger": {
            "type": "integer",
            "minimum": 0
        },
        "nonNegativeIntegerDefault0": {
            "allOf": [
                { "$ref": "#/definitions/nonNegativeInteger" },
                { "default": 0 }
            ]
        },
        "simpleTypes": {
            "enum": [
                "array",
                "boolean",
                "integer",
                "null",
                "number",
                "object",
                "string"
            ]
... (143 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldsSchema/Validation.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldsSchema;
⋮----
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldsSchema\DocumentObject;
⋮----
Helper,
Validator
⋮----
use WP_Error;
⋮----
class Validation {
⋮----
private static $meta_schema_json = '';
⋮----
/**
	 * Get the field schema with context.
	 *
	 * @param string $field_id The field ID.
	 * @param array  $field_schema The field schema.
	 * @param string $context The context.
	 * @return array
	 */
public static function get_field_schema_with_context( $field_id, $field_schema, $context ) {
⋮----
private static function schema_is_unwrapped( $schema ) {
⋮----
public static function validate_document_object( DocumentObject $document_object, $rules ) {
if ( self::schema_is_unwrapped( $rules ) ) {
⋮----
$result    = $validator->validate(
Helper::toJSON( $document_object->get_data() ),
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldTypes/AbstractFieldType.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldTypes;
⋮----
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldsSchema\Validation;
use WP_Error;
⋮----
abstract class AbstractFieldType {
⋮----
public function validate_options( array $options ): bool {
⋮----
return $this->registration_error( $id, 'The field label is required.', '8.6.0' );
⋮----
return $this->registration_error( $id, sprintf( 'The %s must be a valid callback.', $callback ), '8.6.0' );
⋮----
$this->doing_it_wrong( sprintf( 'Registering a field with hidden set to true is not supported. The field "%s" will be registered as visible.', $id ), '8.6.0' );
⋮----
$valid = Validation::is_valid_schema( $options[ $rule_field ] );
⋮----
return $this->registration_error( $id, $rule_field . ': ' . $valid->get_error_message(), '8.6.0' );
⋮----
final public function process_options( array $field_data, array $options ) {
$field_data['attributes'] = $this->process_attributes( $field_data['id'], $field_data['attributes'] );
⋮----
return $this->process_type_options( $field_data, $options );
⋮----
protected function process_type_options( array $field_data, array $options ) {
⋮----
protected function process_attributes( $id, $attributes ): array {
⋮----
$this->doing_it_wrong( sprintf( 'An invalid attributes value was supplied when registering field with id: "%s". Attributes must be a non-empty array.', $id ), '8.6.0' );
⋮----
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldTypes/CheckboxFieldType.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldTypes;
⋮----
class CheckboxFieldType extends AbstractFieldType {
⋮----
protected function process_type_options( array $field_data, array $options ) {
⋮----
$this->doing_it_wrong( sprintf( 'Passing an error message to a non-required checkbox "%s" will have no effect. The error message has been removed from the field.', $id ), '9.8.0' );
⋮----
$this->doing_it_wrong( sprintf( 'The error_message property for field with id: "%s" must be a string, you passed %s. A default message will be shown.', $id, gettype( $options['error_message'] ) ), '9.8.0' );
⋮----
public function format_value( $value, array $field ) {
⋮----
public function prepare_form_field( array $form_field ): array {
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldTypes/DateFieldType.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldTypes;
⋮----
use Automattic\WooCommerce\Utilities\TimeUtil;
use WP_Error;
⋮----
class DateFieldType extends AbstractFieldType {
⋮----
protected function process_type_options( array $field_data, array $options ) {
⋮----
return $this->registration_error(
⋮----
if ( $this->is_absolute_date( $value ) ) {
if ( null === $this->parse_date( $value ) ) {
⋮----
$interval = self::parse_duration( $body );
⋮----
/**
	 * Parses a duration without losing weeks on PHP 7.
	 *
	 * @param string $duration The unsigned ISO duration.
	 * @return \DateInterval The parsed duration.
	 */
private static function parse_duration( string $duration ): \DateInterval {
⋮----
return new \DateInterval( $duration );
⋮----
/**
	 * Trims whitespace from submitted date values before they are validated and stored.
	 *
	 * @param mixed $value The submitted value.
... (59 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldTypes/SelectFieldType.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldTypes;
⋮----
class SelectFieldType extends AbstractFieldType {
⋮----
protected function process_type_options( array $field_data, array $options ) {
⋮----
return $this->registration_error( $id, 'Fields of type "select" must have an array of "options".', '8.6.0' );
⋮----
return $this->registration_error( $id, 'Fields of type "select" must have an array of "options" and each option must contain a "value" and "label" member.', '8.6.0' );
⋮----
$this->doing_it_wrong( sprintf( 'Duplicate key found when registering field with id: "%s". The value in each option of "select" fields must be unique. Duplicate value "%s" found. The duplicate key will be removed.', $id, $value ), '8.6.0' );
⋮----
public function format_value( $value, array $field ) {
⋮----
public function prepare_form_field( array $form_field ): array {
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldTypes/TextFieldType.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldTypes;
⋮----
class TextFieldType extends AbstractFieldType {
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/Email/CustomerNewAccount.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services\Email;
⋮----
use Automattic\WooCommerce\Blocks\Domain\Package;
⋮----
class CustomerNewAccount extends \WC_Email {
⋮----
public function __construct( Package $package ) {
parent::__construct();
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services;
⋮----
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
⋮----
DocumentObject, Validation
⋮----
AbstractFieldType, CheckboxFieldType, DateFieldType, SelectFieldType, TextFieldType
⋮----
use WC_Customer;
use WC_Data;
use WC_Order;
use WP_Error;
⋮----
class CheckoutFields {
⋮----
private $additional_fields = [];
⋮----
private $fields_locations;
⋮----
private $field_types = [];
⋮----
private $groups = [ 'billing', 'shipping', 'other' ];
⋮----
private $asset_data_registry;
⋮----
public function __construct( AssetDataRegistry $asset_data_registry ) {
⋮----
'address' => array_merge( \array_diff_key( $this->get_core_fields_keys(), array( 'email' ) ) ),
⋮----
... (196 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldsAdmin.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services;
⋮----
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
⋮----
class CheckoutFieldsAdmin {
⋮----
private $checkout_fields_controller;
⋮----
public function __construct( CheckoutFields $checkout_fields_controller ) {
⋮----
public function init() {
⋮----
protected function format_field_for_meta_box( $field, $key ) {
⋮----
public function update_callback( $key, $value, $order ) {
⋮----
$group               = CheckoutFields::get_group_name( $group );
$this->checkout_fields_controller->persist_field_for_order( $key, $value, $order, $group, false );
⋮----
public function admin_address_fields( $fields, $order = null, $context = 'edit' ) {
⋮----
$additional_fields = $this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'address', $group_name, $context );
⋮----
$prefixed_key              = CheckoutFields::get_group_key( $group_name ) . $key;
$additional_fields[ $key ] = $this->format_field_for_meta_box( $field, $prefixed_key );
⋮----
public function admin_contact_fields( $fields, $order = null, $context = 'edit' ) {
⋮----
$additional_fields = $this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'contact', 'other', $context );
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldsFrontend.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services;
⋮----
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldsSchema\DocumentObject;
use WC_Customer;
use WC_Order;
⋮----
class CheckoutFieldsFrontend {
⋮----
private $checkout_fields_controller;
⋮----
public function __construct( CheckoutFields $checkout_fields_controller ) {
⋮----
public function init() {
⋮----
protected function render_additional_fields( $fields ) {
⋮----
/**
	 * Render custom field.
	 *
	 * @param array $field An additional field and value.
	 * @return string
	 */
protected function render_additional_field( $field ) {
⋮----
public function render_order_address_fields( $address_type, $order ) {
$fields = $this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'address', $address_type, 'view' );
⋮----
$fields = $this->checkout_fields_controller->filter_fields_for_order_confirmation( $fields, $context );
⋮----
echo $this->render_additional_fields( $fields );
... (92 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldsStorage.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services;
⋮----
use WC_Customer;
use WC_Data;
use WC_Order;
⋮----
trait CheckoutFieldsStorage {
⋮----
public function persist_field_for_order( string $key, $value, WC_Order $order, string $group = 'other', bool $set_customer = true ) {
$group = $this->prepare_group_name( $group );
$this->set_array_meta( $key, $value, $order, $group );
if ( $set_customer && $order->get_customer_id() ) {
$customer = new WC_Customer( $order->get_customer_id() );
$this->persist_field_for_customer( $key, $value, $customer, $group );
⋮----
public function persist_field_for_customer( string $key, $value, WC_Customer $customer, string $group = 'other' ) {
⋮----
$this->set_array_meta( $key, $value, $customer, $group );
⋮----
private function set_array_meta( string $key, $value, WC_Data $wc_object, string $group ) {
$meta_key = self::get_group_key( $group ) . $key;
⋮----
$wc_object->update_meta_data( $meta_key, $value );
⋮----
public function get_field_from_object( string $key, WC_Data $wc_object, string $group = 'other' ) {
$group    = $this->prepare_group_name( $group );
⋮----
$value    = $wc_object->get_meta( $meta_key, true );
⋮----
if ( $this->is_field( $key ) && 'checkbox' === $this->additional_fields[ $key ]['type'] ) {
... (35 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CheckoutLink.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services;
⋮----
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\StoreApi\Utilities\CartTokenUtils;
use Automattic\WooCommerce\StoreApi\Utilities\CartController;
⋮----
class CheckoutLink {
⋮----
public function init() {
⋮----
public function add_checkout_link_endpoint() {
⋮----
\WC_Post_Types::flush_rewrite_rules();
⋮----
public function add_query_vars( $vars ) {
⋮----
public function handle_checkout_link_endpoint() {
⋮----
if ( ! $this->validate_checkout_link() ) {
⋮----
wc()->cart->empty_cart();
$redirect = $this->get_checkout_link();
⋮----
protected function validate_checkout_link() {
$products = $this->get_products_from_checkout_link();
⋮----
protected function get_products_from_checkout_link() {
$raw_products = array_filter( explode( ',', wc_clean( wp_unslash( $_GET['products'] ?? '' ) ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
⋮----
/**
... (35 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CoreCheckoutFields.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services;
⋮----
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
⋮----
class CoreCheckoutFields {
⋮----
public static function get_keys() {
⋮----
public static function get_fields() {
⋮----
'required'       => 'required' === CartCheckoutUtils::get_company_field_visibility(),
'hidden'         => 'hidden' === CartCheckoutUtils::get_company_field_visibility(),
⋮----
'required'       => 'required' === CartCheckoutUtils::get_address_2_field_visibility(),
'hidden'         => 'hidden' === CartCheckoutUtils::get_address_2_field_visibility(),
⋮----
'required'       => 'required' === CartCheckoutUtils::get_phone_field_visibility(),
'hidden'         => 'hidden' === CartCheckoutUtils::get_phone_field_visibility(),
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/CreateAccount.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services;
⋮----
use Automattic\WooCommerce\Blocks\Domain\Package;
⋮----
class CreateAccount {
⋮----
private $package;
⋮----
public function __construct( Package $package ) {
⋮----
public function init() {
⋮----
public function customer_new_account( $customer_id = 0, array $new_customer_data = array() ) {
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/DraftOrders.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services;
⋮----
use Automattic\WooCommerce\Blocks\Domain\Package;
use Exception;
use WC_Order;
⋮----
class DraftOrders {
⋮----
private $package;
⋮----
public function __construct( Package $package ) {
⋮----
public function init() {
⋮----
public function install() {
$this->maybe_create_cronjobs();
⋮----
public function unschedule_cronjobs() {
WC()->queue()->cancel_all( self::DRAFT_CLEANUP_EVENT_HOOK );
⋮----
protected function maybe_create_cronjobs() {
⋮----
public function register_draft_order_status( array $statuses ) {
⋮----
public function register_draft_order_post_status( array $statuses ) {
$statuses[ self::DB_STATUS ] = $this->get_post_status_properties();
⋮----
private function get_post_status_properties() {
⋮----
public function delete_draft_order_post_status_from_args( $args ) {
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/FeatureGating.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services;
⋮----
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
⋮----
class FeatureGating extends DeprecatedClassFacade {
⋮----
protected static $deprecated_in_version = '9.6.0';
⋮----
public function __construct( $environment = 'unset' ) {
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/functions.php">
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
⋮----
function woocommerce_register_additional_checkout_field( $options ) {
⋮----
$checkout_fields = Package::container()->get( CheckoutFields::class );
$result          = $checkout_fields->register_checkout_field( $options );
⋮----
throw new \Exception( esc_attr( $result->get_error_message() ) );
⋮----
function __experimental_woocommerce_blocks_register_checkout_field( $options ) {
⋮----
function __internal_woocommerce_blocks_deregister_checkout_field( $field_id ) {
⋮----
$result          = $checkout_fields->deregister_checkout_field( $field_id );
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/GoogleAnalytics.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services;
⋮----
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Assets\Api as AssetApi;
⋮----
class GoogleAnalytics {
⋮----
protected $asset_api;
⋮----
public function __construct( AssetApi $asset_api ) {
⋮----
public function init() {
⋮----
public function register_assets() {
$this->asset_api->register_script( 'wc-blocks-google-analytics', 'assets/client/blocks/wc-blocks-google-analytics.js', [ 'google-tag-manager' ] );
⋮----
public function enqueue_scripts() {
$settings = $this->get_google_analytics_settings();
⋮----
private function get_google_analytics_settings() {
⋮----
public function async_script_loader_tags( $tag, $handle, $src ) {
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/Hydration.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services;
⋮----
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
use Automattic\WooCommerce\StoreApi\RoutesController;
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\StoreApi;
⋮----
class Hydration {
⋮----
protected $asset_data_registry;
⋮----
protected $cached_store_notices = null;
⋮----
protected $cached_cart_context = null;
⋮----
public function __construct( AssetDataRegistry $asset_data_registry ) {
⋮----
public function get_rest_api_response_data( $path = '' ) {
⋮----
$available_routes = StoreApi::container()->get( RoutesController::class )->get_all_routes( 'v1', true );
$route_match      = $this->match_route_to_handler( $path, $available_routes );
⋮----
$this->disable_nonce_check();
⋮----
$this->cache_store_notices();
$this->cache_cart_context();
⋮----
$response = $this->get_response_from_controller(
⋮----
'body'    => $response->get_data(),
... (44 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Services/Notices.php">
namespace Automattic\WooCommerce\Blocks\Domain\Services;
⋮----
use Automattic\WooCommerce\Blocks\Domain\Package;
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
⋮----
class Notices {
⋮----
private $package;
⋮----
private $notice_templates = array(
⋮----
public function __construct( Package $package ) {
⋮----
public function init() {
⋮----
public function add_kses_notice_allowed_tags( $allowed_tags ) {
⋮----
public function get_notices_template( $template, $template_name, $args, $template_path, $default_path ) {
⋮----
$template = $this->package->get_path( 'templates/block-' . $template_name );
⋮----
public function enqueue_notice_styles() {
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/BlockRegistrationContext.php">
namespace Automattic\WooCommerce\Blocks\Domain;
⋮----
class BlockRegistrationContext {
⋮----
public function should_register(): bool {
⋮----
return (bool) apply_filters( 'woocommerce_should_register_blocks', $this->is_rendering_request() );
⋮----
private function is_rendering_request(): bool {
⋮----
if ( wc()->is_store_api_request() ) {
⋮----
if ( $this->is_non_rendering_path_request() ) {
⋮----
if ( $this->is_woocommerce_rest_request() ) {
⋮----
if ( $this->is_woocommerce_admin_page() ) {
⋮----
private function is_woocommerce_admin_page(): bool {
⋮----
private function is_non_rendering_path_request(): bool {
⋮----
private function is_woocommerce_rest_request(): bool {
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Bootstrap.php">
namespace Automattic\WooCommerce\Blocks\Domain;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Blocks\Assets\Api as AssetApi;
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
use Automattic\WooCommerce\Blocks\AssetsController;
use Automattic\WooCommerce\Blocks\BlockPatterns;
use Automattic\WooCommerce\Blocks\BlockTemplatesRegistry;
use Automattic\WooCommerce\Blocks\BlockTemplatesController;
use Automattic\WooCommerce\Blocks\BlockTypesController;
use Automattic\WooCommerce\Blocks\CoreBreadcrumbsCompatibility;
use Automattic\WooCommerce\Blocks\DependencyDetection;
use Automattic\WooCommerce\Blocks\Patterns\PatternRegistry;
use Automattic\WooCommerce\Blocks\Patterns\PTKClient;
use Automattic\WooCommerce\Blocks\Patterns\PTKPatternsStore;
use Automattic\WooCommerce\Blocks\Domain\Services\Notices;
use Automattic\WooCommerce\Blocks\Domain\Services\DraftOrders;
use Automattic\WooCommerce\Blocks\Domain\Services\GoogleAnalytics;
use Automattic\WooCommerce\Blocks\Domain\Services\Hydration;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldsAdmin;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldsFrontend;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutLink;
use Automattic\WooCommerce\Blocks\Installer;
use Automattic\WooCommerce\Blocks\Payments\Api as PaymentsApi;
use Automattic\WooCommerce\Blocks\Payments\Integrations\BankTransfer;
use Automattic\WooCommerce\Blocks\Payments\Integrations\CashOnDelivery;
use Automattic\WooCommerce\Blocks\Payments\Integrations\Cheque;
use Automattic\WooCommerce\Blocks\Payments\Integrations\PayPal;
use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry;
... (124 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Domain/Package.php">
namespace Automattic\WooCommerce\Blocks\Domain;
⋮----
use Automattic\WooCommerce\Blocks\Options;
use Automattic\WooCommerce\Blocks\Domain\Services\FeatureGating;
⋮----
class Package {
⋮----
private $version;
⋮----
private $path;
⋮----
private $plugin_dir_url;
⋮----
private $feature_gating;
⋮----
public function __construct( $version, $plugin_path, $deprecated = null ) {
⋮----
public function get_version() {
⋮----
public function get_version_stored_on_db() {
⋮----
/**
	 * Sets the version of WooCommerce Blocks in the database.
	 * This is useful during the first installation or after the upgrade process.
	 */
public function set_version_stored_on_db() {
update_option( Options::WC_BLOCK_VERSION, $this->get_version() );
⋮----
/**
	 * Returns the path to the plugin directory.
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Images/Pexels.php">
namespace Automattic\WooCommerce\Blocks\Images;
⋮----
class Pexels {}
</file>

<file path="plugins/woocommerce/src/Blocks/Integrations/IntegrationInterface.php">
namespace Automattic\WooCommerce\Blocks\Integrations;
⋮----
interface IntegrationInterface {
⋮----
public function get_name();
⋮----
public function initialize();
⋮----
public function get_script_handles();
⋮----
public function get_editor_script_handles();
⋮----
public function get_script_data();
</file>

<file path="plugins/woocommerce/src/Blocks/Integrations/IntegrationRegistry.php">
namespace Automattic\WooCommerce\Blocks\Integrations;
⋮----
class IntegrationRegistry {
⋮----
protected $registry_identifier = '';
⋮----
/**
	 * Registered integrations, as `$name => $instance` pairs.
	 *
	 * @var IntegrationInterface[]
	 */
protected $registered_integrations = [];
⋮----
/**
	 * Initializes all registered integrations.
	 *
	 * Integration identifier is used to construct hook names and is given when the integration registry is initialized.
	 *
	 * @param string $registry_identifier Identifier for this registry.
	 */
public function initialize( $registry_identifier = '' ) {
⋮----
foreach ( $this->get_all_registered() as $registered_integration ) {
$registered_integration->initialize();
⋮----
public function register( IntegrationInterface $integration ) {
$name = $integration->get_name();
⋮----
if ( $this->is_registered( $name ) ) {
⋮----
... (27 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Patterns/AIPatterns.php">
namespace Automattic\WooCommerce\Blocks\Patterns;
⋮----
class AIPatterns {}
</file>

<file path="plugins/woocommerce/src/Blocks/Patterns/PatternRegistry.php">
namespace Automattic\WooCommerce\Blocks\Patterns;
⋮----
class PatternRegistry {
⋮----
private function get_category_labels() {
⋮----
public function register_block_pattern( $source, $pattern_data ) {
⋮----
if ( \WP_Block_Patterns_Registry::get_instance()->is_registered( $pattern_data['slug'] ) ) {
⋮----
$category_labels = $this->get_category_labels();
⋮----
$label = $category_labels[ $category_slug ] ?? self::kebab_to_capital_case( $category_slug );
⋮----
private static function kebab_to_capital_case( $value ) {
</file>

<file path="plugins/woocommerce/src/Blocks/Patterns/PTKClient.php">
namespace Automattic\WooCommerce\Blocks\Patterns;
⋮----
use WP_Error;
⋮----
class PTKClient {
⋮----
private $schema;
⋮----
public function __construct() {
⋮----
public function fetch_patterns( array $options = array() ) {
⋮----
$is_pattern_payload_valid = $this->is_valid_schema( $decoded_body );
⋮----
public function is_valid_schema( $patterns ) {
</file>

<file path="plugins/woocommerce/src/Blocks/Patterns/PTKPatternsStore.php">
namespace Automattic\WooCommerce\Blocks\Patterns;
⋮----
use WP_Upgrader;
⋮----
class PTKPatternsStore {
⋮----
private PTKClient $ptk_client;
⋮----
public function __construct( PTKClient $ptk_client ) {
⋮----
public function flush_or_fetch_patterns() {
if ( $this->allowed_tracking_is_enabled() ) {
$this->schedule_fetch_patterns();
⋮----
$this->flush_cached_patterns();
⋮----
private function schedule_fetch_patterns() {
⋮----
$this->schedule_action_if_not_pending( self::FETCH_PATTERNS_ACTION );
⋮----
public function ensure_recurring_fetch_patterns_if_enabled() {
if ( ! $this->allowed_tracking_is_enabled() ) {
⋮----
private function schedule_action_if_not_pending( $action ) {
⋮----
public function get_patterns() {
⋮----
if ( false === $patterns || ! $this->ptk_client->is_valid_schema( $patterns ) ) {
⋮----
private function filter_patterns( array $patterns ) {
... (24 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Payments/Integrations/AbstractPaymentMethodType.php">
namespace Automattic\WooCommerce\Blocks\Payments\Integrations;
⋮----
use Automattic\WooCommerce\Blocks\Payments\PaymentMethodTypeInterface;
⋮----
abstract class AbstractPaymentMethodType implements PaymentMethodTypeInterface {
⋮----
protected $name = '';
⋮----
/**
	 * Settings from the WP options table
	 *
	 * @var array
	 */
protected $settings = [];
⋮----
/**
	 * Get a setting from the settings array if set.
	 *
	 * @param string $name Setting name.
	 * @param mixed  $default Value that is returned if the setting does not exist.
	 * @return mixed
	 */
protected function get_setting( $name, $default = '' ) {
⋮----
/**
	 * Returns the name of the payment method.
	 */
public function get_name() {
⋮----
/**
... (40 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Payments/Integrations/BankTransfer.php">
namespace Automattic\WooCommerce\Blocks\Payments\Integrations;
⋮----
use Automattic\WooCommerce\Blocks\Assets\Api;
use WC_Gateway_BACS;
⋮----
final class BankTransfer extends AbstractPaymentMethodType {
⋮----
protected $name = WC_Gateway_BACS::ID;
⋮----
private $asset_api;
⋮----
public function __construct( Api $asset_api ) {
⋮----
public function initialize() {
⋮----
public function is_active() {
return filter_var( $this->get_setting( 'enabled', false ), FILTER_VALIDATE_BOOLEAN );
⋮----
public function get_payment_method_script_handles() {
$this->asset_api->register_script(
⋮----
public function get_payment_method_data() {
⋮----
'title'       => $this->get_setting( 'title' ),
'description' => $this->get_setting( 'description' ),
'supports'    => $this->get_supported_features(),
</file>

<file path="plugins/woocommerce/src/Blocks/Payments/Integrations/CashOnDelivery.php">
namespace Automattic\WooCommerce\Blocks\Payments\Integrations;
⋮----
use Automattic\WooCommerce\Blocks\Assets\Api;
use WC_Gateway_COD;
⋮----
final class CashOnDelivery extends AbstractPaymentMethodType {
⋮----
protected $name = WC_Gateway_COD::ID;
⋮----
private $asset_api;
⋮----
public function __construct( Api $asset_api ) {
⋮----
public function initialize() {
⋮----
public function is_active() {
return filter_var( $this->get_setting( 'enabled', false ), FILTER_VALIDATE_BOOLEAN );
⋮----
private function get_enable_for_virtual() {
return filter_var( $this->get_setting( 'enable_for_virtual', false ), FILTER_VALIDATE_BOOLEAN );
⋮----
private function get_enable_for_methods() {
$enable_for_methods = $this->get_setting( 'enable_for_methods', [] );
⋮----
/**
	 * Returns an array of scripts/handles to be registered for this payment method.
	 *
	 * @return array
	 */
public function get_payment_method_script_handles() {
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Payments/Integrations/Cheque.php">
namespace Automattic\WooCommerce\Blocks\Payments\Integrations;
⋮----
use Exception;
use Automattic\WooCommerce\Blocks\Assets\Api;
use WC_Gateway_Cheque;
⋮----
final class Cheque extends AbstractPaymentMethodType {
⋮----
protected $name = WC_Gateway_Cheque::ID;
⋮----
private $asset_api;
⋮----
public function __construct( Api $asset_api ) {
⋮----
public function initialize() {
⋮----
public function is_active() {
return filter_var( $this->get_setting( 'enabled', false ), FILTER_VALIDATE_BOOLEAN );
⋮----
public function get_payment_method_script_handles() {
$this->asset_api->register_script(
⋮----
public function get_payment_method_data() {
⋮----
'title'       => $this->get_setting( 'title' ),
'description' => $this->get_setting( 'description' ),
'supports'    => $this->get_supported_features(),
</file>

<file path="plugins/woocommerce/src/Blocks/Payments/Integrations/PayPal.php">
namespace Automattic\WooCommerce\Blocks\Payments\Integrations;
⋮----
use WC_Gateway_Paypal;
use Automattic\WooCommerce\Blocks\Assets\Api;
use Automattic\WooCommerce\Gateways\PayPal\Buttons as PayPalButtons;
⋮----
final class PayPal extends AbstractPaymentMethodType {
⋮----
protected $name = WC_Gateway_Paypal::ID;
⋮----
private $asset_api;
⋮----
public function __construct( Api $asset_api ) {
⋮----
public function initialize() {
⋮----
public function is_active() {
return filter_var( $this->get_setting( 'enabled', false ), FILTER_VALIDATE_BOOLEAN );
⋮----
public function get_payment_method_script_handles() {
$this->asset_api->register_script(
⋮----
public function get_payment_method_data() {
$gateway = WC_Gateway_Paypal::get_instance();
⋮----
if ( ! $gateway->is_available() ) {
⋮----
$options = $buttons->get_options();
⋮----
'title'                  => $this->get_setting( 'title' ),
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Payments/Api.php">
namespace Automattic\WooCommerce\Blocks\Payments;
⋮----
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Payments\Integrations\BankTransfer;
use Automattic\WooCommerce\Blocks\Payments\Integrations\CashOnDelivery;
use Automattic\WooCommerce\Blocks\Payments\Integrations\Cheque;
use Automattic\WooCommerce\Blocks\Payments\Integrations\PayPal;
use Automattic\WooCommerce\Internal\Features\BlockEditorUnifiedAssets;
⋮----
class Api {
⋮----
private $payment_method_registry;
⋮----
private $asset_registry;
⋮----
public function __construct( PaymentMethodRegistry $payment_method_registry, AssetDataRegistry $asset_registry ) {
⋮----
public function init() {
⋮----
public function add_payment_method_script_dependencies( $dependencies, $handle ) {
if ( ! in_array( $handle, $this->get_cart_checkout_script_handles(), true ) ) {
⋮----
$this->payment_method_registry->get_all_active_payment_method_script_dependencies()
⋮----
private function get_cart_checkout_script_handles(): array {
$editor_handles = BlockEditorUnifiedAssets::is_enabled()
⋮----
private function is_payment_gateway_enabled( $gateway ) {
⋮----
... (29 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Payments/PaymentMethodRegistry.php">
namespace Automattic\WooCommerce\Blocks\Payments;
⋮----
use Automattic\WooCommerce\Blocks\Integrations\IntegrationRegistry;
⋮----
final class PaymentMethodRegistry extends IntegrationRegistry {
⋮----
protected $registry_identifier = 'payment_method_type';
⋮----
public function get_all_active_registered() {
⋮----
$this->get_all_registered(),
⋮----
return $payment_method->is_active();
⋮----
public function get_all_active_payment_method_script_dependencies() {
⋮----
$payment_methods = $this->get_all_active_registered();
⋮----
is_admin() ? $payment_method->get_payment_method_script_handles_for_admin() : $payment_method->get_payment_method_script_handles()
⋮----
public function get_all_registered_script_data() {
⋮----
$script_data[ $payment_method->get_name() ] = $payment_method->get_payment_method_data();
</file>

<file path="plugins/woocommerce/src/Blocks/Payments/PaymentMethodTypeInterface.php">
namespace Automattic\WooCommerce\Blocks\Payments;
⋮----
use Automattic\WooCommerce\Blocks\Integrations\IntegrationInterface;
⋮----
interface PaymentMethodTypeInterface extends IntegrationInterface {
⋮----
public function is_active();
⋮----
public function get_payment_method_script_handles();
⋮----
public function get_payment_method_script_handles_for_admin();
⋮----
public function get_payment_method_data();
⋮----
public function get_supported_features();
</file>

<file path="plugins/woocommerce/src/Blocks/Registry/AbstractDependencyType.php">
namespace Automattic\WooCommerce\Blocks\Registry;
⋮----
abstract class AbstractDependencyType {
⋮----
private $callable_or_value;
⋮----
public function __construct( $callable_or_value ) {
⋮----
protected function resolve_value( Container $container ) {
⋮----
return \is_callable( $callback )
? $callback( $container )
⋮----
abstract public function get( Container $container );
</file>

<file path="plugins/woocommerce/src/Blocks/Registry/Container.php">
namespace Automattic\WooCommerce\Blocks\Registry;
⋮----
use Closure;
use Exception;
⋮----
class Container {
⋮----
private $registry = [];
⋮----
public function factory( Closure $instantiation_callback ) {
⋮----
public function register( $id, $value ) {
⋮----
public function get( $id ) {
⋮----
return $this->registry[ $id ]->get( $this );
</file>

<file path="plugins/woocommerce/src/Blocks/Registry/FactoryType.php">
namespace Automattic\WooCommerce\Blocks\Registry;
⋮----
class FactoryType extends AbstractDependencyType {
⋮----
public function get( Container $container ) {
return $this->resolve_value( $container );
</file>

<file path="plugins/woocommerce/src/Blocks/Registry/SharedType.php">
namespace Automattic\WooCommerce\Blocks\Registry;
⋮----
class SharedType extends AbstractDependencyType {
⋮----
private $shared_instance;
⋮----
public function get( Container $container ) {
⋮----
$this->shared_instance = $this->resolve_value( $container );
</file>

<file path="plugins/woocommerce/src/Blocks/SharedStores/ProductsStore.php">
namespace Automattic\WooCommerce\Blocks\SharedStores;
⋮----
use Automattic\WooCommerce\Blocks\Domain\Services\Hydration;
use Automattic\WooCommerce\Blocks\Package;
use InvalidArgumentException;
⋮----
class ProductsStore {
⋮----
private static string $consent_statement = 'I acknowledge that using experimental APIs means my theme or plugin will inevitably break in the next version of WooCommerce';
⋮----
private static string $store_namespace = 'woocommerce/products';
⋮----
private static array $products = array();
⋮----
private static array $product_variations = array();
⋮----
private static array $loaded_variation_parents = array();
⋮----
private static bool $getters_registered = false;
⋮----
private static function check_consent( string $consent_statement ): bool {
⋮----
private static function register_getters(): void {
⋮----
public static function load_product( string $consent_statement, int $product_id ): array {
self::check_consent( $consent_statement );
⋮----
$response = Package::container()->get( Hydration::class )->get_rest_api_response_data( '/wc/store/v1/products/' . $product_id );
⋮----
self::register_getters();
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Shipping/PickupLocation.php">
namespace Automattic\WooCommerce\Blocks\Shipping;
⋮----
use WC_Shipping_Method;
⋮----
class PickupLocation extends WC_Shipping_Method {
⋮----
protected $pickup_locations = [];
⋮----
protected $cost = '';
⋮----
/**
	 * Constructor.
	 */
public function __construct() {
parent::__construct();
⋮----
$this->init();
⋮----
public function init() {
$this->enabled          = $this->get_option( 'enabled' );
$this->title            = $this->get_option( 'title', __( 'Pickup', 'woocommerce' ) );
$this->tax_status       = $this->get_option( 'tax_status' );
$this->cost             = $this->get_option( 'cost' );
⋮----
protected function has_valid_pickup_location( $address ) {
⋮----
// Country is always required.
⋮----
$country_address_fields = wc()->countries->get_address_fields( $address_fields['country'], 'shipping_' );
⋮----
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Shipping/PickupLocationsRestController.php">
namespace Automattic\WooCommerce\Blocks\Shipping;
⋮----
class PickupLocationsRestController extends \WP_REST_Controller {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'pickup-locations';
⋮----
public function register_routes() {
⋮----
public function update_settings_permissions_check( $request ) {
⋮----
return new \WP_Error(
⋮----
public function update_settings( $request ) {
$settings  = $request->get_param( 'pickup_location_settings' );
$locations = $request->get_param( 'pickup_locations' );
⋮----
$settings = $this->sanitize_pickup_location_settings( $settings );
⋮----
$locations = $this->sanitize_pickup_locations( $locations );
⋮----
$this->record_save_event( $settings, $locations );
⋮----
private function record_save_event( array $settings, array $locations ): void {
⋮----
\WC_Tracks::record_event(
⋮----
private function sanitize_pickup_location_settings( array $settings ): array {
⋮----
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Shipping/ShippingController.php">
namespace Automattic\WooCommerce\Blocks\Shipping;
⋮----
use Automattic\WooCommerce\Blocks\Assets\Api as AssetApi;
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
use Automattic\WooCommerce\Blocks\Utils\CartCheckoutUtils;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
use Automattic\WooCommerce\StoreApi\Utilities\LocalPickupUtils;
use Automattic\WooCommerce\Utilities\ArrayUtil;
use WC_Customer;
use WC_Shipping_Rate;
⋮----
class ShippingController {
⋮----
protected $asset_api;
⋮----
protected $asset_data_registry;
⋮----
private $local_pickup_enabled;
⋮----
public function __construct( AssetApi $asset_api, AssetDataRegistry $asset_data_registry ) {
⋮----
$this->local_pickup_enabled = LocalPickupUtils::is_local_pickup_enabled();
⋮----
public function init() {
⋮----
$this->asset_data_registry->add(
⋮----
return WC()->countries->get_states();
⋮----
... (110 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/AbstractPageTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
abstract class AbstractPageTemplate extends AbstractTemplate {
⋮----
public function init() {
⋮----
abstract protected function get_placeholder_page();
⋮----
abstract protected function is_active_template();
⋮----
public function page_template_hierarchy( $templates ) {
if ( $this->is_active_template() ) {
⋮----
public function page_template_title( $title ) {
if ( $this->is_active_template() && $this->get_template_title() ) {
return $this->get_template_title();
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/AbstractTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
abstract class AbstractTemplate {
⋮----
public bool $is_taxonomy_template = false;
⋮----
abstract public function init();
⋮----
abstract public function get_template_title();
⋮----
abstract public function get_template_description();
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/AbstractTemplateCompatibility.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
⋮----
abstract class AbstractTemplateCompatibility {
⋮----
protected $hook_data;
⋮----
public function init() {
$this->set_hook_data();
⋮----
$this->set_compatibility_layer_flag();
⋮----
return $this->update_render_block_data( $parsed_block, $source_block, $parent_block );
⋮----
return $this->inject_hooks( $block_content, $block );
⋮----
abstract public function update_render_block_data( $parsed_block, $source_block, $parent_block );
⋮----
abstract public function inject_hooks( $block_content, $block );
⋮----
abstract protected function set_hook_data();
⋮----
protected function remove_default_hooks() {
⋮----
/**
		 * When extensions implement their equivalent blocks of the template
		 * hook functions, they can use this filter to register their old hooked
		 * data here, so in the blockified template, the old hooked functions
		 * can be removed in favor of the new blocks while keeping the old
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/AbstractTemplatePart.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
abstract class AbstractTemplatePart extends AbstractTemplate {
⋮----
public $template_area;
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/AbstractTemplateWithFallback.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
⋮----
abstract class AbstractTemplateWithFallback extends AbstractTemplate {
⋮----
public string $fallback_template;
⋮----
public function init() {
⋮----
public function template_hierarchy( $templates ) {
⋮----
abstract public function render_block_template();
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/ArchiveProductTemplatesCompatibility.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
class ArchiveProductTemplatesCompatibility extends AbstractTemplateCompatibility {
⋮----
protected $hook_data;
⋮----
public function update_render_block_data( $parsed_block, $source_block, $parent_block ) {
⋮----
if ( ! $this->is_archive_template() ) {
⋮----
$this->inner_blocks_walker( $parsed_block );
⋮----
public function inject_hooks( $block_content, $block ) {
⋮----
if ( $this->is_null_post_template( $block ) ) {
⋮----
if ( $this->is_post_or_product_template( $block_name ) && ! empty( $block_content ) ) {
$this->restore_default_hooks();
⋮----
$this->get_hooks_buffer( $block_hooks, 'before' ),
⋮----
$this->get_hooks_buffer( $block_hooks, 'after' )
⋮----
$this->remove_default_hooks();
⋮----
protected function set_hook_data() {
⋮----
private function is_archive_template() {
⋮----
private function inner_blocks_walker( &$block ) {
... (28 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/CartTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
class CartTemplate extends AbstractPageTemplate {
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
⋮----
protected function get_placeholder_page() {
⋮----
protected function is_active_template() {
⋮----
$placeholder = $this->get_placeholder_page();
⋮----
public function page_template_hierarchy( $templates ) {
if ( $this->is_active_template() ) {
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/CheckoutHeaderTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
class CheckoutHeaderTemplate extends AbstractTemplatePart {
⋮----
public $template_area = 'header';
⋮----
public function init() {}
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/CheckoutTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
class CheckoutTemplate extends AbstractPageTemplate {
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
⋮----
protected function get_placeholder_page() {
⋮----
protected function is_active_template() {
⋮----
$placeholder = $this->get_placeholder_page();
⋮----
public function page_template_hierarchy( $templates ) {
if ( $this->is_active_template() ) {
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/ClassicTemplatesCompatibility.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
⋮----
class ClassicTemplatesCompatibility {
⋮----
protected $asset_data_registry;
⋮----
public function __construct( AssetDataRegistry $asset_data_registry ) {
⋮----
$this->init();
⋮----
protected function init() {
⋮----
public function set_classic_template_data() {
$this->set_filterable_product_data();
$this->set_php_template_data();
⋮----
public function set_filterable_product_data() {
⋮----
$this->asset_data_registry->add( 'hasFilterableProducts', true );
⋮----
public function set_php_template_data() {
⋮----
$this->asset_data_registry->add( 'isRenderingPhpTemplate', true );
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/ComingSoonSocialLinksTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
class ComingSoonSocialLinksTemplate extends AbstractTemplatePart {
⋮----
public $template_area = 'uncategorized';
⋮----
public function init() {}
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
⋮----
protected function get_placeholder_page() {
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/ComingSoonTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
class ComingSoonTemplate extends AbstractPageTemplate {
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
⋮----
protected function get_placeholder_page() {
⋮----
protected function is_active_template() {
⋮----
public static function get_font_families() {
⋮----
$current_theme = wp_get_theme()->get_stylesheet();
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/ExternalProductAddToCartWithOptionsTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
class ExternalProductAddToCartWithOptionsTemplate extends AbstractTemplatePart {
⋮----
public $template_area = 'add-to-cart-with-options';
⋮----
public function init() {
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/GroupedProductAddToCartWithOptionsTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
class GroupedProductAddToCartWithOptionsTemplate extends AbstractTemplatePart {
⋮----
public $template_area = 'add-to-cart-with-options';
⋮----
public function init() {
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/MiniCartTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
class MiniCartTemplate extends AbstractTemplatePart {
⋮----
public $template_area = 'mini-cart';
⋮----
public function init() {
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
⋮----
public function register_mini_cart_template_part_area( $default_area_definitions ) {
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/OrderConfirmationTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
class OrderConfirmationTemplate extends AbstractPageTemplate {
⋮----
public function init() {
⋮----
parent::init();
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
⋮----
public function remove_edit_page_link() {
if ( $this->is_active_template() ) {
⋮----
$wp_admin_bar->remove_menu( 'edit' );
⋮----
protected function get_placeholder_page() {
⋮----
protected function is_active_template() {
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/ProductAttributeTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
use Automattic\WooCommerce\Blocks\Templates\ArchiveProductTemplatesCompatibility;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
⋮----
class ProductAttributeTemplate extends AbstractTemplateWithFallback {
⋮----
public string $fallback_template = ProductCatalogTemplate::SLUG;
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
⋮----
public function render_block_template() {
⋮----
$compatibility_layer->init();
⋮----
public function template_hierarchy( $templates ) {
⋮----
BlockTemplateUtils::theme_has_template( self::SLUG ) ||
BlockTemplateUtils::get_block_templates_from_db( array( self::SLUG ) )
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/ProductBrandTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
use Automattic\WooCommerce\Blocks\Templates\ArchiveProductTemplatesCompatibility;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
⋮----
class ProductBrandTemplate extends AbstractTemplateWithFallback {
⋮----
public string $fallback_template = ProductCatalogTemplate::SLUG;
⋮----
public bool $is_taxonomy_template = true;
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
⋮----
public function render_block_template() {
⋮----
$compatibility_layer->init();
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/ProductCatalogTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
use Automattic\WooCommerce\Blocks\Templates\ArchiveProductTemplatesCompatibility;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
⋮----
class ProductCatalogTemplate extends AbstractTemplate {
⋮----
public function init() {
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
⋮----
public function render_block_template() {
⋮----
$compatibility_layer->init();
⋮----
public function remove_block_template_support_for_shop_page( $is_support ) {
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/ProductCategoryTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
use Automattic\WooCommerce\Blocks\Templates\ArchiveProductTemplatesCompatibility;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
⋮----
class ProductCategoryTemplate extends AbstractTemplateWithFallback {
⋮----
public string $fallback_template = ProductCatalogTemplate::SLUG;
⋮----
public bool $is_taxonomy_template = true;
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
⋮----
public function render_block_template() {
⋮----
$compatibility_layer->init();
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/ProductSearchResultsTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
use Automattic\WooCommerce\Blocks\Templates\ArchiveProductTemplatesCompatibility;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
⋮----
class ProductSearchResultsTemplate extends AbstractTemplate {
⋮----
public function init() {
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
⋮----
public function render_block_template() {
⋮----
$compatibility_layer->init();
⋮----
public function update_search_template_hierarchy( $templates ) {
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/ProductTagTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
use Automattic\WooCommerce\Blocks\Templates\ArchiveProductTemplatesCompatibility;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
⋮----
class ProductTagTemplate extends AbstractTemplateWithFallback {
⋮----
public string $fallback_template = ProductCatalogTemplate::SLUG;
⋮----
public bool $is_taxonomy_template = true;
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
⋮----
public function render_block_template() {
⋮----
$compatibility_layer->init();
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/SimpleProductAddToCartWithOptionsTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
class SimpleProductAddToCartWithOptionsTemplate extends AbstractTemplatePart {
⋮----
public $template_area = 'add-to-cart-with-options';
⋮----
public function init() {
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/SingleProductTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
use Automattic\WooCommerce\Blocks\SharedStores\ProductsStore;
use Automattic\WooCommerce\Blocks\Templates\SingleProductTemplateCompatibility;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
⋮----
class SingleProductTemplate extends AbstractTemplate {
⋮----
public function init() {
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
⋮----
public function render_block_template() {
⋮----
$compatibility_layer->init();
⋮----
ProductsStore::load_product( $consent, $product->get_id() );
⋮----
'productId'   => $product->get_id(),
⋮----
public function update_single_product_content( $query_result ) {
⋮----
if ( ( ! is_admin() && ! ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) && ! BlockTemplateUtils::template_has_legacy_template_block( $template ) ) {
⋮----
$template->content = $this->add_password_form( $template->content );
⋮----
$template->content = SingleProductTemplateCompatibility::add_compatibility_layer( $template->content );
⋮----
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/SingleProductTemplateCompatibility.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
⋮----
class SingleProductTemplateCompatibility extends AbstractTemplateCompatibility {
⋮----
public function inject_hooks( $block_content, $block ) {
⋮----
$this->remove_default_hooks();
⋮----
$first_or_last_block_content = $this->inject_hook_to_first_and_last_blocks( $block_content, $block, $block_hooks );
⋮----
$this->get_hooks_buffer( $block_hooks, 'before' ),
⋮----
$this->get_hooks_buffer( $block_hooks, 'after' )
⋮----
private function inject_hook_to_first_and_last_blocks( $block_content, $block, $block_hooks ) {
⋮----
$this->inject_hooks_after_the_wrapper(
⋮----
$this->get_hooks_buffer(
⋮----
public function update_render_block_data( $parsed_block, $source_block, $parent_block ) {
⋮----
protected function set_hook_data() {
⋮----
public static function add_compatibility_layer( $template_content ) {
⋮----
if ( self::has_single_product_template_blocks( $blocks ) ) {
$blocks = self::wrap_single_product_template( $template_content );
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Templates/VariableProductAddToCartWithOptionsTemplate.php">
namespace Automattic\WooCommerce\Blocks\Templates;
⋮----
class VariableProductAddToCartWithOptionsTemplate extends AbstractTemplatePart {
⋮----
public $template_area = 'add-to-cart-with-options';
⋮----
public function init() {
⋮----
public function get_template_title() {
⋮----
public function get_template_description() {
</file>

<file path="plugins/woocommerce/src/Blocks/Utils/BlockHooksTrait.php">
namespace Automattic\WooCommerce\Blocks\Utils;
⋮----
trait BlockHooksTrait {
⋮----
public function register_hooked_block( $hooked_blocks, $position, $anchor_block, $context ) {
⋮----
! $this->has_block_in_content( $context )
&& $this->is_target_area( $context, $placement['area'] )
⋮----
$modified_hooked_blocks = $callback( $hooked_blocks, $position, $anchor_block, $context );
⋮----
protected function has_block_in_content( $context ) {
$content = $this->get_context_content( $context );
⋮----
protected function get_context_content( $context ) {
⋮----
/**
	 * Given a provided context, returns whether the context refers to header content.
	 *
	 * @param array|\WP_Post|\WP_Block_Template $context Where the block is embedded.
	 * @param string                            $area The area to check against before inserting.
	 * @since 8.5.0
	 * @return boolean
	 */
protected function is_template_part_or_pattern( $context, $area ) {
⋮----
protected function is_target_area( $context, $area ) {
if ( $this->is_template_part_or_pattern( $context, $area ) && ! $this->pattern_is_excluded( $context ) ) {
⋮----
protected function pattern_is_excluded( $context ) {
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Utils/BlocksSharedState.php">
namespace Automattic\WooCommerce\Blocks\Utils;
⋮----
use InvalidArgumentException;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\Hydration;
use Automattic\WooCommerce\Internal\Utilities\PriceSeparators;
⋮----
class BlocksSharedState {
⋮----
private static string $consent_statement = 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WooCommerce';
⋮----
private static string $settings_namespace = 'woocommerce';
⋮----
private static bool $core_config_registered = false;
⋮----
private static ?array $blocks_shared_cart_state = null;
⋮----
private static function prevent_cache(): void {
\WC_Cache_Helper::set_nocache_constants();
⋮----
private static function check_consent( string $consent_statement ): bool {
⋮----
public static function load_store_config( string $consent_statement ): void {
self::check_consent( $consent_statement );
⋮----
wp_interactivity_config( self::$settings_namespace, self::get_currency_data() );
wp_interactivity_config( self::$settings_namespace, self::get_locale_data() );
⋮----
public static function load_cart_state( string $consent_statement ): void {
⋮----
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Utils/BlocksWpQuery.php">
namespace Automattic\WooCommerce\Blocks\Utils;
⋮----
use WP_Query;
⋮----
class BlocksWpQuery extends WP_Query {
⋮----
public function __construct( $query = '' ) {
⋮----
$this->init();
⋮----
$this->parse_query_vars();
⋮----
/**
	 * Get cached posts, if a cache exists.
	 *
	 * A hash is generated using the array of query_vars. If doing custom queries via filters such as posts_where
	 * (where the SQL query is manipulated directly) you can still ensure there is a unique hash by injecting custom
	 * query vars via the parse_query filter. For example:
	 *
	 *      add_filter( 'parse_query', function( $wp_query ) {
	 *           $wp_query->query_vars['my_custom_query_var'] = true;
	 *      } );
	 *
	 * Doing so won't have any negative effect on the query itself, and it will cause the hash to change.
	 *
	 * @param string $transient_version Transient version to allow for invalidation.
	 * @return WP_Post[]|int[] Array of post objects or post IDs.
	 */
public function get_cached_posts( $transient_version = '' ) {
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Utils/BlockTemplateUtils.php">
namespace Automattic\WooCommerce\Blocks\Utils;
⋮----
use WP_Block_Patterns_Registry;
use Automattic\WooCommerce\Blocks\Options;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\BlockTemplatesRegistry;
use Automattic\WooCommerce\Blocks\Templates\ProductCatalogTemplate;
⋮----
class BlockTemplateUtils {
⋮----
public static function get_template( $template_slug ) {
$block_templates_registry = Package::container()->get( BlockTemplatesRegistry::class );
return $block_templates_registry->get_template( $template_slug );
⋮----
public static function flatten_blocks( &$blocks ) {
⋮----
public static function inject_theme_attribute_in_content( $template_content ) {
⋮----
$blocks = self::flatten_blocks( $template_blocks );
⋮----
$block['attrs']['theme'] = wp_get_theme()->get_stylesheet();
⋮----
public static function build_template_result_from_post( $post ) {
⋮----
return new \WP_Error( 'template_missing_theme', __( 'No theme is defined for this template.', 'woocommerce' ) );
⋮----
$template                 = new \WP_Block_Template();
⋮----
public static function build_template_result_from_file( $template_file, $template_type ) {
⋮----
... (98 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Utils/CartCheckoutUtils.php">
namespace Automattic\WooCommerce\Blocks\Utils;
⋮----
use Automattic\Block_Scanner;
⋮----
class CartCheckoutUtils {
⋮----
private static $is_cart_page = null;
⋮----
private static $is_checkout_page = null;
⋮----
private static function is_page_type( string $page_type ): ?bool {
⋮----
return wc_post_content_has_shortcode( 'cart' === $page_type ? 'woocommerce_cart' : 'woocommerce_checkout' ) || self::has_block_variation( 'woocommerce/classic-shortcode', 'shortcode', $page_type, $post->post_content );
⋮----
public static function is_cart_page(): bool {
⋮----
self::$is_cart_page = self::is_page_type( 'cart' );
⋮----
public static function is_checkout_page(): bool {
⋮----
self::$is_checkout_page = self::is_page_type( 'checkout' );
⋮----
public static function shipping_methods_exist() {
⋮----
WC()->shipping()->get_shipping_methods(),
⋮----
return isset( $method->enabled ) && 'yes' === $method->enabled && ! $method->supports( 'shipping-zones' ) && $method->supports( 'local-pickup' );
⋮----
public static function has_block_variation( $block_id, $attribute, $value, $post_content ) {
⋮----
... (70 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Utils/MiniCartUtils.php">
namespace Automattic\WooCommerce\Blocks\Utils;
⋮----
class MiniCartUtils {
⋮----
public static function migrate_attributes_to_color_panel( $attributes ) {
⋮----
public static function get_svg_icon( $icon_name, $icon_color = 'currentColor' ) {
</file>

<file path="plugins/woocommerce/src/Blocks/Utils/ProductAvailabilityUtils.php">
namespace Automattic\WooCommerce\Blocks\Utils;
⋮----
use Automattic\WooCommerce\Blocks\Templates\ProductStockIndicator;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class ProductAvailabilityUtils {
⋮----
public static function get_product_availability( $product ) {
⋮----
$product_availability = $product->get_availability();
⋮----
// If the product is a variable product, make sure at least one of its
// variations is purchasable.
⋮----
ProductType::VARIABLE === $product->get_type()
⋮----
if ( ! $product->has_purchasable_variations() ) {
</file>

<file path="plugins/woocommerce/src/Blocks/Utils/ProductDataUtils.php">
namespace Automattic\WooCommerce\Blocks\Utils;
⋮----
class ProductDataUtils {
⋮----
public static function get_product_data( \WC_Product $product ) {
⋮----
'price_html' => $product->get_price_html(),
</file>

<file path="plugins/woocommerce/src/Blocks/Utils/ProductDescriptionUtils.php">
namespace Automattic\WooCommerce\Blocks\Utils;
⋮----
class ProductDescriptionUtils {
⋮----
private static array $formatting_product_descriptions = array();
⋮----
private static function is_description_accessible( \WC_Product $product ): bool {
if ( post_password_required( $product->get_id() ) ) {
⋮----
$parent_id = $product->get_parent_id();
⋮----
public static function guarded_format( \WC_Product $product, callable $format_callback ): string {
$product_id = $product->get_id();
⋮----
if ( ! self::is_description_accessible( $product ) || isset( self::$formatting_product_descriptions[ $product_id ] ) ) {
⋮----
$result = $format_callback();
</file>

<file path="plugins/woocommerce/src/Blocks/Utils/ProductGalleryUtils.php">
namespace Automattic\WooCommerce\Blocks\Utils;
⋮----
use Automattic\WooCommerce\Internal\ProductGallery\ProductMediaGallery;
⋮----
class ProductGalleryUtils {
⋮----
public static function get_all_image_ids( $product ) {
⋮----
$gallery_image_ids           = self::get_product_gallery_image_ids( $product );
$product_variation_image_ids = self::get_product_variation_image_ids( $product );
⋮----
public static function get_product_gallery_image_data( $product, $size ) {
$all_image_ids = self::get_all_image_ids( $product );
return self::get_image_src_data( $all_image_ids, $size, $product->get_title() );
⋮----
public static function get_product_gallery_image_count( $product ) {
⋮----
return self::get_product_gallery_media_count( $product );
⋮----
public static function get_all_media_items( $product ) {
⋮----
$product_media_items         = ProductMediaGallery::get_product_media_gallery_items_for_display( $product );
⋮----
if ( $is_placeholder_only && ! empty( $product->get_gallery_image_ids() ) ) {
$product_media_items = self::get_product_gallery_image_items( $product );
⋮----
$existing_ids = array_map( 'strval', self::get_media_ids( $product_media_items ) );
⋮----
public static function get_media_ids( $media_items ) {
⋮----
... (92 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Utils/StyleAttributesUtils.php">
namespace Automattic\WooCommerce\Blocks\Utils;
⋮----
class StyleAttributesUtils {
⋮----
/**
	 * If color value is in preset format, convert it to a CSS var. Else return same value
	 * For example:
	 * "var:preset|color|pale-pink" -> "var(--wp--preset--color--pale-pink)"
	 * "#98b66e" -> "#98b66e"
	 *
	 * @param string $color_value value to be processed.
	 *
	 * @return (string)
	 */
public static function get_color_value( $color_value ) {
⋮----
/**
	 * Get CSS value for color preset.
	 *
	 * @param string $preset_name Preset name.
	 *
	 * @return string CSS value for color preset.
	 */
public static function get_preset_value( $preset_name ) {
⋮----
/**
	 * Get CSS value for shadow preset. Returns the same value if it's not a preset.
	 *
	 * @param string $shadow_name Shadow name.
	 *
... (105 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Utils/Utils.php">
namespace Automattic\WooCommerce\Blocks\Utils;
⋮----
use Automattic\WooCommerce\Proxies\LegacyProxy;
⋮----
class Utils {
⋮----
public static function wp_version_compare( $version, $operator = null ) {
⋮----
public static function get_absolute_script_url( $src ) {
$wp_scripts = wc_get_container()->get( LegacyProxy::class )->call_function( 'wp_scripts' );
⋮----
public static function get_current_page_url() {
⋮----
// PATHINFO permalinks keep index.php in the public URL; $wp->request does not.
⋮----
$wp_rewrite->using_index_permalinks()
</file>

<file path="plugins/woocommerce/src/Blocks/Assets.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Assets\Api as AssetApi;
⋮----
class Assets {
⋮----
public static function init() {
⋮----
public static function register_assets() {
⋮----
public static function enqueue_scripts() {
⋮----
public static function add_theme_body_class( $classes = [] ) {
⋮----
public static function add_theme_admin_body_class( $classes = '' ) {
⋮----
public static function redirect_to_field() {
⋮----
public static function register_block_script( $script_name, $handle = '', $dependencies = [] ) {
⋮----
$asset_api = Package::container()->get( AssetApi::class );
$asset_api->register_block_script( $script_name, $handle, $dependencies );
</file>

<file path="plugins/woocommerce/src/Blocks/AssetsController.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Blocks\Assets\Api as AssetApi;
use Automattic\WooCommerce\Blocks\Utils\Utils;
use Automattic\WooCommerce\Internal\Features\BlockEditorUnifiedAssets;
⋮----
final class AssetsController {
⋮----
private $api;
⋮----
public function __construct( AssetApi $asset_api ) {
⋮----
$this->init();
⋮----
protected function init() {
⋮----
public function register_script_modules() {
⋮----
$asset_data = $this->api->get_asset_data(
$this->api->get_block_asset_build_path( 'interactivity-blocks-frontend-assets', 'php' )
⋮----
wp_register_script_module( $handle_without_js, plugins_url( $this->api->get_block_asset_build_path( $handle_without_js ), dirname( __DIR__ ) ), $data['dependencies'], $data['version'] );
⋮----
public function register_assets() {
$this->register_style( 'wc-blocks-packages-style', plugins_url( $this->api->get_block_asset_build_path( 'packages-style', 'css' ), dirname( __DIR__ ) ), array(), 'all', true );
$this->register_style( 'wc-blocks-style', plugins_url( $this->api->get_block_asset_build_path( 'wc-blocks', 'css' ), dirname( __DIR__ ) ), array(), 'all', true );
$this->register_style( 'wc-blocks-editor-style', plugins_url( $this->api->get_block_asset_build_path( 'wc-blocks-editor-style', 'css' ), dirname( __DIR__ ) ), array( 'wp-edit-blocks' ), 'all', true );
if ( BlockEditorUnifiedAssets::is_enabled() ) {
$this->register_style( 'wc-block-library-style', plugins_url( $this->api->get_block_asset_build_path( 'wc-block-library-style', 'css' ), dirname( __DIR__ ) ), array( 'wp-edit-blocks' ), 'all', true );
... (114 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockPatterns.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
use Automattic\WooCommerce\Blocks\Domain\Package;
use Automattic\WooCommerce\Blocks\Patterns\PatternRegistry;
use Automattic\WooCommerce\Blocks\Patterns\PTKPatternsStore;
⋮----
class BlockPatterns {
⋮----
private string $patterns_path;
⋮----
private PatternRegistry $pattern_registry;
⋮----
private PTKPatternsStore $ptk_patterns_store;
⋮----
public function __construct(
⋮----
$this->patterns_path      = $package->get_path( 'patterns' );
⋮----
public function register_block_patterns() {
⋮----
$patterns = $this->get_block_patterns();
⋮----
$this->pattern_registry->register_block_pattern( $pattern_path, $pattern );
⋮----
private function get_block_patterns() {
$pattern_data = $this->get_pattern_cache();
⋮----
$this->set_pattern_cache( $patterns );
⋮----
/**
... (20 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTemplatesController.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
use Automattic\WooCommerce\Blocks\Templates\ComingSoonTemplate;
use Automattic\WooCommerce\Blocks\Utils\Utils;
⋮----
class BlockTemplatesController {
⋮----
public function init() {
⋮----
if ( Utils::wp_version_compare( '6.8', '<=' ) ) {
⋮----
public function dequeue_legacy_scripts() {
⋮----
public function render_woocommerce_template_part( $attributes ) {
⋮----
return function_exists( '\gutenberg_render_block_core_template_part' ) ? \gutenberg_render_block_core_template_part( $attributes ) : \render_block_core_template_part( $attributes );
⋮----
public function add_plugin_templates_parts_support( $settings, $metadata ) {
⋮----
public function prevent_shortcodes_html_breakage( $settings, $metadata ) {
⋮----
return $render_callback( $attributes, $content );
⋮----
public function hide_template_selector_in_cart_checkout_pages() {
⋮----
public function get_block_file_template( $template, $id, $template_type ) {
⋮----
if ( ! $this->block_template_is_available( $template_slug, $template_type ) ) {
⋮----
... (47 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTemplatesRegistry.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;
use Automattic\WooCommerce\Blocks\Templates\AbstractTemplate;
use Automattic\WooCommerce\Blocks\Templates\AbstractTemplatePart;
use Automattic\WooCommerce\Blocks\Templates\MiniCartTemplate;
use Automattic\WooCommerce\Blocks\Templates\CartTemplate;
use Automattic\WooCommerce\Blocks\Templates\CheckoutTemplate;
use Automattic\WooCommerce\Blocks\Templates\CheckoutHeaderTemplate;
use Automattic\WooCommerce\Blocks\Templates\ComingSoonTemplate;
use Automattic\WooCommerce\Blocks\Templates\OrderConfirmationTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductAttributeTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductBrandTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductCatalogTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductCategoryTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductTagTemplate;
use Automattic\WooCommerce\Blocks\Templates\ProductSearchResultsTemplate;
use Automattic\WooCommerce\Blocks\Templates\SingleProductTemplate;
use Automattic\WooCommerce\Blocks\Templates\SimpleProductAddToCartWithOptionsTemplate;
use Automattic\WooCommerce\Blocks\Templates\ExternalProductAddToCartWithOptionsTemplate;
use Automattic\WooCommerce\Blocks\Templates\VariableProductAddToCartWithOptionsTemplate;
use Automattic\WooCommerce\Blocks\Templates\GroupedProductAddToCartWithOptionsTemplate;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class BlockTemplatesRegistry {
⋮----
private $templates = array();
⋮----
public function init() {
if ( BlockTemplateUtils::supports_block_templates( 'wp_template' ) ) {
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/BlockTypesController.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
use Automattic\WooCommerce\Blocks\Assets\Api as AssetApi;
use Automattic\WooCommerce\Blocks\Integrations\IntegrationRegistry;
use Automattic\WooCommerce\Blocks\BlockTypes\Cart;
use Automattic\WooCommerce\Blocks\BlockTypes\Checkout;
use Automattic\WooCommerce\Blocks\BlockTypes\MiniCartContents;
use Automattic\WooCommerce\Internal\Features\BlockEditorUnifiedAssets;
use Automattic\WooCommerce\Internal\ShopperLists\ShopperListsController;
⋮----
final class BlockTypesController {
⋮----
protected $asset_api;
⋮----
protected $asset_data_registry;
⋮----
private $registered_blocks_with_woocommerce_parents;
⋮----
private static $register_blocks_has_run = false;
⋮----
private $should_enqueue_block_style_for_classic_themes = null;
⋮----
public function __construct( AssetApi $asset_api, AssetDataRegistry $asset_data_registry ) {
⋮----
$this->init();
⋮----
protected function init() {
⋮----
public function get_registered_blocks_with_woocommerce_parent() {
... (101 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/CLAUDE.md">
# WooCommerce Blocks (PHP)

See `client/blocks/CLAUDE.md` for full blocks documentation including PHP class hierarchy, patterns, and architecture.
</file>

<file path="plugins/woocommerce/src/Blocks/CoreBreadcrumbsCompatibility.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
final class CoreBreadcrumbsCompatibility {
⋮----
public function set_product_breadcrumbs_preferred_taxonomy( $settings, $post_type, $post_id = 0 ) {
⋮----
public function apply_woocommerce_breadcrumb_filters( $items ) {
⋮----
$items = $this->apply_woocommerce_core_breadcrumb_adjustments( $items );
⋮----
/**
		 * Filters the breadcrumb trail array.
		 *
		 * @since 2.3.0
		 *
		 * @param array               $crumbs The breadcrumb trail.
		 * @param \WC_Breadcrumb|null $breadcrumb The breadcrumb object (null when called from Core block).
		 */
⋮----
private function apply_woocommerce_core_breadcrumb_adjustments( $items ) {
⋮----
$items = $this->replace_product_archive_breadcrumb_label( $items );
$items = $this->prepend_shop_page_to_product_taxonomy_breadcrumbs( $items );
$items = $this->prepend_taxonomy_label_to_product_taxonomy_breadcrumbs( $items );
$items = $this->prepend_shop_page_to_product_search_breadcrumbs( $items );
$items = $this->replace_product_tag_breadcrumb_label( $items );
$items = $this->replace_search_breadcrumb_label( $items );
$items = $this->prepend_my_account_page_to_endpoint_breadcrumbs( $items );
$items = $this->apply_home_breadcrumb_url_filter( $items );
⋮----
... (100 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/DependencyDetection.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
use Automattic\WooCommerce\Blocks\Utils\Utils;
use Automattic\WooCommerce\Internal\Utilities\BlocksUtil;
⋮----
final class DependencyDetection {
⋮----
private bool $proxy_output = false;
⋮----
public function __construct() {
$this->init();
⋮----
public function init(): void {
⋮----
public function output_early_proxy_setup(): void {
⋮----
if ( ! $this->page_has_tracked_blocks() ) {
⋮----
$mapping_json = \wp_json_encode( self::WC_GLOBAL_EXPORTS );
⋮----
$wc_plugin_url  = \plugins_url( '/', WC_PLUGIN_FILE );
⋮----
public function output_script_registry(): void {
⋮----
$script_registry = $this->build_script_registry();
$registry_json   = \wp_json_encode( $script_registry );
⋮----
private function build_script_registry(): array {
⋮----
$src = Utils::get_absolute_script_url( $src );
... (27 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/InboxNotifications.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\Notes;
⋮----
class InboxNotifications {
⋮----
public static function delete_surface_cart_checkout_blocks_notification() {
Notes::delete_notes_with_name( self::SURFACE_CART_CHECKOUT_NOTE_NAME );
</file>

<file path="plugins/woocommerce/src/Blocks/Installer.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
class Installer {
⋮----
public function init() {
⋮----
public function install() {
$this->maybe_create_tables();
⋮----
public function create_pages( $pages ) {
⋮----
public function maybe_create_tables() {
⋮----
$show_errors = $wpdb->hide_errors();
⋮----
$collate     = $wpdb->has_cap( 'collation' ) ? $wpdb->get_charset_collate() : '';
$exists      = $this->maybe_create_table(
⋮----
$wpdb->show_errors();
⋮----
return $this->add_create_table_notice( $table_name );
⋮----
protected function maybe_create_table( $table_name, $create_sql ) {
⋮----
if ( in_array( $table_name, $wpdb->get_col( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ), 0 ), true ) ) {
⋮----
$wpdb->query( $create_sql );
⋮----
return in_array( $table_name, $wpdb->get_col( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ), 0 ), true );
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/Library.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
use Automattic\WooCommerce\Blocks\BlockTypes\AtomicBlock;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
use Automattic\WooCommerce\Blocks\Assets\Api as AssetApi;
use Automattic\WooCommerce\Blocks\Integrations\IntegrationRegistry;
⋮----
class Library {
⋮----
public static function init() {
⋮----
public static function define_tables() {
⋮----
public static function register_blocks() {
</file>

<file path="plugins/woocommerce/src/Blocks/Options.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
class Options {
</file>

<file path="plugins/woocommerce/src/Blocks/Package.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
use Automattic\WooCommerce\Blocks\Domain\Package as NewPackage;
use Automattic\WooCommerce\Blocks\Domain\Bootstrap;
use Automattic\WooCommerce\Blocks\Registry\Container;
use Automattic\WooCommerce\Blocks\Domain\Services\FeatureGating;
⋮----
class Package {
⋮----
protected static function get_package() {
return self::container()->get( NewPackage::class );
⋮----
public static function init() {
self::container()->get( Bootstrap::class );
⋮----
public static function get_version() {
return self::get_package()->get_version();
⋮----
public static function get_path() {
return self::get_package()->get_path();
⋮----
public static function feature() {
⋮----
public static function container( $reset = false ) {
⋮----
$container->register(
</file>

<file path="plugins/woocommerce/src/Blocks/QueryFilters.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
use Automattic\WooCommerce\Internal\ProductFilters\FilterDataProvider;
use Automattic\WooCommerce\Internal\ProductFilters\QueryClauses;
⋮----
final class QueryFilters {
⋮----
public function __construct() {
⋮----
public function init() {
⋮----
public function main_query_filter( $args, $wp_query ) {
⋮----
return wc_get_container()->get( QueryClauses::class )->add_query_clauses_for_main_query( $args, $wp_query );
⋮----
public function add_query_clauses( $args, $wp_query ) {
⋮----
return wc_get_container()->get( QueryClauses::class )->add_query_clauses( $args, $wp_query );
⋮----
public function get_filtered_price( $query_vars ) {
⋮----
return (object) $container->get( FilterDataProvider::class )->with( $container->get( QueryClauses::class ) )->get_filtered_price( $query_vars );
⋮----
public function get_stock_status_counts( $query_vars ) {
⋮----
return $container->get( FilterDataProvider::class )->with( $container->get( QueryClauses::class ) )->get_stock_status_counts( $query_vars, array_keys( wc_get_product_stock_status_options() ) );
⋮----
public function get_rating_counts( $query_vars ) {
⋮----
return $container->get( FilterDataProvider::class )->with( $container->get( QueryClauses::class ) )->get_rating_counts( $query_vars );
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/Blocks/TemplateOptions.php">
namespace Automattic\WooCommerce\Blocks;
⋮----
use Automattic\WooCommerce\Blocks\Options;
⋮----
class TemplateOptions {
⋮----
public function init() {
⋮----
public function check_should_use_blockified_product_grid_templates( $old_name, $old_theme ) {
if ( ! $old_theme->is_block_theme() && wp_is_block_theme() ) {
</file>

<file path="plugins/woocommerce/src/Caches/OrderCache.php">
namespace Automattic\WooCommerce\Caches;
⋮----
use Automattic\WooCommerce\Caching\ObjectCache;
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
⋮----
class OrderCache extends ObjectCache {
⋮----
public function get_object_type(): string {
⋮----
protected function get_object_id( $object ) {
return $object->get_id();
⋮----
protected function validate( $object ): ?array {
</file>

<file path="plugins/woocommerce/src/Caches/OrderCacheController.php">
namespace Automattic\WooCommerce\Caches;
⋮----
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class OrderCacheController {
⋮----
private $order_cache;
⋮----
private $features_controller;
⋮----
private $orders_cache_usage_backup = null;
⋮----
final public function init( OrderCache $order_cache ) {
⋮----
public function orders_cache_usage_is_enabled(): bool {
return OrderUtil::custom_orders_table_usage_is_enabled();
⋮----
public function temporarily_disable_orders_cache_usage(): void {
if ( $this->orders_cache_usage_is_temporarly_disabled() ) {
⋮----
$this->orders_cache_usage_backup = $this->orders_cache_usage_is_enabled();
⋮----
public function orders_cache_usage_is_temporarly_disabled(): bool {
⋮----
public function maybe_restore_orders_cache_usage(): void {
</file>

<file path="plugins/woocommerce/src/Caches/OrderCountCache.php">
namespace Automattic\WooCommerce\Caches;
⋮----
use Automattic\WooCommerce\Enums\OrderStatus;
⋮----
class OrderCountCache {
⋮----
private $cache_prefix = 'order-count';
⋮----
protected $expiration = DAY_IN_SECONDS;
⋮----
private function get_saved_statuses_for_type( string $order_type ) {
$statuses = wp_cache_get( $this->get_saved_statuses_cache_key( $order_type ) );
⋮----
private function ensure_statuses_for_type( string $order_type, array $order_statuses ) {
⋮----
$existing     = $this->get_saved_statuses_for_type( $order_type );
⋮----
wp_cache_set( $this->get_saved_statuses_cache_key( $order_type ), $merged, '', $this->expiration );
⋮----
/**
	 * Get the default statuses.
	 *
	 * @return string[]
	 *
	 * @deprecated 10.1.0 This method will be removed in the future.
	 */
public function get_default_statuses() {
⋮----
/**
	 * Get the cache key for a given order type and status.
... (84 lines truncated)
</file>

<file path="plugins/woocommerce/src/Caches/OrderCountCacheService.php">
namespace Automattic\WooCommerce\Caches;
⋮----
use WC_Order;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class OrderCountCacheService {
⋮----
private $order_count_cache;
⋮----
private $order_statuses = array();
⋮----
private $initial_order_statuses = array();
⋮----
final public function init() {
⋮----
public function refresh_cache( $order_type ) {
$this->order_count_cache->flush( $order_type );
OrderUtil::get_count_for_type( $order_type );
⋮----
public function prime_cache_if_cold( $order_type ) {
⋮----
if ( wp_using_ext_object_cache() && null === $this->order_count_cache->get( $order_type ) ) {
⋮----
public function flush_cache() {
⋮----
public function schedule_background_actions() {
⋮----
public function unschedule_background_actions() {
WC()->queue()->cancel_all( self::BACKGROUND_EVENT_HOOK );
... (32 lines truncated)
</file>

<file path="plugins/woocommerce/src/Caches/ProductCountCache.php">
namespace Automattic\WooCommerce\Caches;
⋮----
class ProductCountCache {
⋮----
private string $cache_prefix = 'product-count';
⋮----
protected int $expiration = DAY_IN_SECONDS;
⋮----
private function get_saved_statuses_for_type( string $product_type ): array {
$cache_key = $this->get_saved_statuses_cache_key( $product_type );
⋮----
private function ensure_statuses_for_type( string $product_type, array $product_statuses ): void {
⋮----
$existing     = $this->get_saved_statuses_for_type( $product_type );
⋮----
wp_cache_set( $this->get_saved_statuses_cache_key( $product_type ), $merged, '', $this->expiration );
⋮----
/**
	 * Get the cache key for a given product type and status.
	 *
	 * @param string $product_type   The post type (e.g. 'product', 'product_variation').
	 * @param string $product_status The status of the product.
	 *
	 * @return string
	 */
private function get_cache_key( string $product_type, string $product_status ): string {
⋮----
private function get_saved_statuses_cache_key( string $product_type ): string {
⋮----
public function is_cached( string $product_type, string $product_status ): bool {
... (56 lines truncated)
</file>

<file path="plugins/woocommerce/src/Caches/ProductCountCacheService.php">
namespace Automattic\WooCommerce\Caches;
⋮----
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use WC_Product;
use WP_Post;
⋮----
class ProductCountCacheService {
⋮----
private ProductCountCache $product_count_cache;
⋮----
private array $product_statuses = array();
⋮----
private array $initial_product_statuses = array();
⋮----
private array $products_in_creation = array();
⋮----
final public function init(): void {
⋮----
public function prime_cache_if_cold( string $product_type = 'product' ): void {
⋮----
if ( wp_using_ext_object_cache() && null === $this->product_count_cache->get( $product_type ) ) {
$this->product_count_cache->flush( $product_type );
wc_get_container()->get( ProductUtil::class )->get_counts_for_type( $product_type );
⋮----
public function flush_cache(): void {
$this->product_count_cache->flush( 'product' );
⋮----
public function schedule_background_actions(): void {
⋮----
public function unschedule_background_actions(): void {
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/src/Caching/CacheEngine.php">
namespace Automattic\WooCommerce\Caching;
⋮----
interface CacheEngine {
⋮----
public function get_cached_object( string $key, string $group = '' );
⋮----
/**
	 * Caches an object under a given key, and with a given expiration.
	 *
	 * @param string       $key The key under which the object will be cached.
	 * @param array|object $object The object to cache.
	 * @param int          $expiration Expiration for the cached object, in seconds.
	 * @param string       $group The group under which the object will be cached.
	 *
	 * @return bool True if the object is cached successfully, false otherwise.
	 */
public function cache_object( string $key, $object, int $expiration, string $group = '' ): bool;
⋮----
/**
	 * Removes a cached object from the cache.
	 *
	 * @param string $key They key under which the object is cached.
	 * @param string $group The group under which the object is cached.
	 *
	 * @return bool True if the object is removed from the cache successfully, false otherwise (because the object wasn't cached or for other reason).
	 */
public function delete_cached_object( string $key, string $group = '' ): bool;
⋮----
/**
	 * Checks if an object is cached under a given key.
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/src/Caching/CacheException.php">
namespace Automattic\WooCommerce\Caching;
⋮----
class CacheException extends \Exception {
⋮----
private $errors;
⋮----
private $thrower;
⋮----
private $cached_id;
⋮----
public function __construct( string $message, ObjectCache $thrower, $cached_id = null, ?array $errors = null, $code = 0, ?\Throwable $previous = null ) {
⋮----
parent::__construct( $message, $code, $previous );
⋮----
public function __toString(): string {
⋮----
return "CacheException: [{$this->thrower->get_object_type()}{$cached_id_part}]: {$this->message}";
⋮----
public function get_errors(): array {
⋮----
public function get_thrower(): object {
⋮----
public function get_cached_id() {
</file>

<file path="plugins/woocommerce/src/Caching/CacheNameSpaceTrait.php">
namespace Automattic\WooCommerce\Caching;
⋮----
trait CacheNameSpaceTrait {
⋮----
public static function get_cache_prefix( $group ) {
⋮----
if ( self::is_valid_cache_prefix( $prefix ) ) {
⋮----
$prefix = self::generate_cache_prefix();
⋮----
if ( self::is_valid_cache_prefix( $cached_prefix ) ) {
⋮----
public static function incr_cache_prefix( $group ) {
⋮----
self::invalidate_cache_group( $group );
⋮----
public static function invalidate_cache_group( $group ) {
return wp_cache_set( 'wc_' . $group . '_cache_prefix', self::generate_cache_prefix(), $group );
⋮----
public static function get_prefixed_key( $key, $group ) {
return self::get_cache_prefix( $group ) . $key;
⋮----
private static function generate_cache_prefix() {
⋮----
private static function is_valid_cache_prefix( $prefix ) {
</file>

<file path="plugins/woocommerce/src/Caching/ObjectCache.php">
namespace Automattic\WooCommerce\Caching;
⋮----
abstract class ObjectCache {
⋮----
private $object_type;
⋮----
protected $default_expiration = HOUR_IN_SECONDS;
⋮----
private $last_cached_data;
⋮----
private $cache_engine = null;
⋮----
abstract public function get_object_type(): string;
⋮----
public function __construct() {
$this->object_type = $this->get_object_type();
⋮----
public function get_default_expiration_value(): int {
⋮----
private function get_cache_engine(): CacheEngine {
⋮----
$engine = $this->get_cache_engine_instance();
⋮----
public function set( $object, $id = null, int $expiration = self::DEFAULT_EXPIRATION ): bool {
⋮----
$this->verify_expiration_value( $expiration );
⋮----
$errors = $this->validate( $object );
⋮----
$id = $this->get_id_from_object_if_null( $object, $id );
... (43 lines truncated)
</file>

<file path="plugins/woocommerce/src/Caching/WPCacheEngine.php">
namespace Automattic\WooCommerce\Caching;
⋮----
class WPCacheEngine implements CacheEngine {
⋮----
public function get_cached_object( string $key, string $group = '' ) {
$prefixed_key = self::get_prefixed_key( $key, $group );
⋮----
/**
	 * Retrieves a set of objects cached under the given keys.
	 *
	 * @param string[] $keys The keys under which the object to retrieve is cached.
	 * @param string   $group The group under which the object is cached.
	 *
	 * @return array The cached array of objects keyed by the given keys, values will be null for any non-cached keys.
	 */
public function get_cached_objects( array $keys, string $group = '' ) {
$prefix  = self::get_cache_prefix( $group );
⋮----
/**
	 * Caches an object under a given key, and with a given expiration.
	 *
	 * @param string       $key The key under which the object will be cached.
	 * @param array|object $object The object to cache.
	 * @param int          $expiration Expiration for the cached object, in seconds.
	 * @param string       $group The group under which the object will be cached.
	 *
	 * @return bool True if the object is cached successfully, false otherwise.
	 */
public function cache_object( string $key, $object, int $expiration, string $group = '' ): bool {
⋮----
... (43 lines truncated)
</file>

<file path="plugins/woocommerce/src/Checkout/Helpers/ReserveStock.php">
namespace Automattic\WooCommerce\Checkout\Helpers;
⋮----
use Automattic\WooCommerce\Enums\OrderInternalStatus;
use Automattic\WooCommerce\Enums\OrderItemType;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
⋮----
final class ReserveStock {
⋮----
private $enabled = true;
⋮----
public function __construct() {
⋮----
protected function is_enabled() {
⋮----
public function get_reserved_stock( $product, $exclude_order_id = 0 ) {
⋮----
if ( ! $this->is_enabled() ) {
⋮----
$wpdb->get_var( $this->get_query_for_reserved_stock( $product->get_stock_managed_by_id(), $exclude_order_id ) )
⋮----
public function reserve_stock_for_order( $order, $minutes = 60 ) {
⋮----
foreach ( $order->get_items() as $item ) {
$is_target_item = $item->is_type( OrderItemType::LINE_ITEM ) && $item->get_quantity() > 0;
⋮----
$product = $item->get_product();
⋮----
if ( ! $product->is_in_stock() ) {
⋮----
... (41 lines truncated)
</file>

<file path="plugins/woocommerce/src/Checkout/Helpers/ReserveStockException.php">
namespace Automattic\WooCommerce\Checkout\Helpers;
⋮----
class ReserveStockException extends \Exception {
⋮----
protected $error_code;
⋮----
protected $error_data;
⋮----
public function __construct( $code, $message, $http_status_code = 400, $data = array() ) {
⋮----
parent::__construct( $message, $http_status_code );
⋮----
public function getErrorCode() {
⋮----
public function getErrorData() {
</file>

<file path="plugins/woocommerce/src/Enums/CatalogSortOrder.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class CatalogSortOrder {
</file>

<file path="plugins/woocommerce/src/Enums/CatalogVisibility.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class CatalogVisibility {
⋮----
public static function get_all(): array {
</file>

<file path="plugins/woocommerce/src/Enums/CurrencyPosition.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class CurrencyPosition {
</file>

<file path="plugins/woocommerce/src/Enums/DefaultCustomerAddress.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class DefaultCustomerAddress {
⋮----
/**
	 * Use the shop's base country/region as the default location.
	 *
	 * @var string
	 */
</file>

<file path="plugins/woocommerce/src/Enums/DimensionUnit.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class DimensionUnit {
⋮----
public static function get_all(): array {
</file>

<file path="plugins/woocommerce/src/Enums/FeaturePluginCompatibility.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class FeaturePluginCompatibility {
</file>

<file path="plugins/woocommerce/src/Enums/OrderInternalStatus.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class OrderInternalStatus {
⋮----
public static function get_all(): array {
</file>

<file path="plugins/woocommerce/src/Enums/OrderItemType.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class OrderItemType {
</file>

<file path="plugins/woocommerce/src/Enums/OrderStatus.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class OrderStatus {
⋮----
public static function get_all(): array {
</file>

<file path="plugins/woocommerce/src/Enums/PaymentGatewayFeature.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class PaymentGatewayFeature {
</file>

<file path="plugins/woocommerce/src/Enums/ProductStatus.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class ProductStatus {
⋮----
public static function get_all(): array {
</file>

<file path="plugins/woocommerce/src/Enums/ProductStockStatus.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class ProductStockStatus {
⋮----
public static function get_all(): array {
</file>

<file path="plugins/woocommerce/src/Enums/ProductTaxStatus.php">
namespace Automattic\WooCommerce\Enums;
⋮----
class ProductTaxStatus {
</file>

<file path="plugins/woocommerce/src/Enums/ProductType.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class ProductType {
⋮----
public static function get_all(): array {
</file>

<file path="plugins/woocommerce/src/Enums/README.md">
# WooCommerce Enumerators <!-- omit in toc -->

This directory contains enumerators used in the WooCommerce plugin. Enumerators are used to define a set of named constants, which can be used to represent a set of possible values.

The enum classes make it easier to reference string values and avoid typos. They also make the code stricter, make it easier to find the usage of the possible values, centralize them, improve their documentation, and many other advantages that should help developers create related code.

## Available Enumerators

- [CatalogSortOrder](./CatalogSortOrder.php) - Enumerates the possible values of the `woocommerce_default_catalog_orderby` option.
- [CatalogVisibility](./CatalogVisibility.php) - Enumerates the possible catalog visibility options for a product.
- [CurrencyPosition](./CurrencyPosition.php) - Enumerates the possible values of the `woocommerce_currency_pos` option.
- [DefaultCustomerAddress](./DefaultCustomerAddress.php) - Enumerates the possible values of the `woocommerce_default_customer_address` option.
- [DimensionUnit](./DimensionUnit.php) - Enumerates the possible values of the `woocommerce_dimension_unit` option.
- [OrderInternalStatus](./OrderInternalStatus.php) - Enumerates the possible internal statuses of an order (when stored in the database).
- [OrderItemType](./OrderItemType.php) - Enumerates the possible types of an order line item.
- [OrderStatus](./OrderStatus.php) - Enumerates the possible statuses of an order.
- [PaymentGatewayFeatures](./PaymentGatewayFeatures.php) - Enumerates the possible features of a payment gateway.
- [ProductStatus](./ProductStatus.php) - Enumerates the possible statuses of a product.
- [ProductStockStatus](./ProductStockStatus.php) - Enumerates the possible stock statuses of a product.
- [ProductType](./ProductType.php) - Enumerates the possible types of a product.
- [StockDisplayFormat](./StockDisplayFormat.php) - Enumerates the possible values of the `woocommerce_stock_format` option.
- [TaxBasedOn](./TaxBasedOn.php) - Enumerates the possible values of the `woocommerce_tax_based_on` option.
- [TaxDisplayMode](./TaxDisplayMode.php) - Enumerates the possible values of the `woocommerce_tax_display_shop` and `woocommerce_tax_display_cart` options.
- [WeightUnit](./WeightUnit.php) - Enumerates the possible values of the `woocommerce_weight_unit` option.

## Contributing

The WooCommerce plugin contains many string values that still need to be converted to enumerators. Feel free to contribute by creating new classes.
</file>

<file path="plugins/woocommerce/src/Enums/StockDisplayFormat.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class StockDisplayFormat {
⋮----
/**
	 * Only show the quantity remaining in stock when it is low (e.g. "Only 2 left in stock").
	 *
	 * @var string
	 */
</file>

<file path="plugins/woocommerce/src/Enums/TaxBasedOn.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class TaxBasedOn {
</file>

<file path="plugins/woocommerce/src/Enums/TaxDisplayMode.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class TaxDisplayMode {
</file>

<file path="plugins/woocommerce/src/Enums/WeightUnit.php">
namespace Automattic\WooCommerce\Enums;
⋮----
final class WeightUnit {
⋮----
public static function get_all(): array {
</file>

<file path="plugins/woocommerce/src/Gateways/PayPal/AddressRequirements.php">
namespace Automattic\WooCommerce\Gateways\PayPal;
⋮----
class AddressRequirements {
⋮----
protected static $instance = null;
⋮----
final public static function instance() {
⋮----
public function country_requires_city( string $country_code ) {
⋮----
public function country_requires_postal_code( string $country_code ) {
</file>

<file path="plugins/woocommerce/src/Gateways/PayPal/Buttons.php">
namespace Automattic\WooCommerce\Gateways\PayPal;
⋮----
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Gateways\PayPal\Request as PayPalRequest;
⋮----
class Buttons {
⋮----
private \WC_Gateway_Paypal $gateway;
⋮----
private bool $enabled;
⋮----
private PayPalRequest $request;
⋮----
public function __construct( \WC_Gateway_Paypal $gateway ) {
⋮----
$this->enabled = $this->gateway->should_use_orders_v2() && 'yes' === $this->gateway->get_option( 'paypal_buttons', 'yes' );
⋮----
public function get_options(): array {
$common_options = $this->get_common_options();
⋮----
'page-type'              => $this->get_page_type(),
⋮----
public function get_common_options(): array {
$intent = $this->gateway->get_option( 'paymentaction' ) === 'authorization' ? 'authorize' : 'capture';
⋮----
'client-id'       => $this->get_client_id(),
⋮----
public function get_client_id(): ?string {
if ( ! $this->gateway->should_use_orders_v2() ) {
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Gateways/PayPal/Constants.php">
namespace Automattic\WooCommerce\Gateways\PayPal;
⋮----
class Constants {
</file>

<file path="plugins/woocommerce/src/Gateways/PayPal/Helper.php">
namespace Automattic\WooCommerce\Gateways\PayPal;
⋮----
use WC_Order;
use Automattic\WooCommerce\Gateways\PayPal\Constants as PayPalConstants;
⋮----
class Helper {
⋮----
public static function is_country_supported_by_paypal( string $country_code ): bool {
⋮----
public static function is_paypal_gateway_available(): bool {
⋮----
public static function is_orders_v2_migration_eligible(): bool {
⋮----
public static function get_wc_order_from_paypal_custom_id( string $custom_id ): ?WC_Order {
⋮----
if ( $order_key !== $order->get_order_key() ) {
⋮----
public static function redact_data( $data ) {
⋮----
$redacted_data[ $key ] = self::mask_email( (string) $value );
⋮----
$redacted_data[ $key ] = self::redact_data( $value );
⋮----
public static function mask_email( string $email ): string {
⋮----
public static function update_addresses_in_order( ?WC_Order $order, array $paypal_order_details ): void {
⋮----
if ( 'yes' === $order->get_meta( PayPalConstants::PAYPAL_ORDER_META_ADDRESSES_UPDATED, true ) ) {
⋮----
$order->set_shipping_first_name( $approximate_first_name );
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/src/Gateways/PayPal/Notices.php">
namespace Automattic\WooCommerce\Gateways\PayPal;
⋮----
use WC_Order;
use Automattic\WooCommerce\Gateways\PayPal\Helper as PayPalHelper;
⋮----
class Notices {
⋮----
private $gateway;
⋮----
public function __construct() {
$this->gateway = \WC_Gateway_Paypal::get_instance();
⋮----
public function add_paypal_notices(): void {
⋮----
if ( ! PayPalHelper::is_paypal_gateway_available() || ! $this->gateway->should_use_orders_v2() ) {
⋮----
$this->add_paypal_migration_notice();
$this->add_paypal_account_restricted_notice();
$this->add_paypal_unsupported_currency_notice();
⋮----
public function add_paypal_notices_on_payments_settings_page(): void {
⋮----
$this->add_paypal_notices();
⋮----
public function add_paypal_migration_notice(): void {
⋮----
if ( $this->is_notice_dismissed( self::PAYPAL_MIGRATION_NOTICE ) ) {
⋮----
$dismiss_url = $this->get_dismiss_url( self::PAYPAL_MIGRATION_NOTICE );
⋮----
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/src/Gateways/PayPal/Request.php">
namespace Automattic\WooCommerce\Gateways\PayPal;
⋮----
use Exception;
use WC_Order;
use Automattic\WooCommerce\Gateways\PayPal\Constants as PayPalConstants;
use Automattic\WooCommerce\Gateways\PayPal\AddressRequirements as PayPalAddressRequirements;
use Automattic\WooCommerce\Gateways\PayPal\Helper as PayPalHelper;
use Automattic\WooCommerce\Enums\OrderItemType;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\Jetpack\Connection\Client as Jetpack_Connection_Client;
⋮----
class Request {
⋮----
private \WC_Gateway_Paypal $gateway;
⋮----
public function __construct( \WC_Gateway_Paypal $gateway ) {
⋮----
public function create_paypal_order(
⋮----
'order'     => $this->get_paypal_create_order_request_params( $order, $payment_source, $js_sdk_params ),
⋮----
$response     = $this->send_wpcom_proxy_request( 'POST', self::WPCOM_PROXY_ORDER_ENDPOINT, $request_body );
⋮----
throw new Exception( 'PayPal order creation failed. Response error: ' . $response->get_error_message() );
⋮----
$redirect_url = $this->get_approve_link( $http_code, $response_data );
⋮----
$order->update_meta_data( PayPalConstants::PAYPAL_ORDER_META_ORDER_ID, $response_data['id'] );
⋮----
$order->update_meta_data( PayPalConstants::PAYPAL_ORDER_META_STATUS, $response_data['status'] );
... (293 lines truncated)
</file>

<file path="plugins/woocommerce/src/Gateways/PayPal/TransactAccountManager.php">
namespace Automattic\WooCommerce\Gateways\PayPal;
⋮----
use Automattic\Jetpack\Connection\Client as Jetpack_Connection_Client;
use Automattic\WooCommerce\Gateways\PayPal\Constants as PayPalConstants;
⋮----
final class TransactAccountManager {
⋮----
private \WC_Gateway_Paypal $gateway;
⋮----
public function __construct( \WC_Gateway_Paypal $gateway ) {
⋮----
public function do_onboarding(): void {
⋮----
$jetpack_connection_manager = $this->gateway->get_jetpack_connection_manager();
⋮----
\WC_Gateway_Paypal::log( 'Jetpack connection manager not found.', 'error' );
⋮----
if ( ! $jetpack_connection_manager->is_connected() ) {
$result = $jetpack_connection_manager->try_registration();
⋮----
\WC_Gateway_Paypal::log( 'Jetpack registration failed: ' . $result->get_error_message(), 'error' );
⋮----
$merchant_account_data = $this->get_transact_account_data( 'merchant' );
⋮----
$merchant_account = $this->create_merchant_account();
⋮----
\WC_Gateway_Paypal::log( 'Transact merchant onboarding failed.', 'error' );
⋮----
$this->update_transact_account_cache(
$this->get_cache_key( 'merchant' ),
... (45 lines truncated)
</file>

<file path="plugins/woocommerce/src/Gateways/PayPal/WebhookHandler.php">
namespace Automattic\WooCommerce\Gateways\PayPal;
⋮----
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Gateways\PayPal\Constants as PayPalConstants;
use Automattic\WooCommerce\Gateways\PayPal\Helper as PayPalHelper;
use Automattic\WooCommerce\Gateways\PayPal\Request as PayPalRequest;
⋮----
class WebhookHandler {
⋮----
public function process_webhook( \WP_REST_Request $request ): void {
$data = $request->get_json_params();
⋮----
\WC_Gateway_Paypal::log( 'Invalid PayPal webhook payload: ' . wc_print_r( $data, true ) );
⋮----
\WC_Gateway_Paypal::log( 'Webhook received: ' . wc_print_r( PayPalHelper::redact_data( $data ), true ) );
⋮----
$this->process_checkout_order_approved( $data );
⋮----
$this->process_payment_capture_pending( $data );
⋮----
$this->process_payment_capture_completed( $data );
⋮----
$this->process_payment_authorization_created( $data );
⋮----
\WC_Gateway_Paypal::log( 'Unhandled PayPal webhook event: ' . wc_print_r( PayPalHelper::redact_data( $data ), true ) );
⋮----
private function process_checkout_order_approved( array $event ): void {
⋮----
$order     = PayPalHelper::get_wc_order_from_paypal_custom_id( $custom_id );
⋮----
... (51 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/Domain/Traits/OrderAbilityTrait.php">
namespace Automattic\WooCommerce\Internal\Abilities\Domain\Traits;
⋮----
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
trait OrderAbilityTrait {
⋮----
protected static function get_allowed_order_status_slugs(): array {
⋮----
protected static function get_order_output_status_slugs(): array {
⋮----
array_merge( OrderStatus::get_all(), array_keys( wc_get_order_statuses() ) )
⋮----
protected static function get_order_note_output_schema(): array {
⋮----
'order'   => self::get_order_output_schema(),
⋮----
protected static function get_order_output_schema(): array {
⋮----
'enum' => self::get_order_output_status_slugs(),
⋮----
protected static function get_order_from_input( array $input ) {
⋮----
return new \WP_Error(
⋮----
public static function can_edit_order( $input = array() ): bool {
$order_id = self::get_id_from_input( $input );
⋮----
protected static function format_order_for_response( \WC_Order $order, bool $include_line_items ): array {
$billing_email = $order->get_billing_email();
... (27 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/Domain/Traits/ProductAbilityTrait.php">
namespace Automattic\WooCommerce\Internal\Abilities\Domain\Traits;
⋮----
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
trait ProductAbilityTrait {
⋮----
protected static function get_product_create_input_schema(): array {
⋮----
'oneOf' => self::get_product_alias_input_schema_branches( array( 'name' ), false ),
⋮----
protected static function get_product_update_input_schema(): array {
$branches          = self::get_product_alias_input_schema_branches( array( 'id' ), true );
$mutation_schemas  = self::get_product_mutation_field_schemas();
⋮----
foreach ( self::get_common_product_mutation_fields() as $field ) {
⋮----
private static function get_product_alias_input_schema_branches( array $base_required, bool $require_alias ): array {
⋮----
foreach ( self::get_product_type_alias_configs() as $product_type_alias => $product_config ) {
⋮----
$properties['product_type_alias'] = self::get_product_type_alias_schema( $product_type_alias );
⋮----
self::get_product_mutation_field_schemas_for_fields( $product_config['fields'] )
⋮----
private static function get_product_type_alias_schema( ?string $product_type_alias = null ): array {
⋮----
'enum'        => null === $product_type_alias ? self::get_supported_product_type_aliases() : array( $product_type_alias ),
⋮----
... (176 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/Domain/AbstractDomainAbility.php">
namespace Automattic\WooCommerce\Internal\Abilities\Domain;
⋮----
abstract class AbstractDomainAbility {
⋮----
protected static function get_collection_output_schema( string $collection_key, array $item_schema ): array {
⋮----
protected static function get_entity_output_schema( string $entity_key, array $item_schema ): array {
⋮----
protected static function get_delete_output_schema(): array {
⋮----
protected static function get_id_from_input( $input ): int {
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/Domain/OrderAddNote.php">
namespace Automattic\WooCommerce\Internal\Abilities\Domain;
⋮----
use Automattic\WooCommerce\Abilities\AbilityDefinition;
use Automattic\WooCommerce\Internal\Abilities\Domain\Traits\OrderAbilityTrait;
⋮----
class OrderAddNote extends AbstractDomainAbility implements AbilityDefinition {
⋮----
public static function get_name(): string {
⋮----
public static function get_registration_args(): array {
⋮----
'input_schema'        => self::get_input_schema(),
'output_schema'       => self::get_order_note_output_schema(),
⋮----
public static function execute( array $input ) {
$order = self::get_order_from_input( $input );
⋮----
return new \WP_Error(
⋮----
$note_id = $order->add_order_note(
⋮----
'order'   => self::format_order_for_response( $order, false ),
⋮----
private static function get_input_schema(): array {
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/Domain/OrdersQuery.php">
namespace Automattic\WooCommerce\Internal\Abilities\Domain;
⋮----
use Automattic\WooCommerce\Abilities\AbilityDefinition;
use Automattic\WooCommerce\Internal\Abilities\Domain\Traits\OrderAbilityTrait;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class OrdersQuery extends AbstractDomainAbility implements AbilityDefinition {
⋮----
public static function get_name(): string {
⋮----
public static function get_registration_args(): array {
⋮----
'input_schema'        => self::get_input_schema(),
'output_schema'       => self::get_collection_output_schema( 'orders', self::get_order_output_schema() ),
⋮----
public static function execute( array $input ) {
⋮----
$order = self::get_order_from_input( $input );
⋮----
'orders'      => array( self::format_order_for_response( $order, $include_line_items ) ),
⋮----
$args['status'] = self::get_allowed_order_status_slugs();
⋮----
$args['orderby'] = self::prepare_orderby_arg( $orderby );
⋮----
$modified_date_query = self::build_modified_date_query_arg( $input );
⋮----
return self::format_order_for_response( $order, $include_line_items );
⋮----
public static function can_query_orders( $input = array() ): bool {
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/Domain/OrderUpdateStatus.php">
namespace Automattic\WooCommerce\Internal\Abilities\Domain;
⋮----
use Automattic\WooCommerce\Abilities\AbilityDefinition;
use Automattic\WooCommerce\Internal\Abilities\Domain\Traits\OrderAbilityTrait;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class OrderUpdateStatus extends AbstractDomainAbility implements AbilityDefinition {
⋮----
public static function get_name(): string {
⋮----
public static function get_registration_args(): array {
⋮----
'input_schema'        => self::get_input_schema(),
'output_schema'       => self::get_entity_output_schema( 'order', self::get_order_output_schema() ),
⋮----
public static function execute( array $input ) {
$order = self::get_order_from_input( $input );
⋮----
return new \WP_Error(
⋮----
$status = OrderUtil::remove_status_prefix( sanitize_key( $input['status'] ) );
⋮----
if ( ! in_array( $status, self::get_allowed_order_status_slugs(), true ) ) {
⋮----
if ( $status === $order->get_status() ) {
⋮----
$updated = $order->update_status(
⋮----
'order' => self::format_order_for_response( $order, false ),
⋮----
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/Domain/ProductCreate.php">
namespace Automattic\WooCommerce\Internal\Abilities\Domain;
⋮----
use Automattic\WooCommerce\Abilities\AbilityDefinition;
use Automattic\WooCommerce\Internal\Abilities\Domain\Traits\ProductAbilityTrait;
⋮----
class ProductCreate extends AbstractDomainAbility implements AbilityDefinition {
⋮----
public static function get_name(): string {
⋮----
public static function get_registration_args(): array {
⋮----
'input_schema'        => self::get_input_schema(),
'output_schema'       => self::get_entity_output_schema( 'product', self::get_product_output_schema() ),
⋮----
public static function execute( array $input ) {
$product_config = self::get_product_config_for_alias( $input['product_type_alias'] ?? 'physical' );
⋮----
return new \WP_Error(
⋮----
self::apply_product_type_config( $product, $product_config );
⋮----
$validation_error = self::set_product_props_from_input( $product, $input, $product_config );
⋮----
return self::get_product_data_exception_error( $exception );
⋮----
$save_error = self::save_product( $product, 'woocommerce_product_create_failed' );
⋮----
'product' => self::format_product_for_response( $product ),
⋮----
public static function can_create_product( $input = array() ): bool {
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/Domain/ProductDelete.php">
namespace Automattic\WooCommerce\Internal\Abilities\Domain;
⋮----
use Automattic\WooCommerce\Abilities\AbilityDefinition;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\Abilities\Domain\Traits\ProductAbilityTrait;
⋮----
class ProductDelete extends AbstractDomainAbility implements AbilityDefinition {
⋮----
public static function get_name(): string {
⋮----
public static function get_registration_args(): array {
⋮----
'input_schema'        => self::get_input_schema(),
'output_schema'       => self::get_delete_output_schema(),
⋮----
public static function execute( array $input ) {
$product = self::get_product_from_input( $input );
⋮----
if ( $product->is_type( ProductType::VARIATION ) ) {
return new \WP_Error(
⋮----
$product_id = $product->get_id();
⋮----
$deleted = $product->delete( $force );
⋮----
public static function can_delete_product( $input = array() ): bool {
$product_id = self::get_id_from_input( $input );
⋮----
private static function get_input_schema(): array {
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/Domain/ProductsQuery.php">
namespace Automattic\WooCommerce\Internal\Abilities\Domain;
⋮----
use Automattic\WooCommerce\Abilities\AbilityDefinition;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\Abilities\Domain\Traits\ProductAbilityTrait;
⋮----
class ProductsQuery extends AbstractDomainAbility implements AbilityDefinition {
⋮----
public static function get_name(): string {
⋮----
public static function get_registration_args(): array {
⋮----
'input_schema'        => self::get_input_schema(),
'output_schema'       => self::get_collection_output_schema( 'products', self::get_product_output_schema() ),
⋮----
public static function execute( array $input ) {
⋮----
$product = self::get_product_from_input( $input );
⋮----
if ( $product->is_type( ProductType::VARIATION ) ) {
return new \WP_Error(
⋮----
'products'    => array( self::format_product_for_response( $product ) ),
⋮----
$type_args          = self::get_product_query_args_for_alias( $product_type_alias );
⋮----
return self::format_product_for_response( $product );
⋮----
public static function can_query_products( $input = array() ): bool {
$product_id = self::get_id_from_input( $input );
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/Domain/ProductUpdate.php">
namespace Automattic\WooCommerce\Internal\Abilities\Domain;
⋮----
use Automattic\WooCommerce\Abilities\AbilityDefinition;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Internal\Abilities\Domain\Traits\ProductAbilityTrait;
⋮----
class ProductUpdate extends AbstractDomainAbility implements AbilityDefinition {
⋮----
public static function get_name(): string {
⋮----
public static function get_registration_args(): array {
⋮----
'input_schema'        => self::get_input_schema(),
'output_schema'       => self::get_entity_output_schema( 'product', self::get_product_output_schema() ),
⋮----
public static function execute( array $input ) {
$product = self::get_product_from_input( $input );
⋮----
return new \WP_Error(
⋮----
$product_config = self::get_product_config_for_product( $product );
⋮----
&& sanitize_key( $input['status'] ) !== $product->get_status()
&& ! self::current_user_can_publish_products()
⋮----
$product_config = self::get_product_config_for_alias( $input['product_type_alias'] );
⋮----
$product = wc_get_product_object( $product_config['wc_type'], $product->get_id() );
⋮----
self::apply_product_type_config( $product, $product_config );
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/REST/RestAbility.php">
namespace Automattic\WooCommerce\Internal\Abilities\REST;
⋮----
class RestAbility extends \WP_Ability {
⋮----
protected function validate_output( $output ) {
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/REST/RestAbilityFactory.php">
namespace Automattic\WooCommerce\Internal\Abilities\REST;
⋮----
use Automattic\WooCommerce\Internal\MCP\Transport\WooCommerceRestTransport;
⋮----
class RestAbilityFactory {
⋮----
public static function register_controller_abilities( array $config ): void {
⋮----
$controller = new $controller_class();
⋮----
self::register_single_ability( $controller, $ability_config, $config['route'] );
⋮----
private static function register_single_ability( $controller, array $ability_config, string $route ): void {
⋮----
'input_schema'        => self::get_schema_for_operation( $controller, $ability_config['operation'] ),
'output_schema'       => self::get_output_schema( $controller, $ability_config['operation'] ),
⋮----
return self::execute_operation( $controller, $ability_config['operation'], $input, $route );
⋮----
return self::check_permission( $controller, $ability_config['operation'] );
⋮----
wc_get_logger()->error(
"Failed to register ability {$ability_config['id']}: " . $e->getMessage(),
⋮----
private static function get_schema_for_operation( $controller, string $operation ): array {
⋮----
return self::sanitize_args_to_schema( $controller->get_collection_params() );
⋮----
$args = $controller->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE );
return self::sanitize_args_to_schema( $args );
... (70 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/AbilitiesCategories.php">
namespace Automattic\WooCommerce\Internal\Abilities;
⋮----
class AbilitiesCategories {
⋮----
final public static function init(): void {
⋮----
public static function register_categories(): void {
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/AbilitiesLoader.php">
namespace Automattic\WooCommerce\Internal\Abilities;
⋮----
use Automattic\WooCommerce\Abilities\AbilityDefinition;
use Automattic\WooCommerce\Internal\Abilities\Domain\OrderAddNote;
use Automattic\WooCommerce\Internal\Abilities\Domain\OrderUpdateStatus;
use Automattic\WooCommerce\Internal\Abilities\Domain\OrdersQuery;
use Automattic\WooCommerce\Internal\Abilities\Domain\ProductCreate;
use Automattic\WooCommerce\Internal\Abilities\Domain\ProductDelete;
use Automattic\WooCommerce\Internal\Abilities\Domain\ProductUpdate;
use Automattic\WooCommerce\Internal\Abilities\Domain\ProductsQuery;
⋮----
class AbilitiesLoader {
⋮----
private static bool $initialized = false;
⋮----
private static array $registered_core_abilities = array();
⋮----
final public static function init(): void {
⋮----
AbilitiesCategories::init();
⋮----
AbilitiesRestBridge::init();
⋮----
public static function register_abilities(): void {
⋮----
foreach ( self::get_ability_definition_classes() as $class_name ) {
⋮----
$ability_name = $class_name::get_name();
⋮----
$is_core_ability = self::is_core_ability_definition_class( $class_name );
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/AbilitiesRegistry.php">
namespace Automattic\WooCommerce\Internal\Abilities;
⋮----
class AbilitiesRegistry {
⋮----
final public function init(): void {
AbilitiesLoader::init();
⋮----
public function get_abilities_ids(): array {
</file>

<file path="plugins/woocommerce/src/Internal/Abilities/AbilitiesRestBridge.php">
namespace Automattic\WooCommerce\Internal\Abilities;
⋮----
use Automattic\WooCommerce\Internal\Abilities\REST\RestAbilityFactory;
use Automattic\WooCommerce\Internal\MCP\MCPAdapterProvider;
⋮----
class AbilitiesRestBridge {
⋮----
private static function get_configurations(): array {
⋮----
final public static function init(): void {
⋮----
public static function register_abilities(): void {
⋮----
if ( ! MCPAdapterProvider::is_mcp_request() ) {
⋮----
foreach ( self::get_configurations() as $config ) {
RestAbilityFactory::register_controller_abilities( $config );
</file>

<file path="plugins/woocommerce/src/Internal/AbilitiesApi/AbilitiesClient.php">
namespace Automattic\WooCommerce\Internal\AbilitiesApi;
⋮----
class AbilitiesClient {
⋮----
private static bool $enabled = false;
⋮----
public static function enable(): bool {
⋮----
public static function enqueue_for_admin(): void {
</file>

<file path="plugins/woocommerce/src/Internal/AddressProvider/AbstractAutomatticAddressProvider.php">
namespace Automattic\WooCommerce\Internal\AddressProvider;
⋮----
use Automattic\WooCommerce\StoreApi\Utilities\JsonWebToken;
use Automattic\Jetpack\Constants;
use WC_Address_Provider;
⋮----
abstract class AbstractAutomatticAddressProvider extends WC_Address_Provider {
⋮----
private $jwt = null;
⋮----
public function __construct() {
⋮----
abstract public function get_address_service_jwt();
⋮----
public function can_telemetry() {
⋮----
public function load_jwt() {
⋮----
if ( $this->jwt && is_string( $this->jwt ) && JsonWebToken::shallow_validate( $this->jwt ) ) {
⋮----
$cached_jwt = $this->get_cached_option( 'address_autocomplete_jwt' );
⋮----
if ( $cached_jwt && is_string( $cached_jwt ) && JsonWebToken::shallow_validate( $cached_jwt ) ) {
⋮----
$retry_data = $this->get_cached_option( 'jwt_retry_data' );
⋮----
$fresh_jwt = $this->get_address_service_jwt();
if ( $fresh_jwt && is_string( $fresh_jwt ) && JsonWebToken::shallow_validate( $fresh_jwt ) ) {
$this->set_jwt( $fresh_jwt );
⋮----
... (57 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/AddressProvider/AddressProviderController.php">
namespace Automattic\WooCommerce\Internal\AddressProvider;
⋮----
use WC_Address_Provider;
⋮----
class AddressProviderController {
⋮----
private $providers = array();
⋮----
private $preferred_provider_option = '';
⋮----
/**
	 * Constructor.
	 *
	 * @internal
	 */
public function __construct() {
⋮----
final public function init() {
⋮----
$this->providers                 = $this->get_registered_providers();
⋮----
/**
	 * Get the registered providers.
	 *
	 * @return WC_Address_Provider[] array of WC_Address_Providers.
	 */
public function get_providers(): array {
⋮----
/**
	 * Get all registered providers.
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/EmailImprovements/EmailImprovements.php">
namespace Automattic\WooCommerce\Internal\Admin\EmailImprovements;
⋮----
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use WC_Tracker;
⋮----
class EmailImprovements {
⋮----
public function __construct() {
⋮----
public static function has_email_templates_overridden() {
$all_template_overrides = WC_Tracker::get_all_template_overrides();
$core_email_overrides   = self::get_core_email_overrides( $all_template_overrides );
⋮----
public static function is_email_customizer_enabled() {
$all_plugins    = WC_Tracker::get_all_plugins();
⋮----
public static function is_email_improvements_enabled_for_existing_stores() {
$is_feature_enabled             = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
public static function should_enable_email_improvements_for_existing_stores() {
if ( FeaturesUtil::feature_is_enabled( 'email_improvements' ) ) {
⋮----
if ( self::has_email_templates_overridden() ) {
⋮----
if ( self::is_email_customizer_enabled() ) {
⋮----
public static function should_notify_merchant_about_email_improvements() {
return ! FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
public static function add_email_improvements_modal_to_url() {
... (31 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/EmailPreview/EmailPreview.php">
namespace Automattic\WooCommerce\Internal\Admin\EmailPreview;
⋮----
use Automattic\WooCommerce\Internal\EmailEditor\WooContentProcessor;
use Automattic\WooCommerce\Enums\OrderStatus;
use Throwable;
use WC_Email;
use WC_Order;
use WC_Order_Item_Product;
use WC_Order_Item_Shipping;
use WC_Product;
use WC_Product_Download;
use WC_Product_Variation;
use WP_User;
⋮----
class EmailPreview {
⋮----
private static array $email_style_setting_ids = array(
⋮----
private static array $email_content_setting_ids = array();
⋮----
private static bool $email_setting_ids_initialized = false;
⋮----
private ?string $email_type = null;
⋮----
private ?WC_Email $email = null;
⋮----
protected static $instance = null;
⋮----
private bool $locale_switched = false;
⋮----
... (212 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/EmailPreview/EmailPreviewRestController.php">
namespace Automattic\WooCommerce\Internal\Admin\EmailPreview;
⋮----
use Automattic\WooCommerce\Internal\RestApiControllerBase;
use WP_Error;
use WP_REST_Request;
⋮----
class EmailPreviewRestController extends RestApiControllerBase {
⋮----
private EmailPreview $email_preview;
⋮----
protected string $route_namespace = 'wc-admin-email';
⋮----
protected string $rest_base = 'settings/email';
⋮----
protected function get_rest_api_namespace(): string {
⋮----
public function __construct() {
$this->email_preview = wc_get_container()->get( EmailPreview::class );
⋮----
public function register_routes() {
⋮----
'callback'            => fn( $request ) => $this->send_email_preview( $request ),
'permission_callback' => fn( $request ) => $this->check_permissions( $request ),
'args'                => $this->get_args_for_send_preview(),
'schema'              => $this->get_schema_with_message(),
⋮----
'subject' => $this->email_preview->get_subject(),
⋮----
'args'                => $this->get_args_for_preview_subject(),
'schema'              => $this->get_schema_for_preview_subject(),
... (46 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/EmailPreview/PreviewOrder.php">
namespace Automattic\WooCommerce\Internal\Admin\EmailPreview;
⋮----
use WC_Order;
⋮----
class PreviewOrder extends WC_Order {
⋮----
public function __construct( $order = 0 ) {
parent::__construct( $order );
⋮----
public function get_order_number() {
⋮----
public function save() {
wc_get_logger()->warning(
⋮----
return $this->get_id();
⋮----
public function save_meta_data(): void {
⋮----
public function delete( $force_delete = false ) {
⋮----
public function get_customer_order_notes() {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Emails/EmailListingRestController.php">
namespace Automattic\WooCommerce\Internal\Admin\Emails;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\RestApiControllerBase;
use Automattic\WooCommerce\Internal\EmailEditor\Integration;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailScratchpadRefresher;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmails;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsGenerator;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsManager;
use WP_Error;
use WP_REST_Request;
⋮----
class EmailListingRestController extends RestApiControllerBase {
⋮----
protected string $route_namespace = 'wc-admin-email';
⋮----
protected string $rest_base = 'settings/email/listing';
⋮----
private $email_template_generator;
⋮----
protected function get_rest_api_namespace(): string {
⋮----
private $scratchpad_refresher;
⋮----
public function __construct() {
⋮----
public function initialize_template_generator() {
⋮----
public function register_routes() {
⋮----
... (43 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ImportExport/CSVUploadHelper.php">
namespace Automattic\WooCommerce\Internal\Admin\ImportExport;
⋮----
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
⋮----
class CSVUploadHelper {
⋮----
protected function get_import_subdir_name(): string {
⋮----
public function get_import_dir( bool $create = true ): string {
⋮----
throw new \Exception( esc_html( $wp_upload_dir['error'] ) );
⋮----
$upload_dir = trailingslashit( $wp_upload_dir['basedir'] ) . $this->get_import_subdir_name();
⋮----
FilesystemUtil::mkdir_p_not_indexable( $upload_dir );
⋮----
public function handle_csv_upload( string $import_type, string $files_index = 'import', ?array $allowed_mime_types = null ): array {
⋮----
throw new \Exception( 'Import type is invalid.' );
⋮----
throw new \Exception( esc_html__( 'File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.', 'woocommerce' ) );
⋮----
$this->get_import_dir();
⋮----
throw new \Exception( esc_html( $upload['error'] ) );
⋮----
throw new \Exception( esc_html__( 'Invalid file type for a CSV import.', 'woocommerce' ) );
⋮----
public function override_upload_dir( $uploads ): array {
$new_subdir = '/' . $this->get_import_subdir_name();
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Logging/FileV2/File.php">
namespace Automattic\WooCommerce\Internal\Admin\Logging\FileV2;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
use Exception;
⋮----
class File {
⋮----
protected $path;
⋮----
protected $source = '';
⋮----
/**
	 * The 0-based increment of the file, if it has been rotated. Derived from the filename. Can only be 0-9.
	 *
	 * @var int|null
	 */
protected $rotation;
⋮----
/**
	 * The date the file was created, as a Unix timestamp, derived from the filename.
	 *
	 * @var int
	 */
protected $created = 0;
⋮----
/**
	 * The hash property of the file, derived from the filename.
	 *
	 * @var string
... (120 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Logging/FileV2/FileController.php">
namespace Automattic\WooCommerce\Internal\Admin\Logging\FileV2;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Logging\Settings;
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
use Exception;
use PclZip;
use WC_Cache_Helper;
use WP_Error;
⋮----
class FileController {
⋮----
/**
	 * Default values for arguments for the search_within_files method.
	 *
	 * @const array
	 */
⋮----
private function get_file_size_limit(): int {
⋮----
public function write_to_file( string $source, string $text, ?int $time = null ): bool {
⋮----
$path = Settings::get_log_directory() . $this->generate_filename( $source, $time );
⋮----
$size = $file->get_file_size();
if ( false !== $size && $size >= $this->get_file_size_limit() ) {
if ( ! $this->rotate_file( $file ) ) {
⋮----
return $file->write( $text );
⋮----
... (135 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Logging/FileV2/FileExporter.php">
namespace Automattic\WooCommerce\Internal\Admin\Logging\FileV2;
⋮----
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
use Exception;
use WP_Error;
⋮----
class FileExporter {
⋮----
private $path;
⋮----
private $alternate_filename;
⋮----
public function __construct( string $path, string $alternate_filename = '' ) {
⋮----
/**
	 * Configure PHP and stream the file to the browser.
	 *
	 * @return WP_Error|void Only returns something if there is an error.
	 */
public function emit_file() {
⋮----
$filesystem  = FilesystemUtil::get_wp_filesystem_direct();
$is_readable = $filesystem->is_file( $this->path ) && $filesystem->is_readable( $this->path );
⋮----
@ini_set( 'output_handler', '' ); // phpcs:ignore WordPress.PHP.IniSet.Risky
⋮----
// phpcs:enable WordPress.PHP.NoSilencedErrors.Discouraged
⋮----
$this->send_headers();
$this->send_contents();
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Logging/FileV2/FileListTable.php">
namespace Automattic\WooCommerce\Internal\Admin\Logging\FileV2;
⋮----
use Automattic\WooCommerce\Internal\Admin\Logging\PageController;
⋮----
use WP_List_Table;
⋮----
class FileListTable extends WP_List_Table {
⋮----
private $file_controller;
⋮----
private $page_controller;
⋮----
public function __construct( FileController $file_controller, PageController $page_controller ) {
⋮----
parent::__construct(
⋮----
public function no_items(): void {
⋮----
protected function get_bulk_actions(): array {
⋮----
protected function get_sources_list(): array {
$sources = $this->file_controller->get_file_sources();
⋮----
protected function extra_tablenav( $which ): void {
$all_sources = $this->get_sources_list();
⋮----
$current_source = File::sanitize_source( wp_unslash( $_GET['source'] ?? '' ) );
⋮----
public function prepare_column_headers(): void {
⋮----
... (59 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Logging/FileV2/SearchListTable.php">
namespace Automattic\WooCommerce\Internal\Admin\Logging\FileV2;
⋮----
use Automattic\WooCommerce\Internal\Admin\Logging\PageController;
⋮----
use WP_List_Table;
⋮----
class SearchListTable extends WP_List_Table {
⋮----
private $file_controller;
⋮----
private $page_controller;
⋮----
public function __construct( FileController $file_controller, PageController $page_controller ) {
⋮----
parent::__construct(
⋮----
public function no_items(): void {
⋮----
public function prepare_column_headers(): void {
⋮----
$this->get_columns(),
⋮----
$this->get_primary_column(),
⋮----
public function prepare_items(): void {
$per_page = $this->get_items_per_page(
⋮----
$this->get_per_page_default()
⋮----
'offset'   => ( $this->get_pagenum() - 1 ) * $per_page,
... (24 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Logging/LogHandlerFileV2.php">
namespace Automattic\WooCommerce\Internal\Admin\Logging;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\{ File, FileController };
use WC_Log_Handler;
⋮----
class LogHandlerFileV2 extends WC_Log_Handler {
⋮----
private $file_controller;
⋮----
public function __construct() {
$this->file_controller = wc_get_container()->get( FileController::class );
⋮----
public function handle( $timestamp, $level, $message, $context ) {
⋮----
$source = $this->determine_source();
⋮----
$entry = static::format_entry( $timestamp, $level, $message, $context );
⋮----
$written = $this->file_controller->write_to_file( $source, $entry, $timestamp );
⋮----
$this->file_controller->invalidate_cache();
⋮----
protected static function format_entry( $timestamp, $level, $message, $context ) {
$time_string  = static::format_time( $timestamp );
⋮----
$context['backtrace'] = static::get_backtrace();
⋮----
protected function determine_source(): string {
⋮----
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Logging/PageController.php">
namespace Automattic\WooCommerce\Internal\Admin\Logging;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Logging\{ LogHandlerFileV2, Settings };
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\{ File, FileController, FileListTable, SearchListTable };
use WC_Admin_Status;
use WC_Log_Handler_File, WC_Log_Handler_DB;
use WC_Log_Levels;
use WP_List_Table;
⋮----
class PageController {
⋮----
private $file_controller;
⋮----
private $settings;
⋮----
private $list_table;
⋮----
final public function init(
⋮----
$this->init_hooks();
⋮----
private function init_hooks(): void {
⋮----
public function maybe_do_logs_tab_action(): void {
⋮----
$params = $this->get_query_params( array( 'view' ) );
⋮----
public function notices() {
if ( ! $this->settings->logging_is_enabled() ) {
... (128 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Logging/Settings.php">
namespace Automattic\WooCommerce\Internal\Admin\Logging;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\File;
use Automattic\WooCommerce\Internal\Admin\Logging\LogHandlerFileV2;
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\FileController;
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Exception;
use WC_Admin_Settings;
use WC_Log_Handler_DB, WC_Log_Handler_File, WC_Log_Levels;
⋮----
class Settings {
⋮----
public function __construct() {
⋮----
public static function get_log_directory( bool $create_dir = true ): string {
if ( true === Constants::get_constant( 'WC_LOG_DIR_CUSTOM' ) ) {
$dir = Constants::get_constant( 'WC_LOG_DIR' );
⋮----
$upload_dir = wc_get_container()->get( LegacyProxy::class )->call_function( 'wp_upload_dir', null, $create_dir );
⋮----
$filesystem = FilesystemUtil::get_wp_filesystem_direct();
$filesystem->put_contents( $dir . '.htaccess', 'deny from all' );
$filesystem->put_contents( $dir . 'index.html', '' );
⋮----
// Best-effort: the directory exists and stays usable without the no-listing files, but log a trace.
error_log( 'WooCommerce: could not write log directory protection files: ' . $exception->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
⋮----
/**
... (82 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Marketing/MarketingSpecs.php">
namespace Automattic\WooCommerce\Internal\Admin\Marketing;
⋮----
class MarketingSpecs {
⋮----
public function get_knowledge_base_posts( ?string $topic ): array {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/CustomizeStoreWithBlocks.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class CustomizeStoreWithBlocks {
⋮----
public static function get_note() {
⋮----
if ( ! self::is_wc_admin_active_in_date_range( 'week-1-4', 14 * DAY_IN_SECONDS ) ) {
⋮----
$query    = new \WC_Product_Query(
⋮----
$products = $query->get_products();
⋮----
$note->set_title( __( 'Customize your online store with WooCommerce blocks', 'woocommerce' ) );
$note->set_content( __( 'With our blocks, you can select and display products, categories, filters, and more virtually anywhere on your site — no need to use shortcodes or edit lines of code. Learn more about how to use each one of them.', 'woocommerce' ) );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_content_data( (object) array() );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/CustomizingProductCatalog.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
use Automattic\WooCommerce\Enums\ProductStatus;
⋮----
class CustomizingProductCatalog {
⋮----
public static function get_note() {
$query = new \WC_Product_Query(
⋮----
$products = $query->get_products();
⋮----
$created_timestamp = $product->get_date_created()->getTimestamp();
⋮----
if ( self::wc_admin_active_for( DAY_IN_SECONDS * 14 ) ) {
⋮----
$note->set_title( __( 'How to customize your product catalog', 'woocommerce' ) );
$note->set_content( __( 'You want your product catalog and images to look great and align with your brand. This guide will give you all the tips you need to get your products looking great in your store.', 'woocommerce' ) );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_content_data( (object) array() );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/EditProductsOnTheMove.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class EditProductsOnTheMove {
⋮----
public static function get_note() {
⋮----
if ( ! self::wc_admin_active_for( $year_in_seconds ) ) {
⋮----
if ( MobileApp::has_note_been_actioned() ) {
⋮----
if ( RealTimeOrderAlerts::has_note_been_actioned() ) {
⋮----
if ( ManageOrdersOnTheGo::has_note_been_actioned() ) {
⋮----
if ( PerformanceOnMobile::has_note_been_actioned() ) {
⋮----
$note->set_title( __( 'Edit products on the move', 'woocommerce' ) );
$note->set_content( __( 'Edit and create new products from your mobile devices with the Woo app', 'woocommerce' ) );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/EmailImprovements.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
use Automattic\WooCommerce\Internal\Admin\EmailImprovements\EmailImprovements as EmailImprovementsFeature;
⋮----
class EmailImprovements {
⋮----
public static function get_note() {
if ( EmailImprovementsFeature::is_email_improvements_enabled_for_existing_stores() ) {
return self::get_email_improvements_enabled_note();
⋮----
if ( EmailImprovementsFeature::should_notify_merchant_about_email_improvements() ) {
return self::get_try_email_improvements_note();
⋮----
private static function get_email_improvements_enabled_note() {
⋮----
$note->set_title( __( 'Your store emails have had an upgrade!', 'woocommerce' ) );
$note->set_content( __( 'We’ve made some exciting improvements to your email templates, including modern, shopper-friendly designs and new customization options. And if you’re using a block theme, you can automatically sync your theme styles! Head to your email settings to explore the new changes.', 'woocommerce' ) );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
⋮----
private static function get_try_email_improvements_note() {
⋮----
$note->set_title( __( 'Store emails have had an upgrade!', 'woocommerce' ) );
$note->set_content( __( 'We’ve made some exciting improvements to our email templates, including modern, shopper-friendly designs and new customization options. And if you’re using a block theme, you can automatically sync your theme styles! Head to your email settings to explore the new features.', 'woocommerce' ) );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/EUVATNumber.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class EUVATNumber {
⋮----
public static function get_note() {
⋮----
$country_code = WC()->countries->get_base_country();
$eu_countries = WC()->countries->get_european_union_countries();
⋮----
$note->set_title( __( 'Collect and validate EU VAT numbers at checkout', 'woocommerce' ) );
$note->set_content( $content );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_MARKETING );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/FirstProduct.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
use Automattic\WooCommerce\Enums\ProductStatus;
⋮----
class FirstProduct {
⋮----
public static function get_note() {
⋮----
if ( ! self::is_wc_admin_active_in_date_range( 'week-1-4' ) ) {
⋮----
$query    = new \WC_Product_Query(
⋮----
$products = $query->get_products();
⋮----
$note->set_title( __( 'Do you need help with adding your first product?', 'woocommerce' ) );
$note->set_content( __( 'This video tutorial will help you go through the process of adding your first product in WooCommerce.', 'woocommerce' ) );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_content_data( (object) array() );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/FullRefundFixDataToolNotice.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class FullRefundFixDataToolNotice {
⋮----
public static function is_applicable() {
if ( ! FeaturesUtil::feature_is_enabled( 'analytics' ) ) {
⋮----
return ! OrderUtil::uses_new_full_refund_data();
⋮----
public static function get_note() {
if ( ! self::is_applicable() ) {
⋮----
$note->set_title( __( 'Fix your refund data in Analytics', 'woocommerce' ) );
$note->set_content(
⋮----
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_WARNING );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
⋮----
$note->add_action(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/GivingFeedbackNotes.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
use Automattic\WooCommerce\Internal\Admin\Survey;
⋮----
class GivingFeedbackNotes {
⋮----
public static function get_note() {
if ( ! self::is_wc_admin_active_in_date_range( 'week-1-4' ) ) {
⋮----
$note->set_title( __( 'You\'re invited to share your experience', 'woocommerce' ) );
$note->set_content( __( 'Now that you’ve chosen us as a partner, our goal is to make sure we\'re providing the right tools to meet your needs. We\'re looking forward to having your feedback on the store setup experience so we can improve it in the future.', 'woocommerce' ) );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
⋮----
Survey::get_url( '/store-setup-survey' )
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/InstallJPAndWCSPlugins.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
use Automattic\WooCommerce\Admin\PluginsHelper;
⋮----
class InstallJPAndWCSPlugins {
⋮----
public function __construct() {
⋮----
public static function get_note() {
⋮----
$note->set_title( __( 'Uh oh... There was a problem during the Jetpack and WooCommerce Shipping & Tax install. Please try again.', 'woocommerce' ) );
$note->set_content( $content );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
⋮----
public static function action_note() {
⋮----
$active_plugin_slugs = PluginsHelper::get_active_plugin_slugs();
⋮----
$data_store = Notes::load_data_store();
$note_ids   = $data_store->get_notes_with_name( self::NOTE_NAME );
⋮----
$note = Notes::get_note( $note_id );
⋮----
... (20 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/LaunchChecklist.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class LaunchChecklist {
⋮----
public static function get_note() {
⋮----
self::is_wc_admin_active_in_date_range( 'week-1-4', $ten_days_in_seconds )
⋮----
$note->set_title( __( 'Ready to launch your store?', 'woocommerce' ) );
$note->set_content( $content );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action( 'learn-more', __( 'Learn more', 'woocommerce' ), 'https://woocommerce.com/posts/pre-launch-checklist-the-essentials/?utm_source=inbox&utm_medium=product' );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/MagentoMigration.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
⋮----
use Automattic\WooCommerce\Admin\Features\Onboarding;
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class MagentoMigration {
⋮----
public function __construct() {
⋮----
public static function possibly_add_note() {
⋮----
WC()->queue()->schedule_single( time() + ( 5 * MINUTE_IN_SECONDS ), 'woocommerce_admin_magento_migration_note' );
⋮----
public static function save_note() {
$note = self::get_note();
⋮----
if ( self::note_exists() ) {
⋮----
$note->save();
⋮----
public static function get_note() {
⋮----
$note->set_title( __( 'How to Migrate from Magento to WooCommerce', 'woocommerce' ) );
$note->set_content( __( 'Changing platforms might seem like a big hurdle to overcome, but it is easier than you might think to move your products, customers, and orders to WooCommerce. This article will help you with going through this process.', 'woocommerce' ) );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/ManageOrdersOnTheGo.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class ManageOrdersOnTheGo {
⋮----
public static function get_note() {
⋮----
if ( ! self::is_wc_admin_active_in_date_range( 'month-6+' ) ) {
⋮----
if ( MobileApp::has_note_been_actioned() ) {
⋮----
if ( RealTimeOrderAlerts::has_note_been_actioned() ) {
⋮----
$note->set_title( __( 'Manage your orders on the go', 'woocommerce' ) );
$note->set_content( __( 'Look for orders, customer info, and process refunds in one click with the Woo app.', 'woocommerce' ) );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/MarketingJetpack.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
use Automattic\WooCommerce\Admin\PluginsHelper;
⋮----
class MarketingJetpack {
⋮----
public static function possibly_add_note() {
⋮----
$installed_plugins = PluginsHelper::get_installed_plugin_slugs();
⋮----
$data_store = \WC_Data_Store::load( 'admin-note' );
⋮----
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
⋮----
$note    = Notes::get_note( $note_id );
⋮----
if ( self::has_backups() && Note::E_WC_ADMIN_NOTE_ACTIONED !== $note->get_status() ) {
$note->set_status( Note::E_WC_ADMIN_NOTE_ACTIONED );
$note->save();
⋮----
if ( ! self::is_wc_admin_active_in_date_range( 'week-1-4', DAY_IN_SECONDS * 3 ) || ! self::can_be_added() || self::has_backups() ) {
⋮----
$note = self::get_note();
⋮----
public static function get_note() {
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/MigrateFromShopify.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class MigrateFromShopify {
⋮----
public static function get_note() {
⋮----
if ( ! self::is_wc_admin_active_in_date_range( 'week-1', $two_days ) ) {
⋮----
$note->set_title( __( 'Do you want to migrate from Shopify to WooCommerce?', 'woocommerce' ) );
$note->set_content( __( 'Changing eCommerce platforms might seem like a big hurdle to overcome, but it is easier than you might think to move your products, customers, and orders to WooCommerce. This article will help you with going through this process.', 'woocommerce' ) );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_content_data( (object) array() );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/MobileApp.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class MobileApp {
⋮----
public static function get_note() {
⋮----
if ( ! self::is_wc_admin_active_in_date_range( 'week-1', $two_days_in_seconds ) ) {
⋮----
$note->set_title( __( 'Install Woo mobile app', 'woocommerce' ) );
$note->set_content( $content );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action( 'learn-more', __( 'Learn more', 'woocommerce' ), 'https://woocommerce.com/mobile/?utm_medium=product' );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/NewSalesRecord.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class NewSalesRecord {
⋮----
public static function sum_sales_for_date( $date ) {
$order_query = new \WC_Order_Query( array( 'date_created' => $date ) );
$orders      = $order_query->get_orders();
⋮----
$total += $order->get_total();
⋮----
public static function possibly_add_note() {
⋮----
$total     = self::sum_sales_for_date( $yesterday );
⋮----
// No previous entry? Just enter what we have and return without generating a note.
⋮----
// Otherwise, if yesterdays total bested the record, update AND generate a note.
⋮----
// We only want one sales record note at any time in the inbox, so we delete any other first.
Notes::delete_notes_with_name( self::NOTE_NAME );
⋮----
$note = self::get_note_with_record_data( $record_date, $record_amt, $yesterday, $total );
$note->save();
⋮----
/**
	 * Get the note with record data.
... (24 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/NoteActionForbiddenException.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
class NoteActionForbiddenException extends \Exception {}
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/OnboardingPayments.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class OnboardingPayments {
⋮----
public static function get_note() {
⋮----
if ( ! self::is_wc_admin_active_in_date_range( 'week-1-4', 5 * DAY_IN_SECONDS ) ) {
⋮----
$gateways         = WC()->payment_gateways->get_available_payment_gateways();
⋮----
$note->set_title( __( 'Start accepting payments on your store!', 'woocommerce' ) );
$note->set_content( __( 'Take payments with the provider that’s right for you - choose from 100+ payment gateways for WooCommerce.', 'woocommerce' ) );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_content_data( (object) array() );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/OnlineClothingStore.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class OnlineClothingStore {
⋮----
private static function is_in_fashion_industry( $industries ) {
⋮----
public static function get_note() {
⋮----
if ( ! self::is_wc_admin_active_in_date_range( 'week-1', 2 * DAY_IN_SECONDS ) ) {
⋮----
if ( ! self::is_in_fashion_industry( $onboarding_profile['industry'] ) ) {
⋮----
$note->set_title( __( 'Start your online clothing store', 'woocommerce' ) );
$note->set_content( __( 'Starting a fashion website is exciting but it may seem overwhelming as well. In this article, we\'ll walk you through the setup process, teach you to create successful product listings, and show you how to market to your ideal audience.', 'woocommerce' ) );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_content_data( (object) array() );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/OrderMilestones.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\Notes;
⋮----
class OrderMilestones {
⋮----
protected $allowed_statuses = array(
⋮----
protected $orders_count = null;
⋮----
protected $milestones = array(
⋮----
public function __construct() {
⋮----
public function init() {
⋮----
public function clear_scheduled_event() {
⋮----
public function get_orders_count( $no_cache = false ) {
⋮----
public function backfill_last_milestone() {
⋮----
if ( ! $this->are_milestones_enabled() ) {
⋮----
$this->set_last_milestone( $this->get_current_milestone() );
⋮----
public function get_last_milestone() {
⋮----
public function set_last_milestone( $milestone ) {
... (69 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/PaymentsMoreInfoNeeded.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
use Automattic\WooCommerce\Internal\Admin\WcPayWelcomePage;
⋮----
class PaymentsMoreInfoNeeded {
⋮----
public static function is_applicable() {
return self::should_display_note();
⋮----
public static function should_display_note() {
⋮----
if ( WcPayWelcomePage::instance()->has_incentive() ) {
⋮----
public static function get_note() {
if ( ! self::should_display_note() ) {
⋮----
$note->set_title( sprintf( __( 'Payments made simple with %s', 'woocommerce' ), 'WooPayments' ) );
$note->set_content( $content );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action( 'learn-more', __( 'Learn more here', 'woocommerce' ), 'https://woocommerce.com/payments/' );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/PaymentsRemindMeLater.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
use Automattic\WooCommerce\Internal\Admin\WcPayWelcomePage;
⋮----
class PaymentsRemindMeLater {
⋮----
public static function is_applicable() {
return self::should_display_note();
⋮----
public static function should_display_note() {
⋮----
if ( ! WcPayWelcomePage::instance()->has_incentive() ) {
⋮----
public static function get_note() {
if ( ! self::should_display_note() ) {
⋮----
$note->set_title( sprintf( __( 'Save big with %s', 'woocommerce' ), 'WooPayments' ) );
$note->set_content( $content );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action( 'learn-more', __( 'Learn more', 'woocommerce' ), admin_url( 'admin.php?page=wc-admin&path=/wc-pay-welcome-page' ) );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/PerformanceOnMobile.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class PerformanceOnMobile {
⋮----
public static function get_note() {
⋮----
if ( ! self::wc_admin_active_for( $nine_months_in_seconds ) ) {
⋮----
if ( MobileApp::has_note_been_actioned() ) {
⋮----
if ( RealTimeOrderAlerts::has_note_been_actioned() ) {
⋮----
if ( ManageOrdersOnTheGo::has_note_been_actioned() ) {
⋮----
$note->set_title( __( 'Track your store performance on mobile', 'woocommerce' ) );
$note->set_content( __( 'Monitor your sales and high performing products with the Woo app.', 'woocommerce' ) );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/PersonalizeStore.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class PersonalizeStore {
⋮----
public static function get_note() {
⋮----
if ( ! self::is_wc_admin_active_in_date_range( 'week-1-4', $five_days_in_seconds ) && ! $is_task_list_complete ) {
⋮----
$note->set_title( __( 'Personalize your store\'s homepage', 'woocommerce' ) );
$note->set_content( $content );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action( 'personalize-homepage', __( 'Personalize homepage', 'woocommerce' ), admin_url( 'post.php?post=' . $homepage_id . '&action=edit' ), Note::E_WC_ADMIN_NOTE_ACTIONED );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/RealTimeOrderAlerts.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class RealTimeOrderAlerts {
⋮----
public static function get_note() {
⋮----
if ( ! self::is_wc_admin_active_in_date_range( 'month-3-6' ) ) {
⋮----
if ( MobileApp::has_note_been_actioned() ) {
⋮----
$note->set_title( __( 'Get real-time order alerts anywhere', 'woocommerce' ) );
$note->set_content( $content );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action( 'learn-more', __( 'Learn more', 'woocommerce' ), 'https://woocommerce.com/mobile/?utm_source=inbox&utm_medium=product' );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/ScheduledUpdatesPromotion.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class ScheduledUpdatesPromotion {
⋮----
public function __construct() {
⋮----
public static function is_applicable() {
⋮----
public static function get_note() {
if ( ! self::is_applicable() ) {
⋮----
$note->set_title( __( 'Analytics now supports scheduled updates', 'woocommerce' ) );
$note->set_content( __( 'This provides improved performance to your store, enable it in Analytics > Settings.', 'woocommerce' ) );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
⋮----
$note->add_action(
⋮----
public function enable_scheduled_updates( $note ): void {
⋮----
if ( self::NOTE_NAME !== $note->get_name() ) {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/SellingOnlineCourses.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
⋮----
class SellingOnlineCourses {
⋮----
public function __construct() {
⋮----
public static function check_onboarding_profile( $old_value, $value, $option ) {
⋮----
self::possibly_add_note();
⋮----
public static function get_note() {
⋮----
$note->set_title( __( 'Do you want to sell online courses?', 'woocommerce' ) );
$note->set_content( __( 'Online courses are a great solution for any business that can teach a new skill. Since courses don’t require physical product development or shipping, they’re affordable, fast to create, and can generate passive income for years to come. In this article, we provide you more information about selling courses using WooCommerce.', 'woocommerce' ) );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_MARKETING );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/TrackingOptIn.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
use WC_Tracks;
⋮----
class TrackingOptIn {
⋮----
public function __construct() {
⋮----
public static function get_note() {
⋮----
if ( ! self::is_wc_admin_active_in_date_range( 'week-1-4' ) ) {
⋮----
$note->set_title( __( 'Help WooCommerce improve with usage tracking', 'woocommerce' ) );
$note->set_content( $note_content );
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action( 'tracking-opt-in', __( 'Activate usage tracking', 'woocommerce' ), false, Note::E_WC_ADMIN_NOTE_ACTIONED, true, __( 'Usage tracking activated', 'woocommerce' ) );
⋮----
public function opt_in_to_tracking( $note ) {
if ( self::NOTE_NAME === $note->get_name() ) {
⋮----
WC_Tracks::track_woocommerce_allow_tracking_toggled( $prev_value, 'yes', 'usage_tracking_note' );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/UnsecuredReportFiles.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
⋮----
class UnsecuredReportFiles {
⋮----
public static function get_note() {
⋮----
$note->set_title( __( 'Potentially unsecured files were found in your uploads directory', 'woocommerce' ) );
$note->set_content(
⋮----
$note->set_content_data( (object) array() );
$note->set_type( Note::E_WC_ADMIN_NOTE_ERROR );
$note->set_name( self::NOTE_NAME );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
⋮----
public static function possibly_add_note() {
$note = self::get_note();
⋮----
if ( self::note_exists() ) {
⋮----
$note->save();
⋮----
public static function note_exists() {
$data_store = \WC_Data_Store::load( 'admin-note' );
$note_ids   = $data_store->get_notes_with_name( self::NOTE_NAME );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/WooCommercePayments.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
⋮----
class WooCommercePayments {
⋮----
public function __construct() {
⋮----
public static function possibly_add_note() {
if ( ! self::is_wc_admin_active_in_date_range( 'week-1-4' ) || 'US' !== WC()->countries->get_base_country() ) {
⋮----
$data_store = Notes::load_data_store();
⋮----
$note_ids = $data_store->get_notes_with_name( self::NOTE_NAME );
⋮----
$note    = Notes::get_note( $note_id );
⋮----
if ( self::is_installed() && Note::E_WC_ADMIN_NOTE_ACTIONED !== $note->get_status() ) {
$note->set_status( Note::E_WC_ADMIN_NOTE_ACTIONED );
$note->save();
⋮----
$current_date = new \DateTime();
$publish_date = new \DateTime( '2020-04-14' );
⋮----
$note = self::get_note();
if ( self::can_be_added() ) {
⋮----
if ( ! WC()->queue()->get_next( $hook_name ) ) {
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/WooCommerceSubscriptions.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\NoteTraits;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
⋮----
class WooCommerceSubscriptions {
⋮----
public static function get_note() {
⋮----
if ( ! self::is_wc_admin_active_in_date_range( 'week-1', DAY_IN_SECONDS ) ) {
⋮----
$note->set_title( __( 'Do you need more info about WooCommerce Subscriptions?', 'woocommerce' ) );
$note->set_content( __( 'WooCommerce Subscriptions allows you to introduce a variety of subscriptions for physical or virtual products and services. Create product-of-the-month clubs, weekly service subscriptions or even yearly software billing packages. Add sign-up fees, offer free trials, or set expiration periods.', 'woocommerce' ) );
$note->set_type( Note::E_WC_ADMIN_NOTE_MARKETING );
$note->set_name( self::NOTE_NAME );
$note->set_content_data( (object) array() );
$note->set_source( 'woocommerce-admin' );
$note->add_action(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Notes/WooSubscriptionsNotes.php">
namespace Automattic\WooCommerce\Internal\Admin\Notes;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Admin\PageController;
⋮----
class WooSubscriptionsNotes {
⋮----
public function __construct() {
⋮----
public function update_option_woocommerce_helper_data( $old_value, $value ) {
⋮----
// The site just disconnected.
⋮----
$this->remove_notes();
⋮----
// The site is connected.
if ( $this->is_connected() ) {
⋮----
$this->refresh_subscription_notes();
⋮----
/**
	 * Runs on `admin_head` hook. Checks the connection and refreshes subscription notes on relevant pages.
	 */
public function admin_head() {
if ( ! PageController::is_admin_or_embed_page() ) {
// To avoid unnecessarily calling Helper API, we only want to refresh subscription notes,
// if the request is initiated from the wc admin dashboard or a WC related page which includes
// the Activity button in WC header.
⋮----
... (76 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Onboarding/Onboarding.php">
namespace Automattic\WooCommerce\Internal\Admin\Onboarding;
⋮----
class Onboarding {
⋮----
final public static function init() {
OnboardingHelper::instance()->init();
OnboardingIndustries::init();
OnboardingJetpack::instance()->init();
OnboardingMailchimp::instance()->init();
OnboardingProfile::init();
OnboardingSetupWizard::instance()->init();
OnboardingSync::instance()->init();
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Onboarding/OnboardingHelper.php">
namespace Automattic\WooCommerce\Internal\Admin\Onboarding;
⋮----
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskLists;
⋮----
class OnboardingHelper {
⋮----
private static $instance = null;
⋮----
final public static function instance() {
⋮----
public function init() {
⋮----
public function add_help_tab() {
⋮----
$help_tabs = $screen->get_help_tabs();
⋮----
$screen->remove_help_tab( 'woocommerce_onboard_tab' );
⋮----
$setup_list    = TaskLists::get_list( 'setup' );
$extended_list = TaskLists::get_list( 'extended' );
⋮----
if ( ! $setup_list->is_complete() ) {
⋮----
( $setup_list->is_hidden()
⋮----
( $extended_list->is_hidden()
⋮----
$screen->add_help_tab( $help_tab );
⋮----
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Onboarding/OnboardingIndustries.php">
namespace Automattic\WooCommerce\Internal\Admin\Onboarding;
⋮----
class OnboardingIndustries {
⋮----
public static function init() {
⋮----
public static function get_allowed_industries() {
⋮----
public static function preload_data( $settings ) {
$settings['onboarding']['industries'] = self::get_allowed_industries();
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Onboarding/OnboardingJetpack.php">
namespace Automattic\WooCommerce\Internal\Admin\Onboarding;
⋮----
class OnboardingJetpack {
⋮----
private static $instance = null;
⋮----
final public static function instance() {
⋮----
public function init() {
⋮----
public function set_woocommerce_setup_jetpack_opted_in() {
⋮----
public function activate_and_install_jetpack_ahead_of_wcpay( $plugins ) {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Onboarding/OnboardingMailchimp.php">
namespace Automattic\WooCommerce\Internal\Admin\Onboarding;
⋮----
use Automattic\WooCommerce\Internal\Admin\Schedulers\MailchimpScheduler;
⋮----
class OnboardingMailchimp {
⋮----
private static $instance = null;
⋮----
final public static function instance() {
⋮----
public function init() {
⋮----
public function on_profile_data_updated( $existing_data, $updating_data ) {
⋮----
MailchimpScheduler::reset();
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Onboarding/OnboardingProducts.php">
namespace Automattic\WooCommerce\Internal\Admin\Onboarding;
⋮----
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Admin\Loader;
use Automattic\WooCommerce\Admin\PluginsHelper;
⋮----
class OnboardingProducts {
⋮----
public static function get_allowed_product_types() {
⋮----
public static function get_product_data( $product_types ) {
⋮----
public static function get_product_types_with_data() {
return self::get_product_data( self::get_allowed_product_types() );
⋮----
public static function get_relevant_products() {
⋮----
$installed     = PluginsHelper::get_installed_plugin_slugs();
⋮----
$product_data  = self::get_product_types_with_data();
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Onboarding/OnboardingProfile.php">
namespace Automattic\WooCommerce\Internal\Admin\Onboarding;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskLists;
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Admin\WCAdminHelper;
⋮----
class OnboardingProfile {
⋮----
public static function init() {
⋮----
public static function trigger_complete( $old_value, $value ) {
⋮----
public static function needs_completion() {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Onboarding/OnboardingSetupWizard.php">
namespace Automattic\WooCommerce\Internal\Admin\Onboarding;
⋮----
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Admin\WCAdminHelper;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskLists;
use Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions\Init;
use Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions\ProcessCoreProfilerPluginInstallOptions;
⋮----
class OnboardingSetupWizard {
⋮----
private static $instance = null;
⋮----
final public static function instance() {
⋮----
public function init() {
⋮----
$this->install_options_for_core_profiler_plugin_install( $slug, $source );
⋮----
private function is_running_from_async_action_scheduler() {
⋮----
return \wc_is_running_from_async_action_scheduler();
⋮----
public function do_admin_redirects() {
⋮----
if ( $this->is_running_from_async_action_scheduler() ) {
⋮----
public function trigger_profile_completed_action( $old_value, $value ) {
⋮----
private function should_show() {
... (40 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Onboarding/OnboardingSync.php">
namespace Automattic\WooCommerce\Internal\Admin\Onboarding;
⋮----
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskLists;
⋮----
class OnboardingSync {
⋮----
private static $instance = null;
⋮----
final public static function instance() {
⋮----
public function init() {
⋮----
private function send_profile_data() {
⋮----
$auth = \WC_Helper_Options::get( 'auth' );
⋮----
\WC_Helper_API::put(
⋮----
public function send_profile_data_on_update( $old_value, $value ) {
⋮----
$this->send_profile_data();
⋮----
public function send_profile_data_on_connect() {
⋮----
public function redirect_wccom_install() {
$task_list = TaskLists::get_list( 'setup' );
⋮----
$task_list->is_hidden() ||
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Orders/MetaBoxes/CustomerHistory.php">
namespace Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore as CustomersDataStore;
use Automattic\WooCommerce\Admin\API\Reports\Customers\Query as CustomersQuery;
use Automattic\WooCommerce\Admin\Overrides\Order as AdminOrder;
use Automattic\WooCommerce\Internal\Admin\Settings;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\Utilities\OrderUtil;
use WC_Order;
⋮----
class CustomerHistory {
⋮----
private $excluded_statuses = null;
⋮----
public function output( WC_Order $order ): void {
⋮----
if ( 'auto-draft' === $order->get_status() ) {
⋮----
$customer_history = $this->get_customer_history( $order );
⋮----
private function get_customer_history( WC_Order $order ): array {
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
$customer_id   = $order->get_customer_id();
$billing_email = $order->get_billing_email();
$result        = $this->query_hpos( $customer_id, $billing_email );
⋮----
$customer_report_id = $this->get_cpt_report_customer_id( $order );
⋮----
$result = $this->query_cpt( $customer_report_id );
⋮----
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Orders/MetaBoxes/CustomMetaBox.php">
namespace Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes;
⋮----
use Automattic\WooCommerce\Internal\DataStores\CustomMetaDataStore;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStoreMeta;
use WC_Order;
use WP_Ajax_Response;
⋮----
class CustomMetaBox {
⋮----
private $update_nonce;
⋮----
private function get_formatted_order_meta_data( \WC_Order $order ) {
$metadata         = $order->get_meta_data();
⋮----
$data = $meta->get_data();
⋮----
public function output( $order_or_post ) {
⋮----
$this->render_custom_meta_form( $this->get_formatted_order_meta_data( $order ), $order );
⋮----
private function render_custom_meta_form( array $metadata_to_list, \WC_Order $order ) {
⋮----
$this->render_meta_form( $order );
⋮----
public function order_meta_keys_autofill( $deprecated, $order ) {
⋮----
$keys  = wc_get_container()->get( OrdersTableDataStoreMeta::class )->get_meta_keys( $limit );
⋮----
public function render_meta_form( \WC_Order $order ) : void {
⋮----
... (61 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Orders/MetaBoxes/OrderAttribution.php">
namespace Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes;
⋮----
use Automattic\WooCommerce\Internal\Traits\OrderAttributionMeta;
use WC_Order;
⋮----
class OrderAttribution {
⋮----
public function __construct() {
$this->set_fields_and_prefix();
⋮----
public function format_meta_data( array &$meta ) {
⋮----
public function output( WC_Order $order ) {
$meta = $this->filter_meta_data( $order->get_meta_data() );
⋮----
$this->format_meta_data( $meta );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Orders/MetaBoxes/TaxonomiesMetaBox.php">
namespace Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes;
⋮----
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
⋮----
class TaxonomiesMetaBox {
⋮----
private $orders_table_data_store;
⋮----
public function init( OrdersTableDataStore $orders_table_data_store ) {
⋮----
public function add_taxonomies_meta_boxes( string $screen_id, string $order_type ) {
⋮----
public function save_taxonomies( \WC_Abstract_Order $order, $taxonomy_input ) {
⋮----
$sanitized_tax_input = $this->sanitize_tax_input( $taxonomy_input );
⋮----
$sanitized_tax_input = $this->orders_table_data_store->init_default_taxonomies( $order, $sanitized_tax_input );
$this->orders_table_data_store->set_custom_taxonomies( $order, $sanitized_tax_input );
⋮----
private function sanitize_tax_input( $taxonomy_data ) : array {
⋮----
public function order_categories_meta_box( $order, $box ) {
$post = get_post( $order->get_id() );
⋮----
public function order_tags_meta_box( $order, $box ) {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Orders/COTRedirectionController.php">
namespace Automattic\WooCommerce\Internal\Admin\Orders;
⋮----
class COTRedirectionController {
⋮----
public function setup(): void {
⋮----
public function handle_hpos_admin_requests( $query_params = null ) {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Orders/Edit.php">
namespace Automattic\WooCommerce\Internal\Admin\Orders;
⋮----
use Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes\CustomerHistory;
use Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes\CustomMetaBox;
use Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes\OrderAttribution;
use Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes\TaxonomiesMetaBox;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Utilities\OrderUtil;
use WC_Order;
⋮----
class Edit {
⋮----
private $screen_id;
⋮----
private $custom_meta_box;
⋮----
private $taxonomies_meta_box;
⋮----
private $order;
⋮----
private $current_action;
⋮----
private $message;
⋮----
private $orders_page_controller;
⋮----
public static function add_order_meta_boxes( string $screen_id, string $title ) {
⋮----
self::maybe_register_order_attribution( $screen_id, $title );
⋮----
... (107 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Orders/EditLock.php">
namespace Automattic\WooCommerce\Internal\Admin\Orders;
⋮----
class EditLock {
⋮----
public function get_lock( \WC_Order $order ) {
$lock = $order->get_meta( self::META_KEY_NAME, true, 'edit' );
⋮----
public function is_locked_by_another_user( \WC_Order $order ) : bool {
$lock = $this->get_lock( $order );
⋮----
public function is_locked( \WC_Order $order ) : bool {
return (bool) $this->get_lock( $order );
⋮----
public function lock( \WC_Order $order ) {
⋮----
$order->update_meta_data( self::META_KEY_NAME, time() . ':' . $user_id );
$order->save_meta_data();
⋮----
return $order->get_meta( self::META_KEY_NAME, true, 'edit' );
⋮----
public function refresh_lock_ajax( $response, $data ) {
⋮----
if ( ! $order || ! is_a( $order, \WC_Order::class ) || ( ! current_user_can( get_post_type_object( $order->get_type() )->cap->edit_post, $order->get_id() ) && ! current_user_can( 'manage_woocommerce' ) ) ) {
⋮----
if ( ! $this->is_locked_by_another_user( $order ) ) {
$response['wc-refresh-order-lock']['lock'] = $this->lock( $order );
⋮----
$current_lock = $this->get_lock( $order );
⋮----
/**
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Orders/ItemQuantityLimits.php">
namespace Automattic\WooCommerce\Internal\Admin\Orders;
⋮----
use WC_Order;
use WC_Order_Item;
use WC_Order_Item_Product;
use WC_Product;
⋮----
class ItemQuantityLimits {
⋮----
public function get_quantity_input_min( WC_Order_Item $item, $product = null ): string {
⋮----
$product = $item instanceof WC_Order_Item_Product ? $item->get_product() : false;
⋮----
$default = (string) min( 0, (float) $item->get_quantity() );
⋮----
public function validate_new_item_quantity( float $qty, WC_Product $product ): void {
⋮----
throw $this->below_min_exception( $product->get_name(), $min );
⋮----
public function validate_posted_item_quantities( WC_Order $order, array $items ): void {
⋮----
$order_items = $order->get_items();
⋮----
$min = (float) $this->get_quantity_input_min( $item );
⋮----
throw $this->below_min_exception( $item->get_name(), $min );
⋮----
private function below_min_exception( string $name, float $min ): \Exception {
return new \Exception(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Orders/ListTable.php">
namespace Automattic\WooCommerce\Internal\Admin\Orders;
⋮----
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\Caches\OrderCountCache;
use Automattic\WooCommerce\Utilities\OrderUtil;
use WC_Order;
use WP_List_Table;
use WP_Screen;
⋮----
class ListTable extends WP_List_Table {
⋮----
private $order_type;
⋮----
private $wp_post_type;
⋮----
private $request = array();
⋮----
private $order_query_args = array();
⋮----
private $has_filter = false;
⋮----
private $page_controller;
⋮----
private $is_trash = false;
⋮----
private $status_count_cache = null;
⋮----
public function __construct() {
... (354 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Orders/PageController.php">
namespace Automattic\WooCommerce\Internal\Admin\Orders;
⋮----
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
⋮----
class PageController {
⋮----
private $order_type = '';
⋮----
/**
	 * Instance of the posts redirection controller.
	 *
	 * @var PostsRedirectionController
	 */
private $redirection_controller;
⋮----
/**
	 * Instance of the orders list table.
	 *
	 * @var ListTable
	 */
private $orders_table;
⋮----
/**
	 * Instance of orders edit form.
	 *
	 * @var Edit
	 */
private $order_edit_form;
⋮----
/**
... (146 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Orders/PostsRedirectionController.php">
namespace Automattic\WooCommerce\Internal\Admin\Orders;
⋮----
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class PostsRedirectionController {
⋮----
private $page_controller;
⋮----
public function __construct( PageController $page_controller ) {
⋮----
if ( ! wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled() ) {
⋮----
$this->maybe_update_menu_items();
⋮----
$this->maybe_redirect_to_orders_page();
⋮----
$this->maybe_redirect_to_new_order_page();
⋮----
$this->maybe_redirect_to_edit_order_page();
⋮----
private function maybe_redirect_to_orders_page(): void {
$post_type = $_GET['post_type'] ?? ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
⋮----
$new_url = $this->page_controller->get_base_page_url( $post_type );
⋮----
'_wp_http_referer' => $this->page_controller->get_orders_url(),
⋮----
private function maybe_redirect_to_new_order_page(): void {
⋮----
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ProductForm/Component.php">
namespace Automattic\WooCommerce\Internal\Admin\ProductForm;
⋮----
abstract class Component {
⋮----
protected $additional_args;
⋮----
public function __construct( $id, $plugin_id, $additional_args ) {
⋮----
public function get_additional_args() {
⋮----
public function get_additional_argument( $key ) {
return self::get_argument_from_path( $this->additional_args, $key );
⋮----
public function get_json() {
⋮----
'id'        => $this->get_id(),
'plugin_id' => $this->get_plugin_id(),
⋮----
$this->get_additional_args()
⋮----
public static function sort( $a, $b, $sort_by = array() ) {
⋮----
$a_val = $a->get_additional_argument( $key );
$b_val = $b->get_additional_argument( $key );
⋮----
public static function get_argument_from_path( $arguments, $path, $delimiter = '.' ) {
⋮----
protected $required_arguments = array();
⋮----
public function get_missing_arguments( $args ) {
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ProductForm/ComponentTrait.php">
namespace Automattic\WooCommerce\Internal\Admin\ProductForm;
⋮----
trait ComponentTrait {
⋮----
protected $id;
⋮----
protected $plugin_id;
⋮----
protected $location;
⋮----
protected $order;
⋮----
public function get_id() {
⋮----
public function get_plugin_id() {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ProductForm/Field.php">
namespace Automattic\WooCommerce\Internal\Admin\ProductForm;
⋮----
class Field extends Component {
⋮----
public function __construct( $id, $plugin_id, $additional_args ) {
parent::__construct( $id, $plugin_id, $additional_args );
⋮----
$missing_arguments = self::get_missing_arguments( $additional_args );
⋮----
throw new \Exception(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ProductForm/FormFactory.php">
namespace Automattic\WooCommerce\Internal\Admin\ProductForm;
⋮----
use WP_Error;
⋮----
class FormFactory {
⋮----
protected static $instance = null;
⋮----
protected static $form_fields = array();
⋮----
protected static $form_subsections = array();
⋮----
protected static $form_sections = array();
⋮----
protected static $form_tabs = array();
⋮----
final public static function instance() {
⋮----
public function init() {    }
⋮----
public static function add_field( $id, $plugin_id, $args ) {
$new_field = self::create_item( 'field', 'Field', $id, $plugin_id, $args );
⋮----
public static function add_subsection( $id, $plugin_id, $args = array() ) {
$new_subsection = self::create_item( 'subsection', 'Subsection', $id, $plugin_id, $args );
⋮----
public static function add_section( $id, $plugin_id, $args ) {
$new_section = self::create_item( 'section', 'Section', $id, $plugin_id, $args );
⋮----
public static function add_tab( $id, $plugin_id, $args ) {
... (32 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ProductForm/README.md">
# Product Form

This folder contains helper classes to specifically extend the WooCommerce Admin product form.
This will primarily be done through the `Form` class, under the `Automattic\WooCommerce\Internal\Admin\ProductForm` namespace.

## Ex - Adding a new field:

```php
function add_product_form_field() {
    if (
        ! method_exists( '\Automattic\WooCommerce\Internal\Admin\ProductForm\FormFactory', 'add_field' )
    ) {
        return;
    }

    \Automattic\WooCommerce\Internal\Admin\ProductForm\FormFactory::add_field(
        'test_new_field',
        'woocommerce-plugin-name',
        array(
          'type'       => 'text',
          'section'    => 'Section',
          'properties' => array( 'name' => 'test_new_field', 'label' => 'Test New Field' ),
        )
    );
}
add_action( 'init', 'add_product_form_field' );
```
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ProductForm/Section.php">
namespace Automattic\WooCommerce\Internal\Admin\ProductForm;
⋮----
class Section extends Component {
⋮----
public function __construct( $id, $plugin_id, $additional_args ) {
parent::__construct( $id, $plugin_id, $additional_args );
⋮----
$missing_arguments        = self::get_missing_arguments( $additional_args );
⋮----
throw new \Exception(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ProductForm/Subsection.php">
namespace Automattic\WooCommerce\Internal\Admin\ProductForm;
⋮----
class Subsection extends Component {}
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ProductForm/Tab.php">
namespace Automattic\WooCommerce\Internal\Admin\ProductForm;
⋮----
class Tab extends Component {
⋮----
public function __construct( $id, $plugin_id, $additional_args ) {
parent::__construct( $id, $plugin_id, $additional_args );
⋮----
$missing_arguments = self::get_missing_arguments( $additional_args );
⋮----
throw new \Exception(
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ProductReviews/Reviews.php">
namespace Automattic\WooCommerce\Internal\Admin\ProductReviews;
⋮----
use WP_Ajax_Response;
use WP_Comment;
use WP_Screen;
⋮----
class Reviews {
⋮----
protected $reviews_page_hook = null;
⋮----
protected $reviews_list_table;
⋮----
public function __construct() {
⋮----
public static function get_capability( string $context = 'view' ): string {
⋮----
public function add_reviews_page(): void {
⋮----
__( 'Reviews', 'woocommerce' ) . $this->get_pending_count_bubble(),
static::get_capability(),
⋮----
public static function get_reviews_page_url(): string {
⋮----
public function is_reviews_page(): bool {
⋮----
public function load_javascript(): void {
if ( $this->is_reviews_page() ) {
⋮----
protected function is_review_or_reply( $object ): bool {
⋮----
... (77 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ProductReviews/ReviewsCommentsOverrides.php">
namespace Automattic\WooCommerce\Internal\Admin\ProductReviews;
⋮----
use WP_Comment_Query;
use WP_Screen;
⋮----
class ReviewsCommentsOverrides {
⋮----
public function __construct() {
⋮----
public function exclude_reviews_from_comments( $args ): array {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ProductReviews/ReviewsListTable.php">
namespace Automattic\WooCommerce\Internal\Admin\ProductReviews;
⋮----
use WC_Product;
use WP_Comment;
use WP_Comments_List_Table;
use WP_List_Table;
use WP_Post;
⋮----
class ReviewsListTable extends WP_List_Table {
⋮----
private $current_user_can_edit_review = false;
⋮----
private $current_user_can_moderate_reviews;
⋮----
private $current_reviews_rating = 0;
⋮----
private $current_product_for_reviews;
⋮----
public function __construct( $args = [] ) {
parent::__construct(
⋮----
$this->current_user_can_moderate_reviews = current_user_can( Reviews::get_capability( 'moderate' ) );
⋮----
public function prepare_items() : void {
⋮----
$this->set_review_status();
$this->set_review_type();
⋮----
$this->set_review_product();
⋮----
... (192 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ProductReviews/ReviewsUtil.php">
namespace Automattic\WooCommerce\Internal\Admin\ProductReviews;
⋮----
class ReviewsUtil {
⋮----
public static function modify_product_review_moderation_urls( $message, $comment_id ) {
⋮----
public static function comments_clauses_without_product_reviews( $clauses, $comment_query ) {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/RemoteFreeExtensions/DefaultFreeExtensions.php">
namespace Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions;
⋮----
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\DefaultPaymentGateways;
⋮----
class DefaultFreeExtensions {
⋮----
private static function get_woo_logo() {
⋮----
public static function get_all() {
⋮----
self::get_plugin( 'woocommerce-payments' ),
self::get_plugin( 'woocommerce-shipping' ),
self::get_plugin( 'woocommerce-services:tax' ),
self::get_plugin( 'jetpack' ),
⋮----
self::get_plugin( 'mailpoet' ),
self::get_plugin( 'google-listings-and-ads' ),
self::get_plugin( 'pinterest-for-woocommerce' ),
self::get_plugin( 'facebook-for-woocommerce' ),
⋮----
self::get_plugin( 'mailpoet:alt' ),
⋮----
self::get_plugin( 'klaviyo:alt' ),
self::get_plugin( 'mailchimp-for-woocommerce' ),
⋮----
self::get_plugin( 'google-listings-and-ads:alt' ),
self::get_plugin( 'tiktok-for-business' ),
self::get_plugin( 'pinterest-for-woocommerce:alt' ),
self::get_plugin( 'facebook-for-woocommerce:alt' ),
⋮----
... (26 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/RemoteFreeExtensions/EvaluateExtension.php">
namespace Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions;
⋮----
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\EvaluateOverrides;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
⋮----
class EvaluateExtension {
⋮----
private static function evaluate( $extension ) {
⋮----
$is_visible            = $rule_evaluator->evaluate( $extension->is_visible );
⋮----
$installed_plugins       = PluginsHelper::get_installed_plugin_slugs();
$activated_plugins       = PluginsHelper::get_active_plugin_slugs();
⋮----
public static function evaluate_bundles( $specs, $allowed_bundles = array() ) {
⋮----
$extension = self::evaluate( (object) $plugin );
⋮----
$bundle['plugins']  = $evaluate_order->evaluate( $bundle['plugins'], $context );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/RemoteFreeExtensions/Init.php">
namespace Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions;
⋮----
use Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions\DefaultFreeExtensions;
use Automattic\WooCommerce\Admin\RemoteSpecs\RemoteSpecsEngine;
⋮----
class Init extends RemoteSpecsEngine {
⋮----
public function __construct() {
⋮----
public static function get_extensions( $allowed_bundles = array() ) {
⋮----
$specs           = self::get_specs();
$results         = EvaluateExtension::evaluate_bundles( $specs, $allowed_bundles );
⋮----
$specs_to_save   = DefaultFreeExtensions::get_all();
$specs_to_return = EvaluateExtension::evaluate_bundles( $specs_to_save, $allowed_bundles )['bundles'];
⋮----
self::log_errors( $results['errors'] );
⋮----
RemoteFreeExtensionsDataSourcePoller::get_instance()->set_specs_transient( array( $locale => $specs_to_save ), 3 * HOUR_IN_SECONDS );
⋮----
public static function delete_specs_transient() {
RemoteFreeExtensionsDataSourcePoller::get_instance()->delete_specs_transient();
⋮----
public static function get_specs() {
⋮----
return DefaultFreeExtensions::get_all();
⋮----
$specs = RemoteFreeExtensionsDataSourcePoller::get_instance()->get_specs_from_data_sources();
</file>

<file path="plugins/woocommerce/src/Internal/Admin/RemoteFreeExtensions/ProcessCoreProfilerPluginInstallOptions.php">
namespace Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions;
⋮----
use WC_Logger_Interface;
⋮----
class ProcessCoreProfilerPluginInstallOptions {
⋮----
private array $plugins;
⋮----
private string $slug;
⋮----
private WC_Logger_Interface $logger;
⋮----
public function __construct( array $plugins, string $slug, ?WC_Logger_Interface $logger = null ) {
⋮----
public function get_install_options( string $plugin_slug ): ?array {
⋮----
if ( $this->matches_plugin_slug( $plugin, $plugin_slug ) ) {
⋮----
public function process_install_options() {
$install_options = $this->get_install_options( $this->slug );
⋮----
$this->add_install_option( $install_option );
⋮----
protected function add_install_option( object $install_option ) {
⋮----
: new \stdClass();
⋮----
$this->logger && $this->logger->error( 'Failed to decode JSON for install option value for ' . $install_option->name . ': ' . json_last_error_msg() );
⋮----
$this->add_option( $install_option->name, $install_option->value, $autoload );
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/RemoteFreeExtensions/RemoteFreeExtensionsDataSourcePoller.php">
namespace Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller;
use WC_Helper;
⋮----
class RemoteFreeExtensionsDataSourcePoller extends DataSourcePoller {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
self::get_data_sources(),
⋮----
public static function get_data_sources() {
⋮----
WC_Helper::get_woocommerce_com_base_url() . 'wp-json/wccom/obw-free-extensions/4.0/extensions.json',
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Reports/HposLegacyOrderReportQueryBuilder.php">
namespace Automattic\WooCommerce\Internal\Admin\Reports;
⋮----
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class HposLegacyOrderReportQueryBuilder {
⋮----
private $report_schema = null;
⋮----
private $column_map = null;
⋮----
private $report_range = null;
⋮----
public function build_query( array $args, int $start_date, int $end_date ): array {
⋮----
$part = $this->build_data_select_and_joins( $raw_key, $value );
⋮----
$joins = array_merge( $joins, $this->resolve_type_joins( $raw_key, $value ) );
⋮----
$joins = array_merge( $joins, $this->build_where_meta_joins( $value ) );
⋮----
$joins = array_merge( $joins, $this->build_parent_orders_join() );
⋮----
$query['from']   = 'FROM ' . OrderUtil::get_table_for_orders() . ' AS orders';
⋮----
$query['where']  = $this->build_where_clause( $order_types, $order_status, $parent_order_status, (bool) $filter_range, $start_date, $end_date );
⋮----
$query['where'] .= $this->build_where_meta_predicates( $where_meta );
⋮----
$query['where'] .= $this->build_where_predicates( $where );
... (177 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Reports/ProductSearchQuery.php">
namespace Automattic\WooCommerce\Internal\Admin\Reports;
⋮----
use WP_Query;
⋮----
class ProductSearchQuery {
⋮----
public static function parse_terms( $value ) {
⋮----
/**
	 * Returns the REST collection parameter definition for the product search.
	 *
	 * @since 11.2.0
	 *
	 * @return array Parameter definition.
	 */
public static function get_collection_param() {
⋮----
public static function get_ids_subquery( $terms, $restrict_to_ids = array() ) {
$terms = self::parse_terms( $terms );
⋮----
$statement = self::build_statement( $args );
⋮----
public static function get_id_condition( string $column, string $search_subquery, array $included_products ): string {
⋮----
/**
	 * Returns the product IDs the given search terms resolve to.
	 *
	 * For callers that need the matches themselves rather than a statement to compose with.
	 * An empty list means the terms matched nothing, which is not the same as `null`, meaning
	 * there was nothing to search for.
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Schedulers/CustomersScheduler.php">
namespace Automattic\WooCommerce\Internal\Admin\Schedulers;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
use Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore as CustomersDataStore;
⋮----
class CustomersScheduler extends ImportScheduler {
⋮----
public static $name = 'customers';
⋮----
public static function init() {
CustomersDataStore::init();
parent::init();
⋮----
public static function get_dependencies() {
⋮----
'delete_batch_init' => OrdersScheduler::get_action( 'delete_batch_init' ),
⋮----
public static function get_items( $limit = 10, $page = 1, $days = false, $skip_existing = false ) {
⋮----
$customer_query = new \WP_User_Query( $query_args );
⋮----
'total' => $customer_query->get_total(),
'ids'   => $customer_query->get_results(),
⋮----
public static function exclude_existing_customers_from_query( $wp_user_query ) {
⋮----
public static function get_total_imported() {
⋮----
return $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}wc_customer_lookup" );
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Schedulers/ImportInterface.php">
namespace Automattic\WooCommerce\Internal\Admin\Schedulers;
⋮----
interface ImportInterface {
⋮----
public static function get_items( $limit, $page, $days, $skip_existing );
⋮----
public static function get_total_imported();
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Schedulers/ImportScheduler.php">
namespace Automattic\WooCommerce\Internal\Admin\Schedulers;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
use Automattic\WooCommerce\Admin\Schedulers\SchedulerTraits;
⋮----
abstract class ImportScheduler implements ImportInterface {
⋮----
public static $name = '';
⋮----
/**
	 * Scheduler traits.
	 */
⋮----
/**
	 * Returns true if an import is in progress.
	 *
	 * @internal
	 * @return bool
	 */
public static function is_importing() {
$pending_jobs = self::queue()->search(
⋮----
$in_progress = self::queue()->search(
⋮----
public static function get_batch_sizes() {
⋮----
self::get_scheduler_batch_sizes(),
⋮----
public static function get_scheduler_actions() {
⋮----
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Schedulers/MailchimpScheduler.php">
namespace Automattic\WooCommerce\Internal\Admin\Schedulers;
⋮----
class MailchimpScheduler {
⋮----
private $logger;
⋮----
public function __construct( ?\WC_Logger_Interface $logger = null ) {
⋮----
public function run() {
⋮----
$country_code = WC()->countries->get_base_country();
$state        = WC()->countries->get_base_state();
⋮----
$response = $this->make_request( $profile_data['store_email'], $address );
⋮----
$this->handle_request_error();
⋮----
$this->handle_request_error( $body );
⋮----
public function make_request( $store_email, $address ) {
⋮----
public static function reset() {
⋮----
private function handle_request_error( $extra_msg = null ) {
⋮----
$this->logger->error( $msg, array( 'source' => self::LOGGER_CONTEXT ) );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Schedulers/OrdersScheduler.php">
namespace Automattic\WooCommerce\Internal\Admin\Schedulers;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
use Automattic\WooCommerce\Admin\API\Reports\Coupons\DataStore as CouponsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore as CustomersDataStore;
use Automattic\WooCommerce\Admin\API\Reports\Orders\DataStore as OrderDataStore;
use Automattic\WooCommerce\Admin\API\Reports\Orders\Stats\DataStore as OrdersStatsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\Products\DataStore as ProductsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\Taxes\DataStore as TaxesDataStore;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class OrdersScheduler extends ImportScheduler {
⋮----
public static $name = 'orders';
⋮----
public static function init() {
⋮----
\Automattic\WooCommerce\Admin\Overrides\Order::add_filters();
\Automattic\WooCommerce\Admin\Overrides\OrderRefund::add_filters();
⋮----
if ( self::is_scheduled_import_enabled() ) {
⋮----
OrdersStatsDataStore::init();
CouponsDataStore::init();
ProductsDataStore::init();
TaxesDataStore::init();
OrderDataStore::init();
⋮----
... (186 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/Exceptions/ApiArgumentException.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\Exceptions;
⋮----
class ApiArgumentException extends ApiException {}
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/Exceptions/ApiException.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\Exceptions;
⋮----
class ApiException extends \Exception {
⋮----
public string $error_code;
⋮----
public array $additional_data = array();
⋮----
public function __construct( string $error_code, string $message, int $http_status_code = 400, array $additional_data = array() ) {
⋮----
parent::__construct( $message, $http_status_code );
⋮----
public function getErrorCode(): string {
⋮----
public function getAdditionalData(): array {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/WooPayments/WooPaymentsController.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\WooPayments;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings\Payments;
⋮----
class WooPaymentsController {
⋮----
private Payments $payments;
⋮----
private WooPaymentsService $woopayments;
⋮----
public function register() {
⋮----
final public function init( Payments $payments, WooPaymentsService $woopayments ): void {
⋮----
public function handle_returns_from_wpcom(): void {
⋮----
$location = $this->payments->get_country();
⋮----
$wpcom_connected = WooPaymentsService::ONBOARDING_STEP_STATUS_COMPLETED === $this->woopayments->get_onboarding_step_status( WooPaymentsService::ONBOARDING_STEP_WPCOM_CONNECTION, $location );
⋮----
$this->woopayments->record_event(
⋮----
$this->woopayments->mark_onboarding_step_completed( WooPaymentsService::ONBOARDING_STEP_WPCOM_CONNECTION, $location );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/WooPayments/WooPaymentsRestController.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\WooPayments;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings\Exceptions\ApiException;
use Automattic\WooCommerce\Internal\Admin\Settings\Payments;
use Automattic\WooCommerce\Internal\RestApiControllerBase;
use Automattic\WooCommerce\Internal\Utilities\ArrayUtil;
use Exception;
use WP_Error;
use WP_Http;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class WooPaymentsRestController extends RestApiControllerBase {
⋮----
protected string $route_namespace = 'wc-admin';
⋮----
protected string $rest_base = 'settings/payments/woopayments';
⋮----
private Payments $payments;
⋮----
private WooPaymentsService $woopayments;
⋮----
protected function get_rest_api_namespace(): string {
⋮----
public function register_routes( bool $override = false ) {
⋮----
'callback'            => fn( $request ) => $this->run( $request, 'get_onboarding_details' ),
⋮----
'permission_callback' => fn( $request ) => $this->check_permissions( $request ),
⋮----
... (159 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/WooPayments/WooPaymentsService.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\WooPayments;
⋮----
use Automattic\Jetpack\Connection\Manager as WPCOM_Connection_Manager;
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\Settings\Exceptions\ApiArgumentException;
use Automattic\WooCommerce\Internal\Admin\Settings\Exceptions\ApiException;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
use Automattic\WooCommerce\Internal\Admin\Settings\Utils;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Exception;
use WP_Error;
use WP_Http;
⋮----
class WooPaymentsService {
⋮----
private PaymentsProviders $payments_providers;
⋮----
private LegacyProxy $proxy;
⋮----
private $wpcom_connection_manager;
⋮----
private PaymentsProviders\PaymentGateway $provider;
⋮----
final public function init( PaymentsProviders $payment_providers, LegacyProxy $proxy ): void {
⋮----
$this->wpcom_connection_manager = $this->proxy->get_instance_of( WPCOM_Connection_Manager::class, 'woocommerce' );
$this->provider                 = $this->payments_providers->get_payment_gateway_provider_instance( self::GATEWAY_ID );
⋮----
public function get_onboarding_details( string $location, string $rest_path, ?string $source = null ): array {
⋮----
... (484 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Affirm.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Affirm extends PaymentGateway {
⋮----
public function needs_setup( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return ! wc_string_to_bool( $payment_gateway->isValidForUse() );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway needs setup: ' . $e->getMessage(),
⋮----
return parent::needs_setup( $payment_gateway );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/AfterpayClearpay.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class AfterpayClearpay extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return ! empty( $payment_gateway->get_merchant_id() ) &&
! empty( $payment_gateway->get_secret_key() );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_afterpay_clearpay_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_in_dev_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_afterpay_clearpay_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_dev_mode( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_afterpay_clearpay_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
private function is_afterpay_clearpay_in_sandbox_mode( WC_Payment_Gateway $payment_gateway ): ?bool {
⋮----
return 'production' !== $payment_gateway->get_api_env();
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Airwallex.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Airwallex extends PaymentGateway {
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_airwallex_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return ! empty( \Airwallex\Services\Util::getClientId() ) &&
! empty( \Airwallex\Services\Util::getApiKey() ) &&
! empty( \Airwallex\Services\Util::getWebhookSecret() );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_airwallex_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
private function is_airwallex_in_sandbox_mode( WC_Payment_Gateway $payment_gateway ): ?bool {
⋮----
return 'demo' === \Airwallex\Services\Util::getEnvironment();
⋮----
'Failed to determine if gateway is in sandbox mode: ' . $e->getMessage(),
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/AmazonPay.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use WC_Payment_Gateway;
⋮----
class AmazonPay extends PaymentGateway {
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_amazon_pay_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_in_dev_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_amazon_pay_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_dev_mode( $payment_gateway );
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_amazon_pay_onboarded( $payment_gateway ) ?? parent::is_account_connected( $payment_gateway );
⋮----
public function is_onboarding_completed( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_amazon_pay_onboarded( $payment_gateway ) ?? parent::is_onboarding_completed( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_amazon_pay_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
private function is_amazon_pay_in_sandbox_mode( WC_Payment_Gateway $payment_gateway ): ?bool {
⋮----
$settings = \WC_Amazon_Payments_Advanced_API::get_settings();
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway is in sandbox mode: ' . $e->getMessage(),
⋮----
private function is_amazon_pay_onboarded( WC_Payment_Gateway $payment_gateway ): ?bool {
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Antom.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Antom extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
! \antom_is_active() ) {
⋮----
$core_settings = \antom_get_core_settings();
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_antom_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_in_dev_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_antom_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_dev_mode( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_antom_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
private function is_antom_in_sandbox_mode( WC_Payment_Gateway $payment_gateway ): ?bool {
⋮----
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Eway.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Eway extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return ! empty( $payment_gateway->get_option( 'customer_api' ) ) && ! empty( $payment_gateway->get_option( 'customer_password' ) );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_eway_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_in_dev_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_eway_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_dev_mode( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_eway_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
private function is_eway_in_sandbox_mode( WC_Payment_Gateway $payment_gateway ): ?bool {
⋮----
$raw_option = $payment_gateway->get_option( 'testmode' );
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/GoCardless.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class GoCardless extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return ! empty( $payment_gateway->get_option( 'access_token', '' ) );
⋮----
// Do nothing but log so we can investigate.
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return $this->is_in_test_mode( $payment_gateway );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Helcim.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Helcim extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return ! wc_string_to_bool( $payment_gateway->needs_setup() );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_helcim_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_helcim_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
private function is_helcim_in_sandbox_mode( WC_Payment_Gateway $payment_gateway ): ?bool {
⋮----
$environment = $payment_gateway->get_option( 'environment' );
⋮----
'Failed to determine if gateway is in sandbox mode: ' . $e->getMessage(),
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/HelioPay.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class HelioPay extends PaymentGateway {
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return wc_string_to_bool( $payment_gateway->get_option( \HELIO_DEVNET_ENABLED ) );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway is in test mode: ' . $e->getMessage(),
⋮----
return parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
if ( $this->is_in_test_mode( $payment_gateway ) ) {
⋮----
return ! empty( $payment_gateway->get_option( \HELIO_API_KEY_DEVNET ) ) && ! empty( $payment_gateway->get_option( \HELIO_API_SECRET_DEVNET ) );
⋮----
return ! empty( $payment_gateway->get_option( \HELIO_API_KEY_MAINNET ) ) && ! empty( $payment_gateway->get_option( \HELIO_API_SECRET_MAINNET ) );
⋮----
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Klarna.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Klarna extends PaymentGateway {
⋮----
public function needs_setup( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return ! wc_string_to_bool( \KP_Settings_Page::get_setting_status( 'credentials' ) );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway needs setup: ' . $e->getMessage(),
⋮----
return parent::needs_setup( $payment_gateway );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Komoju.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings\Payments;
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Komoju extends PaymentGateway {
⋮----
public function get_settings_url( WC_Payment_Gateway $payment_gateway ): string {
⋮----
return parent::get_settings_url( $payment_gateway );
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_komoju_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return $this->is_komoju_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
private function is_komoju_in_sandbox_mode( WC_Payment_Gateway $payment_gateway ): ?bool {
⋮----
$secret_key = $this->get_secret_key( $payment_gateway );
⋮----
return wc_string_to_bool( \WC_Gateway_Komoju::komoju_is_test_mode() );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway is in sandbox mode: ' . $e->getMessage(),
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/KustomCheckout.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class KustomCheckout extends PaymentGateway {
⋮----
public function needs_setup( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
$credentials = \KCO_WC()->credentials;
⋮----
return ! empty( $credentials->get_credentials_from_session() );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return $this->is_in_test_mode( $payment_gateway );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Mastercard.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Mastercard extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
$sandbox_mode = $this->is_mastercard_in_sandbox_mode( $payment_gateway );
⋮----
return '' !== $this->get_string_option( $payment_gateway, $merchant_id_key )
&& '' !== $this->get_string_option( $payment_gateway, $password_key );
⋮----
// Do nothing but log so we can investigate.
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_mastercard_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_mastercard_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
private function is_mastercard_in_sandbox_mode( WC_Payment_Gateway $payment_gateway ): ?bool {
⋮----
$sandbox = $payment_gateway->get_option( 'sandbox' );
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/MercadoPago.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings\Utils;
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use WC_Payment_Gateway;
⋮----
class MercadoPago extends PaymentGateway {
⋮----
public function needs_setup( WC_Payment_Gateway $payment_gateway ): bool {
$is_onboarded = $this->is_mercado_pago_onboarded( $payment_gateway );
⋮----
return parent::needs_setup( $payment_gateway );
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_mercado_pago_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_in_dev_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_mercado_pago_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_dev_mode( $payment_gateway );
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_mercado_pago_onboarded( $payment_gateway ) ?? parent::is_account_connected( $payment_gateway );
⋮----
public function is_onboarding_completed( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_mercado_pago_onboarded( $payment_gateway ) ?? parent::is_onboarding_completed( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_mercado_pago_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
private function is_mercado_pago_in_sandbox_mode( WC_Payment_Gateway $payment_gateway ): ?bool {
⋮----
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Mollie.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings\Payments;
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Mollie extends PaymentGateway {
⋮----
public function get_settings_url( WC_Payment_Gateway $payment_gateway ): string {
⋮----
return $this->get_custom_settings_url();
⋮----
return $this->get_custom_settings_url( 'mollie_payment_methods' );
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
$sandbox_mode = $this->is_mollie_in_sandbox_mode( $payment_gateway );
⋮----
// In production mode, we check the live API key.
⋮----
// Do nothing but log so we can investigate.
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_mollie_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Monei.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Monei extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return ! empty( $payment_gateway->getAccountId() ) &&
! empty( $payment_gateway->getApiKey() );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return $this->is_in_test_mode( $payment_gateway );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/NexiCheckout.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class NexiCheckout extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
$sandbox = $this->is_nexi_in_sandbox_mode( $payment_gateway );
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
? ( ! empty( $payment_gateway->get_option( 'dibs_test_key' ) ) && ! empty( $payment_gateway->get_option( 'dibs_test_checkout_key' ) ) )
: ( ! empty( $payment_gateway->get_option( 'dibs_live_key' ) ) && ! empty( $payment_gateway->get_option( 'dibs_checkout_key' ) ) );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_nexi_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_in_dev_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_nexi_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_dev_mode( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_nexi_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
private function is_nexi_in_sandbox_mode( WC_Payment_Gateway $payment_gateway ): ?bool {
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Payfast.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Payfast extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return ! empty( $payment_gateway->get_option( 'merchant_id' ) ) &&
! empty( $payment_gateway->get_option( 'merchant_key' ) ) &&
! empty( $payment_gateway->get_option( 'pass_phrase' ) ) &&
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return $this->is_in_test_mode( $payment_gateway );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/PaymentGateway.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
use Automattic\WooCommerce\Internal\Admin\Settings\Payments;
use Automattic\WooCommerce\Internal\Admin\Settings\Utils;
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Throwable;
use WC_HTTPS;
use WC_Payment_Gateway;
⋮----
class PaymentGateway {
⋮----
protected LegacyProxy $proxy;
⋮----
public function __construct( LegacyProxy $proxy ) {
⋮----
public function get_details( WC_Payment_Gateway $gateway, int $order = 0, string $country_code = '' ): array {
$onboarding_supported = $this->is_onboarding_supported( $gateway, $country_code ) ?? true; // Assume supported if unknown.
⋮----
'title'       => $this->get_title( $gateway ),
'description' => $this->get_description( $gateway ),
'icon'        => $this->get_icon( $gateway ),
'supports'    => $this->get_supports_list( $gateway ),
'links'       => $this->get_provider_links( $gateway, $country_code ),
⋮----
'enabled'           => $this->is_enabled( $gateway ),
'account_connected' => $this->is_account_connected( $gateway ),
'needs_setup'       => $this->needs_setup( $gateway ),
... (260 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Paymob.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Paymob extends PaymentGateway {
⋮----
public function needs_setup( WC_Payment_Gateway $payment_gateway ): bool {
$needs_setup = wc_string_to_bool( $payment_gateway->needs_setup() );
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_paymob_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return ! $this->needs_setup( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_paymob_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
private function is_paymob_in_sandbox_mode( WC_Payment_Gateway $payment_gateway ): ?bool {
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway is in sandbox mode: ' . $e->getMessage(),
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Payoneer.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Payoneer extends PaymentGateway {
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return ! wc_string_to_bool( $payment_gateway->get_option( 'live_mode' ) );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway is in test mode: ' . $e->getMessage(),
⋮----
return parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
$sandbox_prefix = $this->is_in_test_mode( $payment_gateway ) ? 'sandbox_' : '';
return ! empty( $payment_gateway->get_option( 'merchant_code' ) ) &&
! empty( $payment_gateway->get_option( $sandbox_prefix . 'merchant_token' ) ) &&
! empty( $payment_gateway->get_option( $sandbox_prefix . 'store_code' ) );
⋮----
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/PayPal.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use WC_Payment_Gateway;
⋮----
class PayPal extends PaymentGateway {
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_paypal_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_in_dev_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_paypal_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_dev_mode( $payment_gateway );
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_paypal_onboarded( $payment_gateway ) ?? parent::is_account_connected( $payment_gateway );
⋮----
public function is_onboarding_completed( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_paypal_onboarded( $payment_gateway ) ?? parent::is_onboarding_completed( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_paypal_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
private function is_paypal_in_sandbox_mode( WC_Payment_Gateway $payment_gateway ): ?bool {
⋮----
$container = \WooCommerce\PayPalCommerce\PPCP::container();
⋮----
if ( $container->has( 'settings.connection-state' ) ) {
$state = $container->get( 'settings.connection-state' );
⋮----
return $state->is_sandbox();
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Paystack.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Paystack extends PaymentGateway {
⋮----
public function needs_setup( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
$is_valid_for_use = wc_string_to_bool( $payment_gateway->is_valid_for_use() );
⋮----
return ! $is_valid_for_use || ! $this->is_account_connected( $payment_gateway );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway needs setup: ' . $e->getMessage(),
⋮----
return parent::needs_setup( $payment_gateway );
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return $this->is_in_test_mode( $payment_gateway );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Paytrail.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Paytrail extends PaymentGateway {
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return wc_string_to_bool( $payment_gateway->get_option( 'enable_test_mode', 'no' ) );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway is in test mode: ' . $e->getMessage(),
⋮----
return parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
if ( $this->is_in_test_mode_onboarding( $payment_gateway ) ) {
⋮----
return ! empty( $payment_gateway->get_option( 'merchant_id' ) ) &&
! empty( $payment_gateway->get_option( 'secret_key' ) );
⋮----
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/PayUIndia.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class PayUIndia extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return ! empty( $payment_gateway->get_option( 'currency1_payu_key' ) ) && ! empty( $payment_gateway->get_option( 'currency1_payu_salt' ) );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/PseudoWCPaymentGateway.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
class PseudoWCPaymentGateway extends \WC_Payment_Gateway {
⋮----
public $id = '';
⋮----
/**
	 * Gateway title.
	 *
	 * @var string
	 */
public $title = '';
⋮----
/**
	 * Gateway description.
	 *
	 * @var string
	 */
public $description = '';
⋮----
/**
	 * Gateway method title.
	 *
	 * @var string
	 */
public $method_title = '';
⋮----
/**
	 * Gateway method description.
	 *
... (53 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Razorpay.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Razorpay extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return ! empty( $payment_gateway->getSetting( 'key_id' ) ) &&
! empty( $payment_gateway->getSetting( 'key_secret' ) );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return wc_string_to_bool( \isTestModeEnabled() );
⋮----
'Failed to determine if gateway is in test mode: ' . $e->getMessage(),
⋮----
return parent::is_in_test_mode( $payment_gateway );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Stripe.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings\Payments;
use Automattic\WooCommerce\Internal\Admin\Settings\Utils;
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Stripe extends PaymentGateway {
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return wc_string_to_bool( \WC_Stripe_Mode::is_test() );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway is in test mode: ' . $e->getMessage(),
⋮----
return parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_in_dev_mode( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
$stripe = \WC_Stripe::get_instance();
⋮----
return \WC_Stripe_Account::STATUS_NO_ACCOUNT !== $stripe->account->get_account_status();
⋮----
'Failed to determine if gateway has account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
... (42 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Tilopay.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Tilopay extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Visa.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Visa extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
$settings = $payment_gateway->get_config_settings();
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_visa_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode( $payment_gateway );
⋮----
public function is_in_dev_mode( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_visa_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_dev_mode( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
return $this->is_visa_in_sandbox_mode( $payment_gateway ) ?? parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
private function is_visa_in_sandbox_mode( WC_Payment_Gateway $payment_gateway ): ?bool {
⋮----
'Failed to determine if gateway is in sandbox mode: ' . $e->getMessage(),
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/Vivacom.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Payment_Gateway;
⋮----
class Vivacom extends PaymentGateway {
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
if ( $this->is_in_test_mode( $payment_gateway ) ) {
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->debug(
'Failed to determine if gateway has an account connected: ' . $e->getMessage(),
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return $this->is_in_test_mode( $payment_gateway );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/WCCore.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use WC_Payment_Gateway;
use WC_Gateway_BACS;
use WC_Gateway_Cheque;
use WC_Gateway_COD;
use WC_Gateway_Paypal;
⋮----
class WCCore extends PaymentGateway {
⋮----
public function get_icon( WC_Payment_Gateway $payment_gateway ): string {
⋮----
return parent::get_icon( $payment_gateway );
⋮----
public function is_account_connected( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return parent::is_account_connected( $payment_gateway );
⋮----
public function is_in_test_mode_onboarding( WC_Payment_Gateway $payment_gateway ): bool {
⋮----
return $this->is_in_test_mode( $payment_gateway );
⋮----
return parent::is_in_test_mode_onboarding( $payment_gateway );
⋮----
public function get_plugin_details( WC_Payment_Gateway $payment_gateway ): array {
$plugin_details = parent::get_plugin_details( $payment_gateway );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders/WooPayments.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
⋮----
use Automattic\Jetpack\Connection\Manager as WPCOM_Connection_Manager;
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Admin\WCAdminHelper;
use Automattic\WooCommerce\Enums\OrderInternalStatus;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\WooPayments\WooPaymentsRestController;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\WooPayments\WooPaymentsService;
use Automattic\WooCommerce\Internal\Admin\Settings\Payments;
use Automattic\WooCommerce\Internal\Admin\Settings\Utils;
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Abstract_Order;
use WC_Payment_Gateway;
⋮----
class WooPayments extends PaymentGateway {
⋮----
public function get_details( WC_Payment_Gateway $gateway, int $order = 0, string $country_code = '' ): array {
$details = parent::get_details( $gateway, $order, $country_code );
⋮----
$has_test_account    = $this->has_test_account();
$has_sandbox_account = $this->has_sandbox_account();
⋮----
// Switch the onboarding type to native.
⋮----
$details['onboarding']['state'] = array_merge( $details['onboarding']['state'], $this->get_wpcom_connection_state() );
⋮----
... (144 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/SettingsUIPages/ProductsSettingsPageAdapter.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings\SettingsUIPages;
⋮----
use Automattic\WooCommerce\Admin\Settings\LegacySettingsPageAdapter;
⋮----
final class ProductsSettingsPageAdapter extends LegacySettingsPageAdapter {
⋮----
public function get_schema( string $section ): array {
$schema = parent::get_schema( $section );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/CLAUDE.md">
# Claude Code Documentation for Settings Payments backend

**Location**: `src/Internal/Admin/Settings/`
**Purpose**: Payment settings REST API controllers and business logic

## Quick Reference: JSON Schema Validation

**Common errors and fixes:**

| Error                    | Wrong                   | Correct                                |
| ------------------------ | ----------------------- | -------------------------------------- |
| Object with dynamic keys | `'items' => array(...)` | `'additionalProperties' => array(...)` |
| Enum as type             | `'type' => 'enum'`      | `'type' => 'string', 'enum' => [...]`  |

**Valid types only:** `string`, `number`, `integer`, `boolean`, `array`, `object`, `null`

**Schema keywords:**

| Keyword | For Type | Purpose |
| --------- | ---------- | --------- |
| `properties` | `object` | Define named fields |
| `additionalProperties` | `object` | Define dynamic keys |
| `items` | `array` | Define element schema |
| `enum` | any | Constraint (not a type) |

## File Structure

```text
Settings/
|-- PaymentsRestController.php                          # Main REST endpoint
... (198 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/LegacySettingsPageAdapter.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
use Automattic\WooCommerce\Admin\Settings\SettingsUIPageInterface as PublicSettingsUIPageInterface;
⋮----
class LegacySettingsPageAdapter implements PublicSettingsUIPageInterface {
⋮----
protected \WC_Settings_Page $settings_page;
⋮----
public function __construct( \WC_Settings_Page $settings_page ) {
⋮----
public function get_page_id(): string {
return $this->settings_page->get_id();
⋮----
public function get_schema( string $section ): array {
return SettingsUISchema::from_legacy_settings(
$this->settings_page->get_id(),
⋮----
$this->settings_page->get_label(),
$this->settings_page->get_settings( $section ),
$this->get_save_adapter( $section )
⋮----
public function get_script_handles( string $section ): array {
⋮----
public function get_save_adapter( string $section ): string {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/Payments.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\WooPayments\WooPaymentsService;
use Automattic\WooCommerce\Internal\Admin\Suggestions\PaymentsExtensionSuggestions as ExtensionSuggestions;
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Exception;
⋮----
class Payments {
⋮----
private PaymentsProviders $providers;
⋮----
private ExtensionSuggestions $extension_suggestions;
⋮----
final public function init( PaymentsProviders $payment_providers, ExtensionSuggestions $payment_extension_suggestions ): void {
⋮----
public function get_payment_providers( string $location, bool $for_display = true, bool $remove_shells = false ): array {
⋮----
$payment_gateways = $this->providers->get_payment_gateways( $for_display );
⋮----
$payment_gateways = $this->providers->remove_shell_payment_gateways( $payment_gateways, $location );
⋮----
$providers_order_map = $this->providers->get_order_map();
⋮----
$suggestions = $this->providers->get_extension_suggestions( $location, self::SUGGESTIONS_CONTEXT );
⋮----
$suggestion_order_map_id = $this->providers->get_suggestion_order_map_id( $suggestion['id'] );
⋮----
$providers_order_map = Utils::order_map_add_at_order( $providers_order_map, $suggestion_order_map_id, $last_preferred_order + 1 );
⋮----
$providers_order_map = $this->providers->order_map_add_gateway( $providers_order_map, $payment_gateway->id );
... (69 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsController.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\WooPayments\WooPaymentsService;
use Automattic\WooCommerce\Internal\Logging\SafeGlobalFunctionProxy;
use Throwable;
use WC_Gateway_BACS;
use WC_Gateway_Cheque;
use WC_Gateway_COD;
⋮----
class PaymentsController {
⋮----
private Payments $payments;
⋮----
public function register() {
⋮----
final public function init( Payments $payments ): void {
⋮----
public function add_menu() {
⋮----
if ( $this->is_woopayments_account_onboarded() ) {
⋮----
if ( $this->store_has_providers_with_incentive() ) {
⋮----
public function add_body_classes( $classes = '' ) {
⋮----
// Bail if the type is invalid.
⋮----
public function preload_settings( $settings = array() ) {
⋮----
$settings[ Payments::PAYMENTS_NOX_PROFILE_KEY ]['business_country_code'] = $this->payments->get_country();
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsProviders.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Affirm;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\AfterpayClearpay;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Airwallex;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\AmazonPay;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Antom;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Eway;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\GoCardless;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Helcim;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\HelioPay;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Klarna;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Komoju;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\KustomCheckout;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Mastercard;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\MercadoPago;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Mollie;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Monei;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\NexiCheckout;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Payfast;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\PaymentGateway;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Paymob;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Payoneer;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\PayPal;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Paystack;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Paytrail;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\PayUIndia;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Razorpay;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders\Stripe;
... (362 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/PaymentsRestController.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
use Automattic\WooCommerce\Internal\RestApiControllerBase;
use Automattic\WooCommerce\Internal\Utilities\ArrayUtil;
use Exception;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class PaymentsRestController extends RestApiControllerBase {
⋮----
protected string $route_namespace = 'wc-admin';
⋮----
protected string $rest_base = 'settings/payments';
⋮----
private Payments $payments;
⋮----
protected function get_rest_api_namespace(): string {
⋮----
public function register_routes( bool $override = false ) {
⋮----
'callback'            => fn( $request ) => $this->run( $request, 'set_country' ),
⋮----
'permission_callback' => fn( $request ) => $this->check_permissions( $request ),
⋮----
'validate_callback' => fn( $value, $request ) => $this->check_location_arg( $value, $request ),
⋮----
'callback'            => fn( $request ) => $this->run( $request, 'get_providers' ),
⋮----
'schema' => fn() => $this->get_schema_for_get_payment_providers(),
... (132 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/RegisteredSettingsSectionAdapter.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
use Automattic\WooCommerce\Admin\Settings\SettingsSectionInterface;
⋮----
class RegisteredSettingsSectionAdapter extends LegacySettingsPageAdapter {
⋮----
private SettingsSectionInterface $section;
⋮----
public function __construct( \WC_Settings_Page $settings_page, SettingsSectionInterface $section ) {
parent::__construct( $settings_page );
⋮----
public function get_schema( string $section ): array {
$schema = parent::get_schema( $section );
⋮----
$label                    = html_entity_decode( $this->section->get_label(), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
⋮----
public function get_script_handles( string $section ): array {
return $this->section->get_script_handles( $this->settings_page );
⋮----
public function get_save_adapter( string $section ): string {
return $this->section->get_save_adapter( $this->settings_page );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/SettingsUIPageInterface.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
use Automattic\WooCommerce\Admin\Settings\SettingsUIPageInterface as PublicSettingsUIPageInterface;
⋮----
interface SettingsUIPageInterface extends PublicSettingsUIPageInterface {}
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/SettingsUIRequestContext.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Admin\Settings\SettingsSectionRegistry;
use Automattic\WooCommerce\Admin\Settings\SettingsSectionUIPageProviderInterface;
use Automattic\WooCommerce\Admin\Settings\SettingsUIPageInterface;
⋮----
class SettingsUIRequestContext {
⋮----
private static array $contexts = array();
⋮----
private \WC_Settings_Page $settings_page;
⋮----
private string $section;
⋮----
private ?SettingsUIPageInterface $settings_ui_page;
⋮----
private bool $page_id_resolved = false;
⋮----
private string $page_id = '';
⋮----
/**
	 * Failure raised while resolving the Settings UI page id.
	 *
	 * @var \Throwable|null
	 */
private ?\Throwable $page_id_failure = null;
⋮----
/**
... (251 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/SettingsUISchema.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
use Automattic\WooCommerce\Internal\Utilities\ArrayUtil;
⋮----
class SettingsUISchema {
⋮----
public static function from_legacy_settings( string $page_id, string $section, string $title, array $settings, string $default_save_adapter = 'form_post' ): array {
⋮----
$declared_group_ids    = self::get_declared_group_ids( $settings );
⋮----
self::add_group( $groups, $current_id, $current_group );
⋮----
: self::get_unique_group_id( 'group_' . $group_index, $groups, $declared_group_ids );
⋮----
$current_id    = self::get_unique_group_id( self::DEFAULT_GROUP_ID, $groups, $declared_group_ids );
$current_group = self::get_default_group( $current_id, $group_index );
⋮----
$field = self::transform_legacy_field( $setting, $default_save_adapter, $visibility_controller );
⋮----
return self::canonicalize_schema_values_for_source( $schema, true );
⋮----
public static function assert_valid_schema( array $schema ): void {
self::assert_non_empty_string( $schema['id'] ?? null, 'Schema id must be a non-empty string.' );
⋮----
throw self::invalid_schema( sprintf( 'Schema %s must be a string.', $property ) );
⋮----
throw self::invalid_schema( 'Schema section must be a non-empty string.' );
⋮----
self::assert_page_save_strategy( $schema['save'] ?? null );
self::assert_shell( $schema['shell'] ?? null );
... (553 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings/Utils.php">
namespace Automattic\WooCommerce\Internal\Admin\Settings;
⋮----
use Automattic\WooCommerce\Internal\Jetpack\JetpackConnection;
use WP_REST_Request;
⋮----
class Utils {
⋮----
public static function order_map_apply_mappings( array $base_map, array $new_mappings ): array {
⋮----
$updated_map = self::order_map_add_at_order( $updated_map, $id, $order );
⋮----
$updated_map = self::order_map_move_at_order( $updated_map, $id, $order );
⋮----
return self::order_map_normalize( $updated_map );
⋮----
public static function order_map_move_at_order( array $order_map, string $id, int $order ): array {
⋮----
public static function order_map_place_at_order( array $order_map, string $id, int $order ): array {
⋮----
public static function order_map_add_at_order( array $order_map, string $id, int $order ): array {
⋮----
return self::order_map_place_at_order( $order_map, $id, $order );
⋮----
public static function order_map_normalize( array $order_map ): array {
⋮----
public static function order_map_change_min_order( array $order_map, int $new_min_order ): array {
⋮----
public static function get_testing_plugin_slug_suffixes(): array {
⋮----
public static function generate_testing_plugin_slugs( string $slug, bool $include_original = false ): array {
... (45 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Suggestions/Incentives/Incentive.php">
namespace Automattic\WooCommerce\Internal\Admin\Suggestions\Incentives;
⋮----
abstract class Incentive {
⋮----
protected string $dismissed_meta_name = self::PREFIX . 'dismissed';
⋮----
protected string $suggestion_id;
⋮----
public function __construct( string $suggestion_id ) {
⋮----
public function get_all( string $country_code, string $incentive_type = '' ): array {
⋮----
$this->get_incentives( $country_code ),
fn( $incentive ) => $this->validate_incentive( $incentive )
⋮----
public function get_by_promo_id( string $promo_id, string $country_code, string $incentive_type = '' ): ?array {
⋮----
$this->get_all( $country_code, $incentive_type ),
⋮----
public function get_by_id( string $incentive_id, string $country_code ): ?array {
⋮----
$this->get_all( $country_code ),
⋮----
public function is_visible( string $id, string $country_code, bool $skip_extension_active_check = false ): bool {
⋮----
if ( ! $skip_extension_active_check && $this->is_extension_active() ) {
⋮----
if ( ! $this->user_has_caps() ) {
⋮----
if ( empty( $this->get_by_id( $id, $country_code ) ) ) {
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Suggestions/Incentives/WooPayments.php">
namespace Automattic\WooCommerce\Internal\Admin\Suggestions\Incentives;
⋮----
use Automattic\WooCommerce\Admin\WCAdminHelper;
use Automattic\WooCommerce\Enums\OrderInternalStatus;
use WC_Abstract_Order;
⋮----
class WooPayments extends Incentive {
⋮----
protected string $cache_transient_name;
⋮----
protected string $store_has_orders_transient_name;
⋮----
protected string $store_had_woopayments_option_name;
⋮----
protected string $store_had_woopayments_version_option_name;
⋮----
private ?array $incentives_memo = null;
⋮----
public function __construct( string $suggestion_id ) {
parent::__construct( $suggestion_id );
⋮----
public function is_visible( string $id, string $country_code, bool $skip_extension_active_check = false ): bool {
⋮----
if ( false === parent::is_visible( $id, $country_code, true ) ) {
⋮----
if ( ! $skip_extension_active_check && $this->is_extension_active() && $this->has_wcpay_account_data() ) {
⋮----
public function clear_cache() {
⋮----
$this->reset_memo();
... (35 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Suggestions/PaymentsExtensionSuggestionIncentives.php">
namespace Automattic\WooCommerce\Internal\Admin\Suggestions;
⋮----
use Automattic\WooCommerce\Internal\Admin\Suggestions\Incentives\Incentive;
use Automattic\WooCommerce\Internal\Admin\Suggestions\Incentives\WooPayments;
⋮----
class PaymentsExtensionSuggestionIncentives {
⋮----
private array $suggestion_incentives_class_map = array(
⋮----
private array $instances = array();
⋮----
public function get_incentive( string $suggestion_id, string $country_code, string $incentive_type = '', bool $skip_visibility_check = false ): ?array {
$incentives = $this->get_incentives( $suggestion_id, $country_code, $incentive_type, $skip_visibility_check );
⋮----
/**
	 * Get the incentives list for a specific payment extension suggestion.
	 *
	 * @param string $suggestion_id         The suggestion ID.
	 * @param string $country_code          The business location country code to get incentives for.
	 * @param string $incentive_type        Optional. The type of incentive to check for.
	 *                                      If not provided, all incentives for the suggestion will be returned.
	 * @param bool   $skip_visibility_check Optional. Whether to skip the visibility check for the incentives.
	 *
	 * @return array The incentives list.
	 */
public function get_incentives( string $suggestion_id, string $country_code, string $incentive_type = '', bool $skip_visibility_check = false ): array {
$provider = $this->get_incentive_instance( $suggestion_id );
⋮----
$incentives = $provider->get_all( $country_code, $incentive_type );
⋮----
... (46 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Suggestions/PaymentsExtensionSuggestions.php">
namespace Automattic\WooCommerce\Internal\Admin\Suggestions;
⋮----
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Internal\Admin\Settings\Payments;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
use Automattic\WooCommerce\Internal\Utilities\ArrayUtil;
⋮----
class PaymentsExtensionSuggestions {
⋮----
private ?array $extensions_base_details_memo = null;
⋮----
private array $country_extensions_memo = array();
⋮----
private array $country_extensions = array(
⋮----
private array $context_to_incentive_type_map = array(
⋮----
private PaymentsExtensionSuggestionIncentives $suggestion_incentives;
⋮----
final public function init( PaymentsExtensionSuggestionIncentives $suggestion_incentives ) {
⋮----
public function get_country_extensions( string $country_code, string $context = '' ): array {
⋮----
// Key on the user since incentive visibility and dismissals are user-specific.
⋮----
if ( ! $this->is_extension_allowed( $extension_id, $country_code, $context ) ) {
⋮----
$extension_base_details = $this->get_extension_base_details( $extension_id ) ?? array();
$extension_details      = $this->with_country_details( $extension_base_details, $extension_country_details );
⋮----
... (106 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/WCPayPromotion/DefaultPromotions.php">
namespace Automattic\WooCommerce\Internal\Admin\WCPayPromotion;
⋮----
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\DefaultPaymentGateways;
⋮----
class DefaultPromotions {
⋮----
public static function get_all(): array {
⋮----
DefaultPaymentGateways::get_rules_for_cbd( false ),
DefaultPaymentGateways::get_rules_for_countries( self::get_woopay_available_countries() ),
⋮----
'sub_title'  => self::get_wcpay_payment_icons(),
⋮----
DefaultPaymentGateways::get_rules_for_countries( DefaultPaymentGateways::get_wcpay_countries() ),
⋮----
private static function get_woopay_available_countries(): array {
⋮----
private static function get_wcpay_payment_icons(): string {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/WCPayPromotion/Init.php">
namespace Automattic\WooCommerce\Internal\Admin\WCPayPromotion;
⋮----
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\EvaluateSuggestion;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
use Automattic\WooCommerce\Admin\RemoteSpecs\RemoteSpecsEngine;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class Init extends RemoteSpecsEngine {
⋮----
public static function possibly_register_pre_install_wc_pay_promotion_gateway( $gateways ) {
if ( self::can_show_promotion() && ! WCPaymentGatewayPreInstallWCPayPromotion::is_dismissed() ) {
⋮----
public static function can_show_promotion() {
⋮----
$wc_pay_spec = self::get_wc_pay_promotion_spec();
⋮----
public static function set_gateway_top_of_list( $ordering ) {
⋮----
public static function get_wc_pay_promotion_spec( $fetch_from_remote = true ) {
$promotions            = $fetch_from_remote ? self::get_promotions() : self::get_cached_or_default_promotions();
⋮----
public static function get_promotions() {
⋮----
$specs           = self::get_specs();
$results         = EvaluateSuggestion::evaluate_specs( $specs, array( 'source' => 'wc-wcpay-promotions' ) );
⋮----
$specs_to_save   = DefaultPromotions::get_all();
$specs_to_return = EvaluateSuggestion::evaluate_specs( $specs_to_save )['suggestions'];
⋮----
self::log_errors( $results['errors'] );
... (28 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/WCPayPromotion/WCPaymentGatewayPreInstallWCPayPromotion.php">
namespace Automattic\WooCommerce\Internal\Admin\WCPayPromotion;
⋮----
use Automattic\WooCommerce\Enums\PaymentGatewayFeature;
⋮----
class WCPaymentGatewayPreInstallWCPayPromotion extends \WC_Payment_Gateway {
⋮----
public function __construct() {
$wc_pay_spec = Init::get_wc_pay_promotion_spec();
⋮----
$this->init_form_fields();
$this->init_settings();
⋮----
public function init_form_fields() {
⋮----
public static function is_dismissed() {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/WCPayPromotion/WCPayPromotionDataSourcePoller.php">
namespace Automattic\WooCommerce\Internal\Admin\WCPayPromotion;
⋮----
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller;
use WC_Helper;
⋮----
class WCPayPromotionDataSourcePoller extends DataSourcePoller {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
self::$instance = new self( self::ID, self::get_data_sources() );
⋮----
public static function get_data_sources() {
⋮----
WC_Helper::get_woocommerce_com_base_url() . 'wp-json/wccom/payment-gateway-suggestions/2.0/payment-method/promotions.json',
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ActivityPanels.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\Notes\Notes;
⋮----
class ActivityPanels {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
public function add_user_data_fields( $user_data_fields ) {
⋮----
public function component_settings( $settings ) {
$settings['alertCount'] = Notes::get_notes_count( array( 'error', 'update' ), array( 'unactioned' ) );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Analytics.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Cache;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Admin\API\Reports\Orders\Stats\DataStore as OrderStatsDataStore;
use Automattic\WooCommerce\Internal\Admin\Schedulers\OrdersScheduler;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
⋮----
class Analytics {
⋮----
protected static $instance = null;
⋮----
protected static $is_updated = false;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
if ( ! FeaturesUtil::feature_is_enabled( 'analytics' ) ) {
⋮----
if ( self::should_show_refund_fix_tool() ) {
⋮----
public static function add_feature_toggle( $features ) {
⋮----
public static function reload_page_on_toggle( $old_value, $value ) {
⋮----
public static function maybe_reload_page() {
⋮----
... (56 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/CategoryLookup.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
class CategoryLookup {
⋮----
protected $edited_product_cats = array();
⋮----
protected static $instance = null;
⋮----
protected function __construct() {}
⋮----
final public static function instance() {
⋮----
public function init() {
⋮----
public function regenerate() {
⋮----
$wpdb->query( "TRUNCATE TABLE $wpdb->wc_category_lookup" );
⋮----
$this->unflatten_terms( $hierarchy, $terms, 0 );
$this->get_term_insert_values( $inserts, $hierarchy );
⋮----
$wpdb->query( "INSERT IGNORE INTO $wpdb->wc_category_lookup (category_tree_id,category_id) VALUES ({$insert_string})" );
⋮----
public function before_edit( $category_id ) {
⋮----
public function on_edit( $category_id ) {
⋮----
$this->delete( $category_id, $prev_parent );
$this->update( $category_id );
⋮----
... (37 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Coupons.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\PageController;
⋮----
class Coupons {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
public function maybe_add_coupon_menu_redirect() {
if ( ! $this->should_display_legacy_menu() ) {
⋮----
public function coupon_menu_moved() {
wp_safe_redirect( $this->get_legacy_coupon_url(), 301 );
⋮----
public function move_coupons( $args ) {
⋮----
public function fix_coupon_menu_highlight() {
⋮----
public function maybe_add_marketing_coupon_script() {
$current_screen = PageController::get_instance()->get_current_page();
⋮----
WCAdminAssets::register_style( 'marketing-coupons', 'style' );
WCAdminAssets::register_script( 'wp-admin-scripts', 'marketing-coupons', true );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/CouponsMovedTrait.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\Features\Features;
⋮----
trait CouponsMovedTrait {
⋮----
protected static $query_key = 'legacy_coupon_menu';
⋮----
protected static $option_key = 'wc_admin_show_legacy_coupon_menu';
⋮----
protected static function get_legacy_coupon_url() {
return self::get_coupon_url( [ self::$query_key => true ] );
⋮----
protected static function get_coupon_url( $args = [] ) {
⋮----
protected static function get_management_url( $page ) {
⋮----
return self::get_coupon_url();
⋮----
$path = self::get_marketing_path();
⋮----
protected static function get_marketing_path() {
⋮----
protected static function should_display_legacy_menu() {
⋮----
! Features::is_enabled( 'navigation' )
⋮----
protected static function display_legacy_menu( $display = false ) {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/CustomerEffortScoreTracks.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
class CustomerEffortScoreTracks {
⋮----
private $onsubmit_label;
⋮----
public function __construct() {
$this->enable_survey_enqueing_if_tracking_is_enabled();
⋮----
private function enable_survey_enqueing_if_tracking_is_enabled() {
⋮----
private function get_script_track_edit_php( $action, $title, $first_question, $second_question ) {
⋮----
private function get_product_count() {
$query         = new \WC_Product_Query(
⋮----
$products      = $query->get_products();
⋮----
private function get_shop_order_count() {
$query            = new \WC_Order_Query(
⋮----
$shop_orders      = $query->get_orders();
⋮----
private function has_been_shown( $action ) {
⋮----
private function enqueue_to_ces_tracks( $item ) {
⋮----
public function enqueue_ces_survey_for_search( $search_area, $page_now, $admin_page ) {
if ( $this->has_been_shown( self::SEARCH_ACTION_NAME ) ) {
⋮----
... (52 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Events.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsEngine;
use Automattic\WooCommerce\Internal\Admin\Notes\CustomizeStoreWithBlocks;
use Automattic\WooCommerce\Internal\Admin\Notes\CustomizingProductCatalog;
use Automattic\WooCommerce\Internal\Admin\Notes\EditProductsOnTheMove;
use Automattic\WooCommerce\Internal\Admin\Notes\EmailImprovements;
use Automattic\WooCommerce\Internal\Admin\Notes\EUVATNumber;
use Automattic\WooCommerce\Internal\Admin\Notes\FirstProduct;
use Automattic\WooCommerce\Internal\Admin\Notes\FullRefundFixDataToolNotice;
use Automattic\WooCommerce\Internal\Admin\Notes\InstallJPAndWCSPlugins;
use Automattic\WooCommerce\Internal\Admin\Notes\LaunchChecklist;
use Automattic\WooCommerce\Internal\Admin\Notes\MagentoMigration;
use Automattic\WooCommerce\Internal\Admin\Notes\ManageOrdersOnTheGo;
use Automattic\WooCommerce\Internal\Admin\Notes\MarketingJetpack;
use Automattic\WooCommerce\Internal\Admin\Notes\MigrateFromShopify;
use Automattic\WooCommerce\Internal\Admin\Notes\MobileApp;
use Automattic\WooCommerce\Internal\Admin\Notes\NewSalesRecord;
use Automattic\WooCommerce\Internal\Admin\Notes\OnboardingPayments;
use Automattic\WooCommerce\Internal\Admin\Notes\OnlineClothingStore;
use Automattic\WooCommerce\Internal\Admin\Notes\OrderMilestones;
use Automattic\WooCommerce\Internal\Admin\Notes\PaymentsMoreInfoNeeded;
use Automattic\WooCommerce\Internal\Admin\Notes\PaymentsRemindMeLater;
use Automattic\WooCommerce\Internal\Admin\Notes\PerformanceOnMobile;
use Automattic\WooCommerce\Internal\Admin\Notes\PersonalizeStore;
use Automattic\WooCommerce\Internal\Admin\Notes\RealTimeOrderAlerts;
use Automattic\WooCommerce\Internal\Admin\Notes\ScheduledUpdatesPromotion;
use Automattic\WooCommerce\Internal\Admin\Notes\SellingOnlineCourses;
use Automattic\WooCommerce\Internal\Admin\Notes\TrackingOptIn;
use Automattic\WooCommerce\Internal\Admin\Notes\UnsecuredReportFiles;
... (72 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/FeaturePlugin.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\API;
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Internal\Admin\Notes\OrderMilestones;
use Automattic\WooCommerce\Internal\Admin\Notes\WooSubscriptionsNotes;
use Automattic\WooCommerce\Internal\Admin\Notes\TrackingOptIn;
use Automattic\WooCommerce\Internal\Admin\Notes\WooCommercePayments;
use Automattic\WooCommerce\Internal\Admin\Notes\InstallJPAndWCSPlugins;
use Automattic\WooCommerce\Internal\Admin\Notes\SellingOnlineCourses;
use Automattic\WooCommerce\Internal\Admin\Notes\MagentoMigration;
use Automattic\WooCommerce\Internal\Admin\Notes\ScheduledUpdatesPromotion;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Admin\PluginsInstaller;
use Automattic\WooCommerce\Admin\ReportExporter;
use Automattic\WooCommerce\Admin\ReportsSync;
use Automattic\WooCommerce\Internal\Admin\CategoryLookup;
use Automattic\WooCommerce\Internal\Admin\Events;
use Automattic\WooCommerce\Internal\Admin\Onboarding\Onboarding;
⋮----
class FeaturePlugin {
⋮----
protected static $instance = null;
⋮----
private bool $initialized = false;
⋮----
protected function __construct() {}
⋮----
final public static function instance() {
... (56 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Homescreen.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\Shipping;
⋮----
class Homescreen {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
public function maybe_set_default_shipping_options_on_home( $settings ) {
⋮----
$zone_count = count( \WC_Data_Store::load( 'shipping-zone' )->get_zones() );
⋮----
$country_name = WC()->countries->get_countries()[ $country_code ] ?? null;
⋮----
$zone = new \WC_Shipping_Zone();
$zone->set_zone_name( $country_name );
$zone->add_location( $country_code, 'country' );
⋮----
$instance_id = $zone->add_shipping_method( 'free_shipping' );
$request     = new \WP_REST_Request( 'POST', '/wc/v2/shipping/zones/' . $zone->get_id() . '/methods/' . $instance_id );
$request->set_body_params(
⋮----
Shipping::delete_zone_count_transient();
⋮----
public function add_user_data_fields( $user_data_fields ) {
⋮----
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Loader.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Orders\DataStore as OrdersDataStore;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Internal\Admin\ProductReviews\Reviews;
use Automattic\WooCommerce\Internal\Admin\ProductReviews\ReviewsCommentsOverrides;
⋮----
class Loader {
⋮----
protected static $instance = null;
⋮----
protected static $classes = array();
⋮----
protected static $required_capability = null;
⋮----
protected $preloaded_dependencies = array(
⋮----
public static function get_instance() {
⋮----
public function __construct() {
Features::get_instance();
WCAdminSharedSettings::get_instance();
Translations::get_instance();
WCAdminUser::get_instance();
Settings::get_instance();
SiteHealth::get_instance();
SystemStatusReport::get_instance();
⋮----
... (125 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Marketing.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\Marketing\InstalledExtensions;
use Automattic\WooCommerce\Admin\PageController;
⋮----
class Marketing {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
public function add_parent_menu_item() {
if ( ! Features::is_enabled( 'navigation' ) ) {
⋮----
PageController::get_instance()->connect_page(
⋮----
public function register_pages() {
$this->register_overview_page();
⋮----
$controller = PageController::get_instance();
⋮----
$controller->connect_page( $marketing_page );
⋮----
$controller->register_page( $marketing_page );
⋮----
protected function register_overview_page() {
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Marketplace.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use WC_Helper_Options;
use WC_Helper_Updater;
⋮----
class Marketplace {
⋮----
final public function init() {
⋮----
public function on_init() {
⋮----
public function register_pages() {
⋮----
$marketplace_pages = $this->get_marketplace_pages();
⋮----
public function get_marketplace_pages() {
⋮----
'title'      => __( 'Extensions', 'woocommerce' ) . $this->badge(),
⋮----
private function badge(): string {
$option = WC_Helper_Options::get( 'my_subscriptions_tab_loaded' );
⋮----
return WC_Helper_Updater::get_updates_count_html();
⋮----
/**
	 * Enqueue update script.
	 *
	 * @param string $hook_suffix The current admin page.
	 */
public function enqueue_scripts( $hook_suffix ) {
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/MobileAppBanner.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
class MobileAppBanner {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
public function add_user_data_fields( $user_data_fields ) {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/OrderMilestoneEasterEgg.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class OrderMilestoneEasterEgg {
⋮----
final public function init(): void {
⋮----
public function clear_milestone_cache(): void {
⋮----
public function handle_ajax_opt_out(): void {
⋮----
public function handle_ajax_dismiss(): void {
⋮----
public function handle_admin_enqueue_scripts(): void {
⋮----
// Respect the user's opt-out preference (debug preview always shows).
⋮----
! OrderUtil::custom_orders_table_usage_is_enabled()
⋮----
|| ! $this->is_qualifying_order( $id_param )
⋮----
$milestone_map = $is_debug_preview ? array() : $this->get_milestone_map();
⋮----
$all_msgs        = $this->get_milestone_messages();
⋮----
$needed_variants = $preview_variant ? array( $preview_variant ) : array_keys( $this->get_variant_map() );
⋮----
$svg_data = $this->get_svg_data( $needed_variants );
... (48 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/OrderTaxLookupMigrator.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
use Automattic\WooCommerce\Admin\API\Reports\Orders\Stats\DataStore as OrderStatsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\Taxes\DataStore as TaxesDataStore;
use Automattic\WooCommerce\Internal\Admin\Schedulers\OrdersScheduler;
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessingController;
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessorInterface;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Exception;
⋮----
class OrderTaxLookupMigrator implements BatchProcessorInterface, RegisterHooksInterface {
⋮----
public function register() {
⋮----
public function get_name(): string {
⋮----
public function get_description(): string {
⋮----
public function get_total_pending_count(): int {
⋮----
if ( ! TaxesDataStore::lookup_is_keyed_by_order_item() ) {
⋮----
$table_name = TaxesDataStore::get_db_table_name();
⋮----
return (int) $wpdb->get_var(
$wpdb->prepare(
⋮----
$this->get_cursor(),
⋮----
... (46 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/RemoteInboxNotifications.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsEngine;
⋮----
class RemoteInboxNotifications {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
RemoteInboxNotificationsEngine::init();
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Settings.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\API\Plugins;
use Automattic\WooCommerce\Admin\API\Reports\Orders\DataStore as OrdersDataStore;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\Admin\Settings\SettingsUIRequestContext;
use Automattic\WooCommerce\Internal\Utilities\PriceSeparators;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
use WC_Marketplace_Suggestions;
⋮----
class Settings {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
public static function get_order_statuses( $statuses ) {
⋮----
/**
	 * Get all order statuses present in analytics tables that aren't registered.
	 *
	 * @return array Unregistered order statuses.
	 */
private function get_unregistered_order_statuses() {
... (127 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ShippingLabelBanner.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\Jetpack\Connection\Manager as Jetpack_Connection_Manager;
use Automattic\WooCommerce\Utilities\OrderUtil;
use function WP_CLI\Utils\get_plugin_name;
⋮----
class ShippingLabelBanner {
⋮----
private $shipping_label_banner_display_rules;
⋮----
public function __construct() {
⋮----
private function should_show_meta_box() {
⋮----
$dotcom_connected = ( new Jetpack_Connection_Manager() )->has_connected_owner();
⋮----
$wcs_version = \Automattic\WCShipping\Utils::get_wcshipping_version();
⋮----
return $this->shipping_label_banner_display_rules->should_display_banner();
⋮----
public function add_meta_boxes() {
if ( ! OrderUtil::is_order_edit_screen() ) {
⋮----
if ( $this->should_show_meta_box() ) {
⋮----
private function count_shippable_items( \WC_Order $order ) {
⋮----
foreach ( $order->get_items() as $item ) {
⋮----
$product = $item->get_product();
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/ShippingLabelBannerDisplayRules.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
class ShippingLabelBannerDisplayRules {
⋮----
private $dotcom_connected;
⋮----
private $no_incompatible_plugins_installed;
⋮----
private $wcs_version;
⋮----
private $supported_countries = array( 'US', 'AS', 'PR', 'VI', 'GU', 'MP', 'UM', 'FM', 'MH' );
⋮----
private $supported_currencies = array( 'USD' );
⋮----
public function __construct( $dotcom_connected, $wcs_version, $incompatible_plugins_installed ) {
⋮----
public function should_display_banner() {
return $this->banner_not_dismissed() &&
⋮----
$this->order_has_shippable_products() &&
$this->store_in_us_and_usd() &&
$this->wcs_not_installed();
⋮----
private function banner_not_dismissed() {
⋮----
private function order_has_shippable_products() {
⋮----
foreach ( $order->get_items() as $item ) {
⋮----
$product = $item->get_product();
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/SiteHealth.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Enums\DefaultCustomerAddress;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer;
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register as Download_Directories;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
use WC_Admin_Notices;
use WC_Admin_Status;
use WC_Helper_Updater;
use WC_Install;
use WC_Order_Query;
use WC_Product_Query;
⋮----
class SiteHealth {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
public function handle_site_status_tests( $tests ) {
⋮----
foreach ( $this->get_woocommerce_site_health_tests() as $test_id => $test ) {
⋮----
return $this->run_test( $test_id );
⋮----
public function run_test( string $test_id ): array {
... (72 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Survey.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
class Survey {
⋮----
public static function get_url( $path, $query = array() ) {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/SystemStatusReport.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\Notes\Notes;
⋮----
class SystemStatusReport {
⋮----
protected static $instance = null;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
public function system_status_report() {
⋮----
$this->render_features();
$this->render_daily_cron();
$this->render_options();
$this->render_notes();
$this->render_onboarding_state();
⋮----
public function render_features() {
⋮----
public function render_daily_cron() {
⋮----
public function render_options() {
⋮----
public function render_notes() {
$notes_count = Notes::get_notes_count();
⋮----
public function render_onboarding_state() {
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/TaxSettingsRecommendations.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
class TaxSettingsRecommendations {
⋮----
final public function init(): void {
⋮----
public function register_routes(): void {
⋮----
public function permissions_check( \WP_REST_Request $request ) {
⋮----
return new \WP_Error(
⋮----
public function dismiss( \WP_REST_Request $request ) {
⋮----
return new \WP_REST_Response( array( 'dismissed' => true ), 200 );
⋮----
public function preload_settings( $settings ) {
</file>

<file path="plugins/woocommerce/src/Internal/Admin/Translations.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Internal\Admin\Loader;
⋮----
class Translations {
⋮----
protected static $instance = null;
⋮----
private static $plugin_domain = 'woocommerce';
⋮----
private $regeneration_attempted = false;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
⋮----
private function get_combined_translation_filename( $domain, $locale ) {
⋮----
private function combine_official_translation_chunks( $json_i18n_filenames ) {
⋮----
if ( ! $wp_filesystem->is_readable( $json_filename ) ) {
⋮----
$file_contents = $wp_filesystem->get_contents( $json_filename );
$chunk_data    = \json_decode( $file_contents, true );
⋮----
private function combine_user_translation_chunks( $json_i18n_filenames ) {
⋮----
private function get_translation_chunk_data( $lang_dir, $domain, $locale ) {
⋮----
... (47 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/WCAdminAssets.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use _WP_Dependency;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Internal\Admin\Loader;
use Automattic\WooCommerce\Internal\Admin\Settings\SettingsUIRequestContext;
⋮----
class WCAdminAssets {
⋮----
protected static $instance = null;
⋮----
protected $preloaded_dependencies;
⋮----
public static function get_instance() {
⋮----
public function __construct() {
Features::get_instance();
⋮----
public static function get_path( $ext ) {
⋮----
public static function should_use_minified_js_file( $script_debug ) {
⋮----
if ( ! Features::exists( 'minified-js' ) ) {
⋮----
public static function get_url( $file, $ext ) {
⋮----
// Potentially enqueue minified JavaScript, but only if the minified file exists.
// Core builds do not ship minified JS files, so this also guards against the
// 'minified-js' feature being force-enabled (e.g. via WooCommerce Beta Tester).
... (114 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/WCAdminSharedSettings.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\PageController;
⋮----
class WCAdminSharedSettings {
⋮----
private $settings_prefix = 'admin';
⋮----
protected static $instance = null;
⋮----
protected function __construct() {
⋮----
$this->on_woocommerce_blocks_loaded();
⋮----
public static function get_instance() {
⋮----
public function on_woocommerce_blocks_loaded() {
⋮----
\Automattic\WooCommerce\Blocks\Package::container()->get( \Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry::class )->add(
⋮----
if ( ! PageController::is_admin_or_embed_page() ) {
⋮----
WCAdminAssets::register_script( 'wp-admin-scripts', 'wcsettings-deprecation', true );
</file>

<file path="plugins/woocommerce/src/Internal/Admin/WCAdminUser.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
class WCAdminUser {
⋮----
protected static $instance = null;
⋮----
public function __construct() {
⋮----
public static function get_instance() {
⋮----
public function register_user_data() {
⋮----
if ( ! $this->current_user_can_read_user_data( $user['id'] ?? 0 ) ) {
⋮----
public function get_user_data_values( $user, $attr = null, $request = array() ) {
⋮----
foreach ( $this->get_user_data_fields() as $field ) {
$values[ $field ] = self::get_user_data_field( $user['id'], $field );
⋮----
private function current_user_can_read_user_data( $user_id ) {
⋮----
public function update_user_data_values( $values, $user, $field_id ) {
⋮----
$fields  = $this->get_user_data_fields();
⋮----
self::update_user_data_field( $user->ID, $field, $value );
⋮----
public function get_user_data_fields() {
⋮----
public static function update_user_data_field( $user_id, $field, $value ) {
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Admin/WcPayWelcomePage.php">
namespace Automattic\WooCommerce\Internal\Admin;
⋮----
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskLists;
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Internal\Admin\Suggestions\PaymentsExtensionSuggestionIncentives;
use Automattic\WooCommerce\Internal\Admin\Suggestions\PaymentsExtensionSuggestions;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WcPayWelcomePage {
⋮----
private PaymentsExtensionSuggestionIncentives $suggestion_incentives;
⋮----
protected static ?WcPayWelcomePage $instance = null;
⋮----
public static function instance(): ?WcPayWelcomePage {
⋮----
public function __construct() {
$this->suggestion_incentives = wc_get_container()->get( PaymentsExtensionSuggestionIncentives::class );
⋮----
public function has_incentive( bool $skip_wcpay_active = false ): bool {
⋮----
if ( ! $skip_wcpay_active && $this->is_wcpay_active() ) {
⋮----
$incentive = $this->get_incentive();
⋮----
if ( $this->is_incentive_dismissed( $incentive ) ) {
⋮----
return $this->suggestion_incentives->is_incentive_visible(
... (44 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Api/Autogenerated/GraphQLController.php">
namespace Automattic\WooCommerce\Internal\Api\Autogenerated;
⋮----
class GraphQLController {
⋮----
public function register(): void {}
</file>

<file path="plugins/woocommerce/src/Internal/BatchProcessing/BatchProcessingController.php">
namespace Automattic\WooCommerce\Internal\BatchProcessing;
⋮----
class BatchProcessingController {
⋮----
private $logger;
⋮----
public function __construct() {
⋮----
$this->handle_watchdog_action();
⋮----
$this->process_next_batch_for_single_processor( $batch_process );
⋮----
$this->remove_or_retry_failed_processors();
⋮----
public function enqueue_processor( string $processor_class_name ): void {
⋮----
if ( $this->enqueued_list_needs_update( $this->get_enqueued_processors(), $processor_class_name ) ) {
$this->mutate_enqueued_processors(
⋮----
$deduplicated_updates = $this->sanitize_processor_list( $pending_updates );
⋮----
$this->schedule_watchdog_action( false, true );
⋮----
private function sanitize_processor_list( array $processors ): array {
⋮----
/**
	 * Determine whether the stored enqueued-processors list needs to be rewritten to include a given processor
	 * or to heal pre-existing corruption (duplicates or non-string entries).
	 *
	 * @since 11.0.0
... (182 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/BatchProcessing/BatchProcessorInterface.php">
namespace Automattic\WooCommerce\Internal\BatchProcessing;
⋮----
interface BatchProcessorInterface {
⋮----
public function get_name() : string;
⋮----
public function get_description() : string;
⋮----
public function get_total_pending_count() : int;
⋮----
public function get_next_batch_to_process( int $size ) : array;
⋮----
public function process_batch( array $batch ): void;
⋮----
public function get_default_batch_size() : int;
</file>

<file path="plugins/woocommerce/src/Internal/Caches/OrdersVersionStringInvalidator.php">
namespace Automattic\WooCommerce\Internal\Caches;
⋮----
class OrdersVersionStringInvalidator {
⋮----
private array $pre_save_customer_ids = array();
⋮----
final public function init(): void {
⋮----
$this->register_hooks();
⋮----
private function register_hooks(): void {
⋮----
public function handle_before_order_save( $order ): void {
if ( ! $order instanceof \WC_Order || 'shop_order' !== $order->get_type() ) {
⋮----
$order_id = $order->get_id();
⋮----
$this->pre_save_customer_ids[ $order_id ] = (int) $order->get_data()['customer_id'];
⋮----
public function handle_woocommerce_new_order( $order_id, $order ): void {
$this->invalidate( (int) $order_id );
$this->invalidate_orders_list();
⋮----
public function handle_woocommerce_update_order( $order_id, $order ): void {
⋮----
$this->invalidate( $order_id );
⋮----
if ( $this->did_customer_change( $order_id, $order ) ) {
⋮----
private function did_customer_change( int $order_id, $order ): bool {
... (35 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Caches/ProductCache.php">
namespace Automattic\WooCommerce\Internal\Caches;
⋮----
use Automattic\WooCommerce\Caching\ObjectCache;
use WC_Product;
⋮----
class ProductCache extends ObjectCache {
⋮----
public function get_object_type(): string {
⋮----
protected function get_object_id( $product ) {
return $product->get_id();
⋮----
protected function validate( $product ): ?array {
⋮----
public function set( $product, $id = null, int $expiration = self::DEFAULT_EXPIRATION ): bool {
⋮----
$original_mode = $product->get_clone_mode();
$product->set_clone_mode( \WC_Data::CLONE_MODE_CACHE );
$result = parent::set( $product, $id, $expiration );
$product->set_clone_mode( $original_mode );
⋮----
public function remove( $id ): bool {
return parent::remove( (int) $id );
⋮----
public function get( $id, int $expiration = self::DEFAULT_EXPIRATION, ?callable $get_from_datastore_callback = null ): ?WC_Product {
⋮----
$product = parent::get( $id, $expiration, $get_from_datastore_callback );
⋮----
$product->set_clone_mode( \WC_Data::CLONE_MODE_DUPLICATE );
</file>

<file path="plugins/woocommerce/src/Internal/Caches/ProductCacheController.php">
namespace Automattic\WooCommerce\Internal\Caches;
⋮----
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class ProductCacheController {
⋮----
private ProductCache $product_cache;
⋮----
final public function init( ProductCache $product_cache ): void {
⋮----
$this->set_product_cache_group_as_non_persistent();
⋮----
public function on_init(): void {
if ( ! FeaturesUtil::feature_is_enabled( self::FEATURE_NAME ) ) {
⋮----
$this->register_hooks();
⋮----
public function register_hooks(): void {
⋮----
public function set_product_cache_group_as_non_persistent(): void {
wp_cache_add_non_persistent_groups( array( $this->product_cache->get_object_type() ) );
⋮----
public function invalidate_product_cache_on_clean( $post_id, $post ): void {
⋮----
$this->product_cache->remove( $post_id );
⋮----
public function invalidate_product_cache( $post_id ): void {
⋮----
public function invalidate_product_cache_by_meta( $meta_id, $object_id ): void {
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Caches/ProductTermCacheInvalidator.php">
namespace Automattic\WooCommerce\Internal\Caches;
⋮----
use WC_Cache_Helper;
⋮----
class ProductTermCacheInvalidator {
⋮----
final public function init(): void {
⋮----
public function handle_clean_taxonomy_cache( $taxonomy ): void {
⋮----
WC_Cache_Helper::invalidate_cache_group( 'product_terms_' . $taxonomy );
</file>

<file path="plugins/woocommerce/src/Internal/Caches/ProductTransientsDeferrer.php">
namespace Automattic\WooCommerce\Internal\Caches;
⋮----
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
⋮----
class ProductTransientsDeferrer {
⋮----
private ProductUtil $product_util;
⋮----
private int $deferral_level = 0;
⋮----
private array $deferred_product_ids = array();
⋮----
final public function init( ProductUtil $product_util ): void {
⋮----
public function start_deferring(): void {
⋮----
public function stop_deferring(): void {
⋮----
$this->flush();
⋮----
public function maybe_defer_deletion( int $product_id ): bool {
⋮----
public function handle_shutdown(): void {
⋮----
private function flush(): void {
⋮----
$this->product_util->delete_product_transients_for_products( $product_ids );
</file>

<file path="plugins/woocommerce/src/Internal/Caches/ProductVersionStringInvalidator.php">
namespace Automattic\WooCommerce\Internal\Caches;
⋮----
use Automattic\WooCommerce\Internal\Features\FeaturesController;
⋮----
class ProductVersionStringInvalidator {
⋮----
final public function init(): void {
⋮----
$this->register_hooks();
⋮----
private function register_hooks(): void {
⋮----
if ( $this->is_using_cpt_data_store() ) {
⋮----
private function is_using_cpt_data_store(): bool {
$data_store = \WC_Data_Store::load( 'product' );
return $data_store->get_current_class_name() === 'WC_Product_Data_Store_CPT';
⋮----
public function handle_save_post_product( $post_id ): void {
⋮----
$this->invalidate( $post_id );
⋮----
public function handle_delete_post( $post_id, $post = null ): void {
⋮----
$this->invalidate_variation_and_parent( $post_id, $parent_id );
$this->invalidate_variations_list( $parent_id );
$this->invalidate_variation_parent_cache( $post_id );
⋮----
$this->invalidate_products_list();
⋮----
... (120 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Caches/TaxRateVersionStringInvalidator.php">
namespace Automattic\WooCommerce\Internal\Caches;
⋮----
class TaxRateVersionStringInvalidator {
⋮----
final public function init(): void {
⋮----
$this->register_hooks();
⋮----
private function register_hooks(): void {
⋮----
public function handle_woocommerce_tax_rate_added( $tax_rate_id ): void {
$this->invalidate( (int) $tax_rate_id );
$this->invalidate_tax_rates_list();
⋮----
public function handle_woocommerce_tax_rate_updated( $tax_rate_id ): void {
⋮----
public function handle_woocommerce_tax_rate_deleted( $tax_rate_id ): void {
⋮----
private function invalidate_tax_rates_list(): void {
wc_get_container()->get( VersionStringGenerator::class )->delete_version( 'list_tax_rates' );
⋮----
public function invalidate( int $tax_rate_id ): void {
wc_get_container()->get( VersionStringGenerator::class )->delete_version( "tax_rate_{$tax_rate_id}" );
</file>

<file path="plugins/woocommerce/src/Internal/Caches/VersionStringGenerator.php">
namespace Automattic\WooCommerce\Internal\Caches;
⋮----
use Automattic\WooCommerce\Proxies\LegacyProxy;
⋮----
class VersionStringGenerator {
⋮----
private ?bool $can_use = null;
⋮----
private LegacyProxy $legacy_proxy;
⋮----
final public function init( LegacyProxy $legacy_proxy ) {
⋮----
public function can_use(): bool {
⋮----
$this->can_use = $this->legacy_proxy->call_function( 'wp_using_ext_object_cache' ) ?? false;
⋮----
public function get_version( string $id, bool $generate = true ): ?string {
$this->validate_input( $id );
⋮----
$cache_key = $this->get_cache_key( $id );
⋮----
$entry_exists = $this->cache_entry_exists( $version, $found );
⋮----
$this->log_invalid_cached_value( $id, $version, $generate );
⋮----
// The new version is written to the same cache key, replacing the invalid
// value, so deleting it first would only add a redundant round-trip.
return $this->generate_version( $id );
⋮----
// Refresh the cache lifetime.
... (47 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Commands/ListCommand.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Commands;
⋮----
use Automattic\WooCommerce\Internal\CLI\Migrator\Core\PlatformRegistry;
use WP_CLI;
⋮----
class ListCommand {
⋮----
private PlatformRegistry $platform_registry;
⋮----
final public function init( PlatformRegistry $platform_registry ): void {
⋮----
public function __invoke( array $args, array $assoc_args ): void {
⋮----
$platforms = $this->platform_registry->get_platforms();
⋮----
WP_CLI::line( 'No migration platforms are registered.' );
⋮----
// Add separator row between platforms (but not after the last one).
⋮----
WP_CLI\Utils\format_items(
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Commands/ProductsCommand.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Commands;
⋮----
use Automattic\WooCommerce\Internal\CLI\Migrator\Core\CredentialManager;
use Automattic\WooCommerce\Internal\CLI\Migrator\Core\PlatformRegistry;
use Automattic\WooCommerce\Internal\CLI\Migrator\Core\ProductsController;
use WP_CLI;
⋮----
final class ProductsCommand {
⋮----
private CredentialManager $credential_manager;
⋮----
private PlatformRegistry $platform_registry;
⋮----
private ProductsController $products_controller;
⋮----
final public function init( CredentialManager $credential_manager, PlatformRegistry $platform_registry, ProductsController $products_controller ): void {
⋮----
public function __invoke( array $args, array $assoc_args ): void {
⋮----
$platform              = $this->platform_registry->resolve_platform( $assoc_args );
$platform_display_name = $this->platform_registry->get_platform_display_name( $platform );
⋮----
if ( ! $this->credential_manager->has_credentials( $platform ) ) {
WP_CLI::log( "Credentials for '{$platform_display_name}' not found. Let's set them up." );
⋮----
$required_fields = $this->platform_registry->get_platform_credential_fields( $platform );
⋮----
WP_CLI::error( "The platform '{$platform_display_name}' does not have configured credential fields." );
⋮----
$this->credential_manager->setup_credentials( $platform, $required_fields );
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Commands/ResetCommand.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Commands;
⋮----
use Automattic\WooCommerce\Internal\CLI\Migrator\Core\CredentialManager;
use Automattic\WooCommerce\Internal\CLI\Migrator\Core\PlatformRegistry;
use WP_CLI;
⋮----
class ResetCommand {
⋮----
private CredentialManager $credential_manager;
⋮----
private PlatformRegistry $platform_registry;
⋮----
final public function init( CredentialManager $credential_manager, PlatformRegistry $platform_registry ): void {
⋮----
public function __invoke( array $args, array $assoc_args ) {
⋮----
$platform              = $this->platform_registry->resolve_platform( $assoc_args );
$platform_display_name = $this->platform_registry->get_platform_display_name( $platform );
⋮----
if ( ! $this->credential_manager->has_credentials( $platform ) ) {
WP_CLI::warning( "No credentials found for '{$platform_display_name}' to reset." );
⋮----
$this->credential_manager->delete_credentials( $platform );
⋮----
WP_CLI::success( "Credentials for the '{$platform_display_name}' platform have been cleared." );
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Commands/SetupCommand.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Commands;
⋮----
use Automattic\WooCommerce\Internal\CLI\Migrator\Core\CredentialManager;
use Automattic\WooCommerce\Internal\CLI\Migrator\Core\PlatformRegistry;
use WP_CLI;
⋮----
class SetupCommand {
⋮----
private CredentialManager $credential_manager;
⋮----
private PlatformRegistry $platform_registry;
⋮----
final public function init( CredentialManager $credential_manager, PlatformRegistry $platform_registry ): void {
⋮----
public function __invoke( array $args, array $assoc_args ) {
⋮----
$platform              = $this->platform_registry->resolve_platform( $assoc_args );
$platform_display_name = $this->platform_registry->get_platform_display_name( $platform );
⋮----
$required_fields = $this->platform_registry->get_platform_credential_fields( $platform );
⋮----
WP_CLI::error( "The platform '{$platform_display_name}' does not have configured credential fields." );
⋮----
$this->credential_manager->setup_credentials( $platform, $required_fields );
WP_CLI::success( 'Credentials saved successfully.' );
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Core/CredentialManager.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Core;
⋮----
use WP_CLI;
⋮----
class CredentialManager {
⋮----
public function get_credentials( string $platform_slug ): ?array {
⋮----
public function has_credentials( string $platform_slug ): bool {
$credentials = $this->get_credentials( $platform_slug );
⋮----
public function prompt_for_credentials( array $fields ): array {
⋮----
$credentials[ $key ] = $this->readline( $prompt . ' ' );
⋮----
public function save_credentials( string $platform_slug, array $credentials ): void {
⋮----
public function delete_credentials( string $platform_slug ): void {
⋮----
public function setup_credentials( string $platform_slug, array $required_fields ): void {
⋮----
WP_CLI::error( 'No credential fields specified for setup.' );
⋮----
WP_CLI::log( 'Configuring credentials for ' . ucfirst( $platform_slug ) . '...' );
⋮----
$credentials = $this->prompt_for_credentials( $required_fields );
$this->save_credentials( $platform_slug, $credentials );
⋮----
private function readline( string $prompt ): string {
⋮----
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Core/MigratorTracker.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Core;
⋮----
class MigratorTracker {
⋮----
private array $current_session = array();
⋮----
public function __construct() {
$this->init_hooks();
⋮----
private function init_hooks(): void {
⋮----
public function on_session_started( string $platform, array $metadata ): void {
⋮----
public function on_batch_processed( array $batch_results, array $source_data, array $mapped_data ): void {
⋮----
$this->track_product_types( $mapped_data, $batch_results );
⋮----
public function on_session_completed( string $platform, array $final_stats ): void {
⋮----
wc_get_logger()->warning(
⋮----
$this->save_session_data();
⋮----
private function track_product_types( array $mapped_data, array $batch_results ): void {
⋮----
// Only track types for successfully imported products.
⋮----
private function save_session_data(): void {
$analytics = $this->get_stored_analytics();
⋮----
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Core/PlatformRegistry.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Core;
⋮----
use InvalidArgumentException;
use Automattic\WooCommerce\Internal\CLI\Migrator\Interfaces\PlatformFetcherInterface;
use Automattic\WooCommerce\Internal\CLI\Migrator\Interfaces\PlatformMapperInterface;
use WP_CLI;
⋮----
class PlatformRegistry {
⋮----
private array $platforms = array();
⋮----
private CredentialManager $credential_manager;
⋮----
public function __construct() {
$this->load_platforms();
⋮----
final public function init( CredentialManager $credential_manager ): void {
⋮----
private function load_platforms(): void {
⋮----
public function get_platforms(): array {
⋮----
public function get_platform( string $platform_id ): ?array {
⋮----
public function get_fetcher( string $platform_id ): PlatformFetcherInterface {
$platform = $this->get_platform( $platform_id );
⋮----
$credentials = $this->credential_manager->get_credentials( $platform_id );
⋮----
return new $fetcher_class( $credentials );
... (24 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Core/ProductsController.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Core;
⋮----
use Automattic\WooCommerce\Internal\CLI\Migrator\Core\CredentialManager;
use Automattic\WooCommerce\Internal\CLI\Migrator\Core\MigratorTracker;
use Automattic\WooCommerce\Internal\CLI\Migrator\Core\PlatformRegistry;
use Automattic\WooCommerce\Internal\CLI\Migrator\Core\WooCommerceProductImporter;
use Automattic\WooCommerce\Internal\CLI\Migrator\Lib\ImportSession;
use Exception;
use WP_CLI;
⋮----
class ProductsController {
⋮----
private CredentialManager $credential_manager;
⋮----
private PlatformRegistry $platform_registry;
⋮----
private ?ImportSession $session = null;
⋮----
private array $parsed_args = array();
⋮----
private array $fields_to_process = array();
⋮----
private WooCommerceProductImporter $product_importer;
⋮----
private MigratorTracker $tracker;
⋮----
private int $session_start_time = 0;
⋮----
final public function init(
⋮----
... (272 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Core;
⋮----
use WC_Product;
use WC_Product_Simple;
use WC_Product_Variable;
use WC_Product_Variation;
use WP_Error;
use Exception;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WooCommerceProductImporter {
⋮----
private array $import_options;
⋮----
private $progress_callback = null;
⋮----
private array $import_stats = array(
⋮----
private array $migration_data = array(
⋮----
private array $current_attribute_mapping = array();
⋮----
public function __construct() {
$this->import_options = $this->get_default_options();
⋮----
public function configure( array $options ): void {
⋮----
public function set_progress_callback( ?callable $callback ): void {
⋮----
public function import_product( array $product_data, array $source_data = array() ): array {
... (311 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Interfaces/PlatformFetcherInterface.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Interfaces;
⋮----
interface PlatformFetcherInterface {
⋮----
public function fetch_batch( array $args ): array;
⋮----
public function fetch_total_count( array $args ): int;
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Interfaces/PlatformMapperInterface.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Interfaces;
⋮----
interface PlatformMapperInterface {
⋮----
public function map_product_data( object $platform_data ): array;
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Lib/ImportSession.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Lib;
⋮----
use WP_Query;
⋮----
use function get_all_post_meta_flat;
use function is_wp_error;
⋮----
class ImportSession {
⋮----
private $post_id;
private $cached_stage;
⋮----
public static function create( $args ) {
⋮----
throw new \Exception( 'File name is required for WXR file imports' );
⋮----
throw new \Exception( 'Source URL is required for remote imports' );
⋮----
throw new \Exception( 'File name is required for Markdown ZIP imports' );
⋮----
throw new \Exception( 'Directory path is required for local directory imports' );
⋮----
throw new \Exception( 'Error creating an import session: ' . $post_id->get_error_message() );
⋮----
public static function by_id( $post_id ) {
⋮----
public static function get_active() {
⋮----
public function __construct( $post_id ) {
⋮----
... (88 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/README.md">
# Shopify Platform - Technical Reference

Production-ready Shopify to WooCommerce migration platform. For general usage instructions, see the [CLI Migrator documentation](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Internal/CLI/Migrator/README.md).

## Architecture

| Component | Purpose | File |
|-----------|---------|------|
| **ShopifyPlatform** | Platform registration | [`ShopifyPlatform.php`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyPlatform.php) |
| **ShopifyClient** | API communication (REST + GraphQL) | [`ShopifyClient.php`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyClient.php) |
| **ShopifyFetcher** | Data retrieval (implements [`PlatformFetcherInterface`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Internal/CLI/Migrator/Interfaces/PlatformFetcherInterface.php)) | [`ShopifyFetcher.php`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyFetcher.php) |
| **ShopifyMapper** | Data transformation (implements [`PlatformMapperInterface`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Internal/CLI/Migrator/Interfaces/PlatformMapperInterface.php)) | [`ShopifyMapper.php`](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyMapper.php) |

## API Integration

- **Shopify API Version**: `2025-04`
- **Authentication**: X-Shopify-Access-Token header
- **Data Retrieval**: GraphQL for complex queries, REST for counts
- **Pagination**: Cursor-based with `edges` and `pageInfo`

## Key Features

### Data Fetching

- Comprehensive GraphQL query retrieving products, variants, images, collections, metafields
- Filtering support: status, vendor, product type, date ranges, specific IDs
- Batch processing with configurable limits (default: 50 products per batch)

### Data Mapping

... (126 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyClient.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Platforms\Shopify;
⋮----
class ShopifyClient {
⋮----
private array $credentials;
⋮----
public function __construct( array $credentials ) {
⋮----
public function rest_request( string $path, array $query_params = array(), string $method = 'GET', array $body = array() ) {
$credentials = $this->get_credentials();
⋮----
$rest_endpoint = $this->build_rest_url( $credentials['domain'], $path, $query_params );
$request_args  = $this->build_request_args( $credentials['access_token'], $method, $body );
⋮----
return $this->process_response( $response, $path );
⋮----
public function graphql_request( string $query, array $variables = array() ) {
⋮----
$graphql_endpoint = $this->build_graphql_url( $credentials['domain'] );
$request_args     = $this->build_graphql_request_args( $credentials['access_token'], $query, $variables );
⋮----
return $this->process_graphql_response( $response );
⋮----
private function get_credentials() {
⋮----
return new \WP_Error(
⋮----
private function build_rest_url( string $domain, string $path, array $query_params ): string {
⋮----
private function build_request_args( string $access_token, string $method, array $body ): array {
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyFetcher.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Platforms\Shopify;
⋮----
use Automattic\WooCommerce\Internal\CLI\Migrator\Interfaces\PlatformFetcherInterface;
⋮----
class ShopifyFetcher implements PlatformFetcherInterface {
⋮----
private $shopify_client;
⋮----
private array $credentials;
⋮----
public function __construct( array $credentials ) {
⋮----
public function fetch_batch( array $args ): array {
$variables = $this->build_graphql_variables( $args );
⋮----
$response_data = $this->shopify_client->graphql_request( self::SHOPIFY_PRODUCT_QUERY, $variables );
⋮----
\WP_CLI::warning( 'Failed to fetch products via GraphQL: ' . $response_data->get_error_message() );
⋮----
\WP_CLI::warning( 'Invalid GraphQL response structure - missing products.edges field.' );
⋮----
private function build_graphql_variables( array $args ): array {
⋮----
'query'         => $this->build_graphql_query_string( $args ),
⋮----
/**
	 * Build GraphQL query string from filter arguments.
	 *
	 * @param array $args Filter arguments.
	 * @return string GraphQL query string.
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyMapper.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Platforms\Shopify;
⋮----
use Automattic\WooCommerce\Enums\WeightUnit;
use Automattic\WooCommerce\Internal\CLI\Migrator\Interfaces\PlatformMapperInterface;
⋮----
class ShopifyMapper implements PlatformMapperInterface {
⋮----
private $fields_to_process = array();
⋮----
public function __construct( array $args = array() ) {
$this->fields_to_process = $args['fields'] ?? $this->get_default_product_fields();
⋮----
public function map_product_data( object $shopify_product ): array {
$is_variable = $this->is_variable_product( $shopify_product );
⋮----
$wc_data = $this->map_basic_product_fields( $shopify_product, $is_variable );
⋮----
$simple_data = $this->map_simple_product_data( $shopify_product );
⋮----
$wc_data['images'] = $this->map_product_images( $shopify_product );
⋮----
$wc_data['metafields'] = $this->map_metafields( $shopify_product );
⋮----
$variable_data = $this->map_variable_product_data( $shopify_product, $is_variable );
⋮----
private function is_variable_product( object $shopify_product ): bool {
⋮----
private function get_woo_product_status( object $shopify_product ): string {
⋮----
private function map_enhanced_status( object $shopify_product ): array {
... (56 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyPlatform.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Platforms\Shopify;
⋮----
class ShopifyPlatform {
⋮----
final public static function init(): void {
⋮----
public static function register_platform( array $platforms ): array {
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Webflow/WebflowClient.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Platforms\Webflow;
⋮----
class WebflowClient {
⋮----
private array $credentials;
⋮----
public function __construct( array $credentials ) {
⋮----
public function rest_request( string $path, array $query_params = array() ) {
$credentials = $this->get_credentials();
⋮----
return $this->process_response( $response, $path );
⋮----
return new \WP_Error( 'api_error', "REST request to {$path} exceeded retry budget after repeated 429 responses." );
⋮----
public function get_site_id() {
⋮----
return new \WP_Error(
⋮----
private function get_credentials() {
⋮----
private function process_response( $response, string $path ) {
⋮----
return new \WP_Error( 'api_error', 'REST request failed: ' . $response->get_error_message() );
⋮----
return new \WP_Error( 'api_error', 'Failed to decode REST JSON response: ' . json_last_error_msg() );
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Webflow/WebflowFetcher.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Platforms\Webflow;
⋮----
use Automattic\WooCommerce\Internal\CLI\Migrator\Interfaces\PlatformFetcherInterface;
⋮----
class WebflowFetcher implements PlatformFetcherInterface {
⋮----
private WebflowClient $webflow_client;
⋮----
private ?array $category_cache = null;
⋮----
public function __construct( array $credentials ) {
⋮----
public function fetch_batch( array $args ): array {
$site_id = $this->webflow_client->get_site_id();
⋮----
\WP_CLI::warning( 'Failed to fetch Webflow products: ' . $site_id->get_error_message() );
return $this->empty_batch();
⋮----
$response = $this->webflow_client->rest_request( "/sites/{$site_id}/products", $query );
⋮----
\WP_CLI::warning( 'Failed to fetch products from Webflow: ' . $response->get_error_message() );
⋮----
\WP_CLI::warning( 'Invalid Webflow response: missing items array.' );
⋮----
$this->ensure_category_cache_loaded( $site_id );
$this->decorate_items_with_categories( $items );
⋮----
public function fetch_total_count( array $args ): int {
⋮----
\WP_CLI::warning( 'Could not fetch Webflow product count: ' . $site_id->get_error_message() );
... (34 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Webflow/WebflowMapper.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Platforms\Webflow;
⋮----
use Automattic\WooCommerce\Internal\CLI\Migrator\Interfaces\PlatformMapperInterface;
⋮----
class WebflowMapper implements PlatformMapperInterface {
⋮----
private array $fields_to_process = array();
⋮----
private ?array $currency_decimals = null;
⋮----
public function __construct( array $args = array() ) {
⋮----
public function map_product_data( object $platform_data ): array {
$product    = $this->extract_product( $platform_data );
$field_data = $this->extract_field_data( $product );
$skus       = $this->extract_skus( $platform_data );
⋮----
$properties = $this->extract_sku_properties( $field_data );
⋮----
$wc_data = $this->map_basic_fields( $product, $field_data, $is_variable );
⋮----
$wc_data['categories'] = $this->should_process( 'categories' ) ? $this->map_categories( $platform_data ) : array();
⋮----
$images            = $this->should_process( 'images' ) ? $this->build_images( $field_data, $skus ) : array();
⋮----
$wc_data = array_merge( $wc_data, $this->map_variable_data( $properties, $skus, $images ) );
⋮----
$wc_data               = array_merge( $wc_data, $this->map_simple_data( $skus ) );
⋮----
$wc_data['metafields'] = $this->map_seo( $field_data );
... (111 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Webflow/WebflowPlatform.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator\Platforms\Webflow;
⋮----
class WebflowPlatform {
⋮----
final public static function init(): void {
⋮----
public static function register_platform( array $platforms ): array {
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/README.md">
# WooCommerce CLI Migrator

A command-line tool for migrating products from external e-commerce platforms to WooCommerce.

## Available Commands

| Command | Description | Example |
|---------|-------------|---------|
| `setup` | Configure platform credentials | `wp wc migrate setup [--platform=shopify]` |
| `products` | Migrate products from source platform | `wp wc migrate products --platform=shopify` |
| `list` | List all registered migration platforms | `wp wc migrate list` |
| `reset` | Reset platform credentials | `wp wc migrate reset [--platform=shopify]` |

## Basic Usage

1. **Configure platform credentials:**

   ```bash
   wp wc migrate setup
   ```

2. **Migrate products:**

   ```bash
   # Get product count
   wp wc migrate products --count
   
   # Migrate all products
   wp wc migrate products
   
... (305 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CLI/Migrator/Runner.php">
namespace Automattic\WooCommerce\Internal\CLI\Migrator;
⋮----
use Automattic\WooCommerce\Internal\CLI\Migrator\Commands\ProductsCommand;
use Automattic\WooCommerce\Internal\CLI\Migrator\Commands\ResetCommand;
use Automattic\WooCommerce\Internal\CLI\Migrator\Commands\SetupCommand;
use Automattic\WooCommerce\Internal\CLI\Migrator\Commands\ListCommand;
use Automattic\WooCommerce\Internal\CLI\Migrator\Platforms\Shopify\ShopifyPlatform;
use Automattic\WooCommerce\Internal\CLI\Migrator\Platforms\Webflow\WebflowPlatform;
use WP_CLI;
use WC_Product_Factory;
⋮----
final class Runner {
⋮----
public static function register_commands(): void {
⋮----
self::init_platforms();
⋮----
WP_CLI::add_command(
⋮----
$container->get( ProductsCommand::class ),
⋮----
$container->get( ResetCommand::class ),
⋮----
$container->get( SetupCommand::class ),
⋮----
$container->get( ListCommand::class ),
⋮----
private static function init_platforms(): void {
ShopifyPlatform::init();
WebflowPlatform::init();
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ComingSoon/ComingSoonAdminBarBadge.php">
namespace Automattic\WooCommerce\Internal\ComingSoon;
⋮----
class ComingSoonAdminBarBadge {
⋮----
private function is_badge_enabled(): bool {
⋮----
final public function init() {
⋮----
public function init_hooks() {
⋮----
public function site_visibility_badge( $wp_admin_bar ) {
if ( ! $this->is_badge_enabled() ) {
⋮----
$wp_admin_bar->add_node( $args );
⋮----
public function output_css() {
</file>

<file path="plugins/woocommerce/src/Internal/ComingSoon/ComingSoonCacheInvalidator.php">
namespace Automattic\WooCommerce\Internal\ComingSoon;
⋮----
class ComingSoonCacheInvalidator {
⋮----
final public function init() {
⋮----
public function invalidate_caches() {
</file>

<file path="plugins/woocommerce/src/Internal/ComingSoon/ComingSoonHelper.php">
namespace Automattic\WooCommerce\Internal\ComingSoon;
⋮----
use Automattic\WooCommerce\Admin\WCAdminHelper;
⋮----
class ComingSoonHelper {
⋮----
public function is_site_live(): bool {
⋮----
public function is_site_coming_soon(): bool {
⋮----
public function is_store_coming_soon(): bool {
⋮----
public function is_current_page_coming_soon(): bool {
⋮----
if ( $this->is_site_live() ) {
⋮----
if ( $this->is_site_coming_soon() ) {
⋮----
if ( $this->is_store_coming_soon() && WCAdminHelper::is_current_page_store_page() ) {
</file>

<file path="plugins/woocommerce/src/Internal/ComingSoon/ComingSoonRequestHandler.php">
namespace Automattic\WooCommerce\Internal\ComingSoon;
⋮----
use Automattic\WooCommerce\Blocks\BlockTemplatesController;
use Automattic\WooCommerce\Blocks\BlockTemplatesRegistry;
use Automattic\WooCommerce\Blocks\Package as BlocksPackage;
use Automattic\Jetpack\Constants;
⋮----
class ComingSoonRequestHandler {
⋮----
private $coming_soon_helper = null;
⋮----
private static $show_coming_soon = false;
⋮----
final public function init( ComingSoonHelper $coming_soon_helper ) {
⋮----
if ( $this->coming_soon_helper->is_site_live() ) {
⋮----
public function possibly_init_block_templates() {
⋮----
$container = BlocksPackage::container();
$container->get( BlockTemplatesRegistry::class )->init();
$container->get( BlockTemplatesController::class )->init();
⋮----
public function handle_template_include( $template ) {
if ( ! $this->should_show_coming_soon() ) {
⋮----
$is_store_coming_soon = $this->coming_soon_helper->is_store_coming_soon();
⋮----
// In non-FSE themes, other templates will still be rendered.
// We need to exit to prevent further processing.
... (34 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CostOfGoodsSold/CogsAwareRestControllerTrait.php">
namespace Automattic\WooCommerce\Internal\CostOfGoodsSold;
⋮----
trait CogsAwareRestControllerTrait {
⋮----
private function add_cogs_info_to_returned_product_data( array &$data, $product ): void {
if ( ! $this->cogs_is_enabled() ) {
⋮----
'defined_value'   => $product->get_cogs_value(),
'effective_value' => $product->get_cogs_effective_value(),
⋮----
'total_value' => $product->get_cogs_total_value(),
⋮----
$data['cost_of_goods_sold']['defined_value_is_additive'] = $product->get_cogs_value_is_additive();
⋮----
private function set_cogs_info_in_product_object( $request, $product ): void {
⋮----
$product->set_cogs_value( $value );
⋮----
$product->set_cogs_value_is_additive( $is_additive );
⋮----
private function add_cogs_related_product_schema( array $schema, bool $for_variations_controller ): array {
</file>

<file path="plugins/woocommerce/src/Internal/CostOfGoodsSold/CogsAwareTrait.php">
namespace Automattic\WooCommerce\Internal\CostOfGoodsSold;
⋮----
use Automattic\WooCommerce\Proxies\LegacyProxy;
⋮----
trait CogsAwareTrait {
⋮----
protected function cogs_is_enabled( ?string $doing_it_wrong_function_name = null ): bool {
if ( wc_get_container()->get( CostOfGoodsSoldController::class )->feature_is_enabled() ) {
⋮----
wc_get_container()->get( LegacyProxy::class )->call_function(
</file>

<file path="plugins/woocommerce/src/Internal/CostOfGoodsSold/CogsAwareUnitTestSuiteTrait.php">
namespace Automattic\WooCommerce\Internal\CostOfGoodsSold;
⋮----
trait CogsAwareUnitTestSuiteTrait {
⋮----
private function enable_cogs_feature() {
⋮----
private function disable_cogs_feature() {
⋮----
private function expect_doing_it_wrong_cogs_disabled( string $method_name ) {
$this->register_legacy_proxy_function_mocks(
⋮----
throw new \Exception( "Doing it wrong, function: '$function_name', message: '$message'" );
⋮----
$this->expectExceptionMessage( "Doing it wrong, function: '{$method_name}', message: 'The Cost of Goods sold feature is disabled, thus the method called will do nothing and will return dummy data.'" );
</file>

<file path="plugins/woocommerce/src/Internal/CostOfGoodsSold/CostOfGoodsSoldController.php">
namespace Automattic\WooCommerce\Internal\CostOfGoodsSold;
⋮----
use Automattic\WooCommerce\Enums\FeaturePluginCompatibility;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
⋮----
class CostOfGoodsSoldController implements RegisterHooksInterface {
⋮----
private FeaturesController $features_controller;
⋮----
public function register() {
⋮----
final public function init( FeaturesController $features_controller ) {
⋮----
public function feature_is_enabled(): bool {
return $this->features_controller->feature_is_enabled( 'cost_of_goods_sold' );
⋮----
public function add_feature_definition( $features_controller ) {
⋮----
$features_controller->add_feature_definition(
⋮----
public function add_debug_tools_entry( array $tools_array ): array {
⋮----
$column_exists = $this->product_meta_lookup_table_cogs_value_columns_exist();
if ( ! $this->feature_is_enabled() && ! $column_exists ) {
⋮----
public function generate_lookup_cogs_columns() {
⋮----
if ( $this->feature_is_enabled() && ! $this->product_meta_lookup_table_cogs_value_columns_exist() ) {
$wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_product_meta_lookup ADD COLUMN cogs_total_value DECIMAL(19,4)" );
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CustomerEmailVerification/Admin/UserProfileField.php">
namespace Automattic\WooCommerce\Internal\CustomerEmailVerification\Admin;
⋮----
use Automattic\WooCommerce\Internal\CustomerEmailVerification\EmailVerificationService;
use WP_User;
⋮----
class UserProfileField {
⋮----
private $service;
⋮----
public function __construct() {
⋮----
final public function init( EmailVerificationService $service ): void {
⋮----
public function render( $user ): void {
⋮----
<input type="checkbox" name="<?php echo esc_attr( self::FIELD ); ?>" id="<?php echo esc_attr( self::FIELD ); ?>" value="1" <?php checked( $this->service->is_verified( $user->ID ) ); ?> />
⋮----
public function save( $user_id ): void {
⋮----
// profile_update fires on every wp_update_user() call, so the nonce is what scopes us to a
// profile-screen submission where our field was actually rendered; without it we would clear
// verification on every unrelated user update.
⋮----
$this->service->mark_verified( $user_id );
⋮----
$this->service->clear_verification( $user_id );
</file>

<file path="plugins/woocommerce/src/Internal/CustomerEmailVerification/Emails/CustomerVerifyEmail.php">
namespace Automattic\WooCommerce\Internal\CustomerEmailVerification\Emails;
⋮----
use WC_Customer;
use WC_Email;
use WP_User;
⋮----
class CustomerVerifyEmail extends WC_Email {
⋮----
public $verify_url;
⋮----
public $user_display_name;
⋮----
public $user_email;
⋮----
public $user_login;
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function get_default_additional_content() {
⋮----
public function trigger( $user_id, $verify_url = '' ) {
$this->setup_locale();
⋮----
$first_name              = ! empty( $customer->get_billing_first_name() ) ? $customer->get_billing_first_name() : $this->object->first_name;
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CustomerEmailVerification/CustomerEmailVerification.php">
namespace Automattic\WooCommerce\Internal\CustomerEmailVerification;
⋮----
use Automattic\WooCommerce\Internal\CustomerEmailVerification\Admin\UserProfileField;
use Automattic\WooCommerce\Internal\CustomerEmailVerification\Emails\CustomerVerifyEmail;
⋮----
class CustomerEmailVerification {
⋮----
public function __construct() {
⋮----
public function init_hooks(): void {
⋮----
$container->get( VerificationController::class );
$container->get( VerificationEventListener::class );
⋮----
$container->get( UserProfileField::class );
⋮----
public function register_email_classes( array $emails ): array {
</file>

<file path="plugins/woocommerce/src/Internal/CustomerEmailVerification/EmailVerificationService.php">
namespace Automattic\WooCommerce\Internal\CustomerEmailVerification;
⋮----
use Automattic\WooCommerce\Internal\Utilities\Users;
⋮----
class EmailVerificationService {
⋮----
private function get_account_email( int $user_id ): ?string {
⋮----
public function is_verified( int $user_id ): bool {
$verified_email = (string) Users::get_site_user_meta( $user_id, self::VERIFIED_META );
⋮----
return '' !== $verified_email && $verified_email === $this->get_account_email( $user_id );
⋮----
/**
	 * Mark the given user as having verified their current account email address.
	 *
	 * Stores the verified email address, clears any pending key, and fires the
	 * {@see 'woocommerce_customer_email_verified'} action. No-ops if the user is already
	 * verified for their current email.
	 *
	 * @since 11.0.0
	 *
	 * @param int $user_id WordPress user ID.
	 * @return void
	 */
public function mark_verified( int $user_id ): void {
if ( $this->is_verified( $user_id ) ) {
⋮----
$account_email = $this->get_account_email( $user_id );
⋮----
... (83 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CustomerEmailVerification/VerificationController.php">
namespace Automattic\WooCommerce\Internal\CustomerEmailVerification;
⋮----
class VerificationController {
⋮----
private $service;
⋮----
public function __construct() {
⋮----
final public function init( EmailVerificationService $service ): void {
⋮----
public function maybe_process_request(): void {
⋮----
$this->handle_send_request();
⋮----
$this->handle_verify_link(
⋮----
private function handle_verify_link( int $user_id, string $key ): void {
⋮----
$this->redirect_with_result( 'mismatch' );
⋮----
if ( $this->process_verification( $user_id, $key ) ) {
$this->redirect_with_result( 'confirmed' );
⋮----
if ( $this->service->is_verified( $user_id ) ) {
⋮----
$this->redirect_with_result( 'expired' );
⋮----
public function handle_send_request(): void {
⋮----
$this->redirect_with_result( 'invalid' );
... (48 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/CustomerEmailVerification/VerificationEventListener.php">
namespace Automattic\WooCommerce\Internal\CustomerEmailVerification;
⋮----
use WP_User;
⋮----
class VerificationEventListener {
⋮----
private $service;
⋮----
public function __construct() {
⋮----
final public function init( EmailVerificationService $service ): void {
⋮----
public function on_password_reset( $user ): void {
⋮----
$this->service->mark_verified( $user->ID );
</file>

<file path="plugins/woocommerce/src/Internal/Customers/SearchService.php">
namespace Automattic\WooCommerce\Internal\Customers;
⋮----
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
final class SearchService {
⋮----
public function find_user_ids_by_billing_email_for_coupons_usage_lookup( array $emails ): array {
⋮----
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
⋮----
$include_user_ids = $wpdb->get_col(
$wpdb->prepare(
⋮----
OrdersTableDataStore::get_orders_table_name(),
⋮----
$users_query = new \WP_User_Query(
⋮----
return array_map( 'intval', array_unique( $users_query->get_results() ) );
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/Orders/CustomOrdersTableController.php">
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
⋮----
use Automattic\WooCommerce\Caches\OrderCache;
use Automattic\WooCommerce\Caches\OrderCacheController;
use Automattic\WooCommerce\Enums\FeaturePluginCompatibility;
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessingController;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Utilities\PluginUtil;
use WC_Admin_Settings;
⋮----
class CustomOrdersTableController {
⋮----
private $data_store;
⋮----
private $refund_data_store;
⋮----
private $data_synchronizer;
⋮----
private $data_cleanup;
⋮----
private $batch_processing_controller;
⋮----
private $features_controller;
⋮----
private $order_cache;
⋮----
private $order_cache_controller;
⋮----
... (154 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/Orders/DataSynchronizer.php">
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
⋮----
use Automattic\WooCommerce\Caches\OrderCacheController;
use Automattic\WooCommerce\Database\Migrations\CustomOrderTable\PostsToOrdersMigrationController;
use Automattic\WooCommerce\Internal\Admin\Orders\EditLock;
use Automattic\WooCommerce\Internal\BatchProcessing\{ BatchProcessingController, BatchProcessorInterface };
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
use Automattic\WooCommerce\Proxies\LegacyProxy;
⋮----
class DataSynchronizer implements BatchProcessorInterface {
⋮----
private $data_store;
⋮----
private $database_util;
⋮----
private $posts_to_cot_migrator;
⋮----
private $error_logger;
⋮----
private $legacy_proxy;
⋮----
private $order_cache_controller;
⋮----
private $batch_processing_controller;
⋮----
public function __construct() {
⋮----
if ( self::BACKGROUND_SYNC_MODE_CONTINUOUS === $this->get_background_sync_mode() ) {
⋮----
$this->unschedule_background_sync();
... (255 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/Orders/HposOrderCapabilityHelper.php">
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
⋮----
use Automattic\WooCommerce\Utilities\OrderUtil;
use WC_Abstract_Order;
use WP_Post;
use WP_Post_Type;
⋮----
class HposOrderCapabilityHelper {
⋮----
public function translate_order_caps( $caps, $cap, $user_id, $args ) {
⋮----
$order_type    = OrderUtil::get_order_type( $order_id );
⋮----
return $this->map_edit_order_caps( $order, $order_type_ob, (int) $user_id, $post );
⋮----
return $this->map_delete_order_caps( $order, $order_type_ob, (int) $user_id, $post );
⋮----
return $this->map_read_order_caps( $order, $order_type_ob, (int) $user_id, $post );
⋮----
private function map_edit_order_caps( WC_Abstract_Order $order, WP_Post_Type $order_type_ob, int $user_id, ?WP_Post $post ): array {
$status  = $this->get_wp_status_for_order( $order );
$is_mine = $user_id === $this->get_author_id( $post );
⋮----
if ( $this->is_published_status( $status ) ) {
⋮----
if ( 'trash' === $status && $this->is_published_status( $this->get_trashed_status( $order ) ) ) {
⋮----
} elseif ( $this->is_private_status( $status ) ) {
⋮----
private function map_delete_order_caps( WC_Abstract_Order $order, WP_Post_Type $order_type_ob, int $user_id, ?WP_Post $post ): array {
... (20 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/Orders/LegacyDataCleanup.php">
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
⋮----
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessingController;
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessorInterface;
⋮----
class LegacyDataCleanup implements BatchProcessorInterface {
⋮----
private $batch_processing;
⋮----
private $legacy_handler;
⋮----
private $data_synchronizer;
⋮----
private $error_logger;
⋮----
final public function init( BatchProcessingController $batch_processing, LegacyDataHandler $legacy_handler, DataSynchronizer $data_synchronizer ) {
⋮----
public function get_name(): string {
⋮----
public function get_description(): string {
⋮----
public function get_total_pending_count(): int {
return $this->can_run() ? $this->legacy_handler->count_orders_for_cleanup() : 0;
⋮----
public function get_next_batch_to_process( int $size ): array {
return $this->can_run()
? array_map( 'absint', $this->legacy_handler->get_orders_for_cleanup( array(), $size ) )
⋮----
public function process_batch( array $batch ): void {
⋮----
... (40 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/Orders/LegacyDataHandler.php">
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
⋮----
use Automattic\WooCommerce\Database\Migrations\CustomOrderTable\PostsToOrdersMigrationController;
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
use Automattic\WooCommerce\Utilities\ArrayUtil;
use WC_Abstract_Order;
⋮----
class LegacyDataHandler {
⋮----
private OrdersTableDataStore $data_store;
⋮----
private DataSynchronizer $data_synchronizer;
⋮----
private PostsToOrdersMigrationController $posts_to_cot_migrator;
⋮----
final public function init( OrdersTableDataStore $data_store, DataSynchronizer $data_synchronizer, PostsToOrdersMigrationController $posts_to_cot_migrator ) {
⋮----
public function count_orders_for_cleanup( $order_ids = array() ): int {
⋮----
return (int) $wpdb->get_var( $this->build_sql_query_for_cleanup( $order_ids, 'count' ) );
⋮----
public function get_orders_for_cleanup( $order_ids = array(), int $limit = 0 ): array {
⋮----
$wpdb->get_col( $this->build_sql_query_for_cleanup( $order_ids, 'ids', $limit ) )
⋮----
private function build_sql_query_for_cleanup( array $order_ids = array(), string $result = 'ids', int $limit = 0 ): string {
⋮----
$hpos_orders_table = $this->data_store->get_orders_table_name();
⋮----
// Expand ranges in $order_ids as needed to build the WHERE clause.
... (139 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php">
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Caches\OrderCache;
use Automattic\WooCommerce\Caching\WPCacheEngine;
use Automattic\WooCommerce\Enums\OrderInternalStatus;
use Automattic\WooCommerce\Internal\Admin\Orders\EditLock;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\ArrayUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Exception;
use WC_Abstract_Order;
use WC_Data;
use WC_Order;
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
⋮----
class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements \WC_Object_Data_Store_Interface, \WC_Order_Data_Store_Interface {
⋮----
private static $reading_order_ids = array();
⋮----
private static $backfilling_order_ids = array();
⋮----
private static $sync_on_read_order_ids = array();
⋮----
protected $internal_meta_keys = array(
⋮----
protected $ephemeral_meta_keys = array(
⋮----
... (917 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStoreMeta.php">
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
⋮----
use Automattic\WooCommerce\Caching\WPCacheEngine;
use Automattic\WooCommerce\Internal\DataStores\CustomMetaDataStore;
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class OrdersTableDataStoreMeta extends CustomMetaDataStore {
⋮----
protected function get_cache_group() {
⋮----
protected function get_table_name() {
return OrdersTableDataStore::get_meta_table_name();
⋮----
protected function get_object_id_field() {
⋮----
public function delete_meta( &$object, $meta ): bool {
$successful = parent::delete_meta( $object, $meta );
⋮----
$this->clear_cached_data( array( $object->get_id() ) );
⋮----
public function add_meta( &$object, $meta ) {
$insert_id = parent::add_meta( $object, $meta );
⋮----
public function update_meta( &$object, $meta ): bool {
$is_successful = parent::update_meta( $object, $meta );
⋮----
public function get_meta_data_for_object_ids( array $object_ids ): array {
if ( ! OrderUtil::custom_orders_table_datastore_cache_enabled() ) {
return parent::get_meta_data_for_object_ids( $object_ids );
⋮----
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableFieldQuery.php">
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
⋮----
class OrdersTableFieldQuery {
⋮----
private $query = null;
⋮----
private $force_no_results = false;
⋮----
private $queries = array();
⋮----
private $join = array();
⋮----
private $where = array();
⋮----
private $table_aliases = array();
⋮----
public function __construct( OrdersTableQuery $q ) {
$field_query = $q->get( 'field_query' );
⋮----
$this->queries = $this->sanitize_query( $field_query );
$this->where   = ( ! $this->force_no_results ) ? $this->process( $this->queries ) : '1=0';
⋮----
private function sanitize_query( array $q ) {
⋮----
} elseif ( $this->is_atomic( $arg ) ) {
⋮----
$arg['cast'] = $this->sanitize_cast_type( $arg['type'] ?? '' );
⋮----
$field_info = $this->query->get_field_mapping_info( $arg['field'] );
⋮----
... (53 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableMetaQuery.php">
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
⋮----
class OrdersTableMetaQuery {
⋮----
private $meta_table = '';
⋮----
/**
	 * Name of the metadata table.
	 *
	 * @var string
	 */
private $orders_table = '';
⋮----
/**
	 * Sanitized `meta_query`.
	 *
	 * @var array
	 */
private $queries = array();
⋮----
/**
	 * Flat list of clauses by name.
	 *
	 * @var array
	 */
private $flattened_clauses = array();
⋮----
/**
	 * JOIN clauses to add to the main SQL query.
	 *
... (142 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php">
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
⋮----
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
⋮----
class OrdersTableQuery {
⋮----
/**
	 * Regex used to catch "shorthand" comparisons in date-related query args.
	 */
⋮----
/**
	 * Names of all COT tables (orders, addresses, operational_data, meta) in the form 'table_id' => 'table name'.
	 *
	 * @var array
	 */
private $tables = array();
⋮----
private $mappings = array();
⋮----
private $args = array();
⋮----
private $query_args = array();
⋮----
private $fields = array();
⋮----
private $join = array();
⋮----
private $where = array();
⋮----
private $groupby = array();
... (367 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableRefundDataStore.php">
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
⋮----
use \WC_Cache_Helper;
use \WC_Meta_Data;
⋮----
class OrdersTableRefundDataStore extends OrdersTableDataStore {
⋮----
protected $internal_meta_keys = array(
⋮----
protected $operational_data_column_mapping = array(
⋮----
public function delete( &$refund, $args = array() ) {
$refund_id = $refund->get_id();
⋮----
$refund_cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'refund_ids' . $refund->get_parent_id();
⋮----
$this->delete_order_data_from_custom_order_tables( $refund_id );
$refund->set_id( 0 );
⋮----
$orders_table_is_authoritative = $refund->get_data_store()->get_current_class_name() === self::class;
⋮----
$data_synchronizer = wc_get_container()->get( DataSynchronizer::class );
if ( $data_synchronizer->data_sync_is_enabled() ) {
⋮----
$this->handle_order_deletion_with_sync_disabled( $refund_id );
⋮----
protected function set_order_props_from_data( &$refund, $data ) {
parent::set_order_props_from_data( $refund, $data );
⋮----
$refund->set_amount( $meta->meta_value );
... (35 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableSearchQuery.php">
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
⋮----
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
use Exception;
⋮----
class OrdersTableSearchQuery {
⋮----
private $query;
⋮----
private $search_term;
⋮----
private $search_filters;
⋮----
public function __construct( OrdersTableQuery $query ) {
⋮----
$this->search_term    = $query->get( 's' );
$this->search_filters = $this->sanitize_search_filters( $query->get( 'search_filter' ) ?? '' );
⋮----
/**
	 * Sanitize search filter param.
	 *
	 * @param string $search_filter Search filter param.
	 *
	 * @return array Array of search filters.
	 */
private function sanitize_search_filters( string $search_filter ): array {
⋮----
/**
	 * Supplies an array of clauses to be used in an order query.
	 *
... (101 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableStatusUnionQuery.php">
namespace Automattic\WooCommerce\Internal\DataStores\Orders;
⋮----
use Automattic\WooCommerce\Utilities\OrderUtil;
⋮----
class OrdersTableStatusUnionQuery {
⋮----
private OrdersTableQuery $query;
⋮----
private string $orders_table;
⋮----
public function __construct( OrdersTableQuery $query ) {
⋮----
$this->orders_table = $query->get_table_name( 'orders' );
⋮----
public function get_sql( array $clauses, bool $suppress_filters ): ?string {
⋮----
if ( ! $this->has_rewritable_clause_shape( $clauses ) ) {
⋮----
$direction = $this->extract_order_direction( $clauses['orderby'] ?? '' );
⋮----
$limit = $this->extract_limit( $clauses['limits'] ?? '' );
⋮----
$types_and_statuses = $this->extract_types_and_statuses();
⋮----
if ( ! $this->is_enabled( $types, $statuses, $suppress_filters ) ) {
⋮----
if ( ! $this->where_matches_type_status_args( $clauses['where'] ?? '' ) ) {
⋮----
return $this->build_union_sql( $types, $statuses, $direction, $offset + $row_count, $clauses['limits'] ?? '' );
⋮----
... (46 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/StockNotifications/StockNotificationsDataStore.php">
namespace Automattic\WooCommerce\Internal\DataStores\StockNotifications;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EmailNormalizer;
⋮----
class StockNotificationsDataStore implements \WC_Object_Data_Store_Interface {
⋮----
protected DatabaseUtil $database_util;
⋮----
protected StockNotificationsMetaDataStore $data_store_meta;
⋮----
final public function init( StockNotificationsMetaDataStore $data_store_meta, DatabaseUtil $database_util ) {
⋮----
public function get_table_name(): string {
⋮----
public function get_meta_table_name(): string {
return $this->data_store_meta->get_table_name();
⋮----
public function get_database_schema(): string {
⋮----
$collate = $wpdb->has_cap( 'collation' ) ? $wpdb->get_charset_collate() : '';
⋮----
$table_name       = $this->get_table_name();
$meta_table_name  = $this->get_meta_table_name();
$max_index_length = $this->database_util->get_max_index_length();
⋮----
/**
	 * Filter the raw meta data.
... (217 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/StockNotifications/StockNotificationsMetaDataStore.php">
namespace Automattic\WooCommerce\Internal\DataStores\StockNotifications;
⋮----
use Automattic\WooCommerce\Internal\DataStores\CustomMetaDataStore;
⋮----
class StockNotificationsMetaDataStore extends CustomMetaDataStore {
⋮----
public function get_table_name() {
⋮----
protected function get_meta_id_field() {
⋮----
protected function get_object_id_field() {
⋮----
public function delete_by_notification_id( $notification_id ) {
⋮----
$table  = $this->get_table_name();
$result = $wpdb->delete(
</file>

<file path="plugins/woocommerce/src/Internal/DataStores/CustomMetaDataStore.php">
namespace Automattic\WooCommerce\Internal\DataStores;
⋮----
abstract class CustomMetaDataStore {
⋮----
abstract protected function get_table_name();
⋮----
protected function get_meta_id_field() {
⋮----
protected function get_object_id_field() {
⋮----
protected function get_db_info() {
⋮----
'table'           => $this->get_table_name(),
'meta_id_field'   => $this->get_meta_id_field(),
'object_id_field' => $this->get_object_id_field(),
⋮----
public function read_meta( &$object ) {
$object_id     = $object->get_id();
$raw_meta_data = $this->get_meta_data_for_object_ids( array( $object_id ) );
⋮----
public function delete_meta( &$object, $meta ) : bool {
⋮----
$db_info = $this->get_db_info();
⋮----
return (bool) $wpdb->delete(
⋮----
$db_info['object_id_field'] => $object->get_id(),
⋮----
public function add_meta( &$object, $meta ) {
⋮----
... (41 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/DependencyManagement/ContainerException.php">
namespace Automattic\WooCommerce\Internal\DependencyManagement;
⋮----
class ContainerException extends \Exception {
⋮----
public function __construct( $message = null, $code = 0, ?\Exception $previous = null ) {
parent::__construct( $message, $code, $previous );
</file>

<file path="plugins/woocommerce/src/Internal/DependencyManagement/RuntimeContainer.php">
namespace Automattic\WooCommerce\Internal\DependencyManagement;
⋮----
use Automattic\WooCommerce\Blocks\Package as BlocksPackage;
use Automattic\WooCommerce\StoreApi\StoreApi;
use Automattic\WooCommerce\Utilities\StringUtil;
⋮----
class RuntimeContainer {
⋮----
/**
	 * Cache of classes already resolved.
	 *
	 * @var array
	 */
protected array $resolved_cache;
⋮----
/**
	 * A copy of the initial resolved classes cache passed to the constructor.
	 *
	 * @var array
	 */
protected array $initial_resolved_cache;
⋮----
/**
	 * Initializes a new instance of the class.
	 *
	 * @param array $initial_resolved_cache Dictionary of class name => instance, to be used as the starting point for the resolved classes cache.
	 */
public function __construct( array $initial_resolved_cache ) {
⋮----
/**
... (107 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Email/DeferredEmailQueue.php">
namespace Automattic\WooCommerce\Internal\Email;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Factory as StockNotificationFactory;
use Automattic\WooCommerce\Internal\StockNotifications\Notification as StockNotification;
⋮----
final class DeferredEmailQueue {
⋮----
private array $queue = array();
⋮----
private bool $shutdown_registered = false;
⋮----
final public function init(): void {
⋮----
public function push( string $filter, array $args ): bool {
⋮----
$args = $this->prepare_arg_for_queue( $args );
⋮----
public function dispatch(): void {
⋮----
\WC()->queue()->add(
⋮----
public function send_queued_transactional_email( $filter, $args ): void {
⋮----
$args = $this->restore_args_from_queue( $args );
⋮----
\WC_Emails::send_queued_transactional_email( $filter, $args );
⋮----
private function prepare_arg_for_queue( $arg ) {
⋮----
$arg[ $key ] = $this->prepare_arg_for_queue( $value );
... (35 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Email/EmailColors.php">
namespace Automattic\WooCommerce\Internal\Email;
⋮----
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class EmailColors {
⋮----
public static function get_default_colors( ?bool $email_improvements_enabled = null ) {
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
$global_colors = static::get_colors_from_global_styles();
⋮----
public static function get_colors_from_global_styles() {
$styles = static::get_global_styles_data();
⋮----
// Only return colors if all are set, otherwise email styles might not match and the email can become unreadable.
⋮----
protected static function get_global_styles_data() {
</file>

<file path="plugins/woocommerce/src/Internal/Email/EmailFont.php">
namespace Automattic\WooCommerce\Internal\Email;
⋮----
class EmailFont {
⋮----
public static $font = array(
</file>

<file path="plugins/woocommerce/src/Internal/Email/EmailLogger.php">
namespace Automattic\WooCommerce\Internal\Email;
⋮----
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use WC_Email;
use WC_Log_Levels;
use WC_Order;
use WC_Product;
use WP_Error;
use WP_User;
⋮----
class EmailLogger implements RegisterHooksInterface {
⋮----
private ?string $last_mail_error = null;
⋮----
public function register(): void {
⋮----
public function capture_mail_error( WP_Error $error ): void {
$this->last_mail_error = $error->get_error_message();
⋮----
public function handle_woocommerce_email_sent( $success, string $email_id, WC_Email $email ): void {
⋮----
$object_context  = $this->get_object_context( $email->object );
⋮----
'recipient'  => $this->resolve_recipient( $email->get_recipient() ),
⋮----
$reason  = $last_mail_error ? ': ' . $this->redact_emails( $last_mail_error ) : '';
⋮----
wc_get_logger()->log( $level, $message, $context );
⋮----
... (36 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Email/EmailStyleSync.php">
namespace Automattic\WooCommerce\Internal\Email;
⋮----
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
⋮----
class EmailStyleSync implements RegisterHooksInterface {
⋮----
private $is_syncing = false;
⋮----
public function register() {
⋮----
public function maybe_sync_on_option_update( $old_value, $new_value, $option ) {
⋮----
$this->update_email_colors();
⋮----
public function is_auto_sync_enabled() {
⋮----
public function set_auto_sync( bool $enabled ) {
⋮----
public function sync_email_styles_with_theme() {
if ( $this->is_syncing || ! $this->is_auto_sync_enabled() || ! wp_theme_has_theme_json() ) {
⋮----
protected function update_email_colors() {
$colors = EmailColors::get_default_colors();
</file>

<file path="plugins/woocommerce/src/Internal/Email/OrderPriceFormatter.php">
namespace Automattic\WooCommerce\Internal\Email;
⋮----
use Automattic\WooCommerce\Enums\TaxDisplayMode;
use WC_Abstract_Order;
use WC_Order_Item;
⋮----
class OrderPriceFormatter {
⋮----
public static function get_formatted_item_subtotal( WC_Abstract_Order $order, WC_Order_Item $item, string $tax_display ): string {
⋮----
$item_subtotal = $order->get_item_subtotal( $item, $includes_tax );
return self::format_price( $order, $item_subtotal, $includes_tax );
⋮----
private static function format_price( WC_Abstract_Order $order, float $amount, bool $includes_tax ): string {
⋮----
'ex_tax_label' => ( ! $includes_tax && $order->get_prices_include_tax() ) ? 1 : 0,
'currency'     => $order->get_currency(),
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/EmailPatterns/PatternsController.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\EmailPatterns;
⋮----
class PatternsController {
⋮----
final public function init(): void {
$this->register_patterns();
⋮----
public function register_patterns(): void {
⋮----
register_block_pattern( $pattern->get_namespace() . '/' . $pattern->get_name(), $pattern->get_properties() );
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/EmailPatterns/WooEmailContentPattern.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\EmailPatterns;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Patterns\Abstract_Pattern;
use Automattic\WooCommerce\Internal\EmailEditor\Integration;
⋮----
class WooEmailContentPattern extends Abstract_Pattern {
⋮----
public $name = 'woo-email-content-pattern';
⋮----
public $block_types = array();
⋮----
public $template_types = array( 'email-template' );
⋮----
public $categories = array( 'email-contents' );
⋮----
public $namespace = 'woocommerce';
⋮----
protected $post_types = array( Integration::EMAIL_POST_TYPE );
⋮----
public function get_content(): string {
⋮----
public function get_title(): string {
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/EmailTemplates/TemplateApiController.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\EmailTemplates;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Builder;
⋮----
class TemplateApiController {
⋮----
public function get_template_data( $template_data ): array {
⋮----
public function save_template_data( array $data, \WP_Block_Template $template_post ): ?\WP_Error {
⋮----
return new \WP_Error( 'invalid_email_address', __( 'Invalid email address provided for sender settings', 'woocommerce' ), array( 'status' => 400 ) );
⋮----
public function get_template_data_schema(): array {
return Builder::object(
⋮----
'sender_settings' => Builder::object(
⋮----
'preheader'   => Builder::string(),
'preview_url' => Builder::string(),
⋮----
)->to_array();
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/EmailTemplates/TemplatesController.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\EmailTemplates;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Templates\Template;
use Automattic\WooCommerce\EmailEditor\Engine\Templates\Templates_Registry;
use Automattic\WooCommerce\Internal\EmailEditor\Integration;
⋮----
class TemplatesController {
⋮----
private string $template_prefix = 'woocommerce';
⋮----
final public function init(): void {
⋮----
public function filter_email_templates( $templates ) {
⋮----
public function register_templates( Templates_Registry $templates_registry ) {
⋮----
$template->get_slug(),
$template->get_title(),
$template->get_description(),
$template->get_content(),
⋮----
$templates_registry->register( $the_template );
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/EmailTemplates/WooEmailTemplate.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\EmailTemplates;
⋮----
class WooEmailTemplate {
⋮----
public function get_slug(): string {
⋮----
public function get_title(): string {
⋮----
public function get_description(): string {
⋮----
public function get_content(): string {
⋮----
' . $this->get_site_logo_or_title() . '
⋮----
private function get_site_logo_or_title(): string {
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/PersonalizationTags/AbstractTagProvider.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\PersonalizationTags;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
⋮----
abstract class AbstractTagProvider {
⋮----
abstract public function register_tags( Personalization_Tags_Registry $registry ): void;
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/PersonalizationTags/CustomerTagsProvider.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\PersonalizationTags;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tag;
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
use Automattic\WooCommerce\Internal\EmailEditor\Integration;
⋮----
class CustomerTagsProvider extends AbstractTagProvider {
⋮----
public function register_tags( Personalization_Tags_Registry $registry ): void {
$registry->register(
⋮----
return $context['order']->get_billing_email() ?? '';
⋮----
return $context['order']->get_billing_first_name() ?? '';
⋮----
return $context['order']->get_billing_last_name() ?? '';
⋮----
return $context['order']->get_formatted_billing_full_name() ?? '';
⋮----
$country_code = $context['order']->get_billing_country();
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/PersonalizationTags/OrderTagsProvider.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\PersonalizationTags;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tag;
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
use Automattic\WooCommerce\Internal\EmailEditor\Integration;
⋮----
class OrderTagsProvider extends AbstractTagProvider {
⋮----
public function register_tags( Personalization_Tags_Registry $registry ): void {
$registry->register(
⋮----
return $context['order']->get_order_number() ?? '';
⋮----
$date_created = $context['order']->get_date_created();
⋮----
foreach ( $context['order']->get_items() as $item ) {
$items[] = $item->get_name();
⋮----
return (string) $context['order']->get_subtotal() ?? '';
⋮----
return (string) $context['order']->get_total_tax() ?? '';
⋮----
return wc_price( $context['order']->get_discount_total(), array( 'currency' => $context['order']->get_currency() ) );
⋮----
return wc_price( $context['order']->get_shipping_total(), array( 'currency' => $context['order']->get_currency() ) );
⋮----
return (string) $context['order']->get_total() ?? '';
⋮----
return $context['order']->get_payment_method_title() ?? '';
⋮----
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/PersonalizationTags/SiteTagsProvider.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\PersonalizationTags;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tag;
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
use Automattic\WooCommerce\Internal\EmailEditor\Integration;
use Automattic\WooCommerce\Internal\Orders\PointOfSaleOrderUtil;
use Automattic\WooCommerce\Internal\Settings\PointOfSaleDefaultSettings;
⋮----
class SiteTagsProvider extends AbstractTagProvider {
⋮----
public function register_tags( Personalization_Tags_Registry $registry ): void {
$registry->register(
⋮----
if ( isset( $context['order'] ) && PointOfSaleOrderUtil::is_pos_order( $context['order'] ) ) {
⋮----
return htmlspecialchars_decode( empty( $store_name ) ? PointOfSaleDefaultSettings::get_default_store_name() : $store_name, ENT_QUOTES );
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/PersonalizationTags/StoreTagsProvider.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\PersonalizationTags;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tag;
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
use Automattic\WooCommerce\Internal\EmailEditor\Integration;
⋮----
class StoreTagsProvider extends AbstractTagProvider {
⋮----
public function register_tags( Personalization_Tags_Registry $registry ): void {
$registry->register(
⋮----
return $wc_email->get_from_address();
⋮----
if ( isset( $context['wc_email'] ) && ! empty( $context['wc_email']->get_from_name() ) ) {
return $context['wc_email']->get_from_name();
⋮----
return WC()->mailer->get_store_address() ?? '';
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCEmailPostsCleanup.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger_Interface;
use Automattic\WooCommerce\Internal\EmailEditor\Integration;
use Automattic\WooCommerce\Internal\EmailEditor\Logger;
⋮----
class WCEmailPostsCleanup {
⋮----
public static function run( ?Email_Editor_Logger_Interface $logger = null ): bool {
⋮----
$posts_manager = WCTransactionalEmailPostsManager::get_instance();
$emails_by_id  = $posts_manager->get_emails_by_id();
⋮----
foreach ( self::fetch_email_post_mappings() as $mapping ) {
⋮----
$email_type  = self::email_type_from_option_name( $option_name );
⋮----
if ( self::was_never_customized( $post, $email ) ) {
⋮----
$logger->error(
⋮----
$e->getMessage()
⋮----
$posts_manager->clear_caches();
⋮----
$logger->info(
⋮----
private static function was_never_customized( \WP_Post $post, \WC_Email $email ): bool {
⋮----
$canonical_hash = sha1( WCTransactionalEmailPostsGenerator::compute_canonical_post_content( $email ) );
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCEmailScratchpadRefresher.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails;
⋮----
class WCEmailScratchpadRefresher {
⋮----
public function maybe_refresh( \WP_Post $scratchpad, \WC_Email $email ): void {
if ( ! $this->was_never_edited( $scratchpad ) ) {
⋮----
$this->refresh_content( $scratchpad, $email );
⋮----
private function was_never_edited( \WP_Post $post ): bool {
⋮----
private function refresh_content( \WP_Post $scratchpad, \WC_Email $email ): void {
$post_data       = WCTransactionalEmailPostsGenerator::build_filtered_post_data( (string) $email->id, $email );
⋮----
// Restamped for every email, not only sync-registry ones: the update
// above bumped `post_modified`, so without a matching hash the
// timestamp fallback in `was_never_edited()` would treat this
// scratchpad as edited forever and this refresh would never run again.
⋮----
$sync_config = WCEmailTemplateSyncRegistry::get_email_sync_config( (string) $email->id );
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCEmailTemplateAutoApplier.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger_Interface;
use Automattic\WooCommerce\Internal\EmailEditor\Logger;
⋮----
class WCEmailTemplateAutoApplier {
⋮----
private static bool $is_auto_applying = false;
⋮----
private static ?Email_Editor_Logger_Interface $logger = null;
⋮----
public static function apply_to_post( \WC_Email $email, int $post_id, array $opts = array() ) {
⋮----
$sync_config = WCEmailTemplateSyncRegistry::get_email_sync_config( (string) $email->id );
⋮----
return new \WP_Error(
⋮----
if ( '' === $stored_source_hash || ! self::is_sha1_hash( $stored_source_hash ) ) {
⋮----
$canonical   = WCTransactionalEmailPostsGenerator::compute_canonical_post_content( $email );
⋮----
$status = WCEmailTemplateDivergenceDetector::reclassify( $post_id );
⋮----
WCEmailTemplateSyncTracker::record_auto_applied( $post_id );
⋮----
public static function schedule(): void {
⋮----
public static function run(): void {
⋮----
$registry      = WCEmailTemplateSyncRegistry::get_sync_enabled_emails();
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCEmailTemplateChangeSummary.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger_Interface;
use Automattic\WooCommerce\Internal\EmailEditor\Logger;
⋮----
class WCEmailTemplateChangeSummary {
⋮----
private static $logger = null;
⋮----
public static function summarize( int $post_id ): array {
⋮----
return self::fallback_payload( '', '' );
⋮----
$posts_manager = WCTransactionalEmailPostsManager::get_instance();
$email_id      = $posts_manager->get_email_type_from_post_id( $post_id );
⋮----
$sync_config = WCEmailTemplateSyncRegistry::get_email_sync_config( $email_id );
⋮----
$emails = $posts_manager->get_emails_by_id();
⋮----
return self::fallback_payload( '', (string) $sync_config['version'] );
⋮----
$core_content = WCTransactionalEmailPostsGenerator::compute_canonical_post_content( $email );
⋮----
self::get_logger()->error(
⋮----
$e->getMessage()
⋮----
return self::fallback_payload(
⋮----
... (136 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCEmailTemplateDivergenceDetector.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger_Interface;
use Automattic\WooCommerce\Internal\EmailEditor\Integration;
use Automattic\WooCommerce\Internal\EmailEditor\Logger;
⋮----
class WCEmailTemplateDivergenceDetector {
⋮----
private static $logger = null;
⋮----
public static function register_meta(): void {
⋮----
public static function rest_meta_auth_read_only( $allowed, $meta_key, $object_id, $user_id, $cap, $caps ): bool {
⋮----
public static function mark_backfill_complete_on_fresh_install(): void {
⋮----
public static function run_sweep(): void {
⋮----
$registry = WCEmailTemplateSyncRegistry::get_sync_enabled_emails();
⋮----
$posts_manager = WCTransactionalEmailPostsManager::get_instance();
⋮----
$post = $posts_manager->get_email_post( (string) $email_id );
⋮----
self::reclassify( (int) $post->ID );
⋮----
self::get_logger()->error(
⋮----
$e->getMessage()
⋮----
... (34 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCEmailTemplateSelectiveApplier.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger_Interface;
use Automattic\WooCommerce\Internal\EmailEditor\Integration;
use Automattic\WooCommerce\Internal\EmailEditor\Logger;
⋮----
class WCEmailTemplateSelectiveApplier {
⋮----
private static bool $is_applying = false;
⋮----
private static ?Email_Editor_Logger_Interface $logger = null;
⋮----
public static function apply_selectively( int $post_id, array $choices ) {
⋮----
return new \WP_Error(
⋮----
$posts_manager = WCTransactionalEmailPostsManager::get_instance();
$email_id      = $posts_manager->get_email_type_from_post_id( $post_id );
⋮----
$sync_config = WCEmailTemplateSyncRegistry::get_email_sync_config( $email_id );
⋮----
$emails = $posts_manager->get_emails_by_id();
⋮----
$summary = WCEmailTemplateChangeSummary::summarize( $post_id );
⋮----
$core_content = WCTransactionalEmailPostsGenerator::compute_canonical_post_content( $email );
⋮----
self::get_logger()->error(
⋮----
$e->getMessage()
... (108 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCEmailTemplateSyncBackfill.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger_Interface;
use Automattic\WooCommerce\Internal\EmailEditor\Integration;
use Automattic\WooCommerce\Internal\EmailEditor\Logger;
⋮----
class WCEmailTemplateSyncBackfill {
⋮----
private static $is_backfilling = false;
⋮----
private static $logger = null;
⋮----
public static function run(): bool {
$eligible = self::fetch_eligible_posts();
⋮----
self::finalize();
⋮----
$registry = WCEmailTemplateSyncRegistry::get_sync_enabled_emails();
⋮----
$posts_manager = WCTransactionalEmailPostsManager::get_instance();
$emails_by_id  = $posts_manager->get_emails_by_id();
⋮----
$email_id = (string) $posts_manager->get_email_type_from_post_id( $post_id );
⋮----
$canonical_post_content = WCTransactionalEmailPostsGenerator::compute_canonical_post_content( $email );
⋮----
$case_id = self::classify( $row, $current_core_hash );
⋮----
self::apply_case_to_post( $post_id, $case_id, $canonical_post_content, $current_core_hash, $email );
⋮----
... (84 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCEmailTemplateSyncRegistry.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger_Interface;
use Automattic\WooCommerce\Internal\EmailEditor\Logger;
⋮----
class WCEmailTemplateSyncRegistry {
⋮----
private static $first_party_ids = null;
⋮----
private static $registry_cache = null;
⋮----
private static $logger = null;
⋮----
public static function get_sync_enabled_emails(): array {
⋮----
self::$registry_cache = self::resolve();
⋮----
public static function get_email_sync_config( string $email_id ): ?array {
$registry = self::get_sync_enabled_emails();
⋮----
public static function is_enabled( string $email_id ): bool {
⋮----
public static function reset_cache(): void {
⋮----
public static function set_logger( ?Email_Editor_Logger_Interface $logger ): void {
⋮----
private static function resolve(): array {
$eligible_ids = WCTransactionalEmails::get_transactional_emails();
⋮----
$emails_by_id = WCTransactionalEmailPostsManager::get_instance()->get_emails_by_id();
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCEmailTemplateSyncTracker.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails;
⋮----
use WC_Tracks;
⋮----
class WCEmailTemplateSyncTracker {
⋮----
private static $event_recorder = null;
⋮----
public static function set_event_recorder( ?callable $recorder ): void {
⋮----
private static function record( string $event_name, array $payload ): void {
⋮----
WC_Tracks::record_event( $event_name, $payload );
⋮----
public static function record_update_available( int $post_id ): void {
if ( self::should_suppress() ) {
⋮----
$payload = self::build_base_payload( $post_id );
⋮----
$transient_key = self::available_dedup_transient_key( $post_id, $version_to );
⋮----
self::record( self::EVENT_UPDATE_AVAILABLE, $payload );
⋮----
// Set the dedup transient after the record() call. record() swallows
// throws from the Tracks pipeline in production, so in steady state
// either ordering would dedup identically. The post-record ordering is
// intentional for the testing path: when set_event_recorder() injects a
// throwing spy, the transient stays unwritten and a retry remains
// possible without manually clearing it. 30-day TTL outlasts the gap
// between core releases without leaving stale dedup keys forever.
... (48 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCTransactionalEmailPostsGenerator.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails;
⋮----
use Automattic\WooCommerce\Internal\EmailEditor\Integration;
use Automattic\WooCommerce\Internal\EmailEditor\EmailTemplates\WooEmailTemplate;
use Automattic\WooCommerce\Utilities\StringUtil;
⋮----
class WCTransactionalEmailPostsGenerator {
⋮----
public static function resolve_block_template_name( $email ): string {
⋮----
public static function resolve_block_template_path( $email ): string {
$template_name = self::resolve_block_template_name( $email );
⋮----
/**
	 * Get the email template for the given email.
	 *
	 * Looks for the initial email block content in plugins/woocommerce/templates/emails/block.
	 *
	 * @param \WC_Email $email The email object.
	 * @return string The email template.
	 */
public function get_email_template( $email ) {
return self::render_block_template_html( $email );
⋮----
/**
	 * Render the block template HTML for a given email.
	 *
	 * Resolves the block template (honouring theme overrides), falls back to the
	 * default block content on failure, and applies the
	 * `woocommerce_email_block_template_html` filter. Stateless so both the
... (98 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCTransactionalEmailPostsManager.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails;
⋮----
class WCTransactionalEmailPostsManager {
⋮----
private static $instance = null;
⋮----
private $post_id_to_email_type_cache = array();
⋮----
private $email_class_name_cache = array();
⋮----
private $mapping_options_primed = false;
⋮----
public static function get_instance() {
⋮----
public function get_emails_by_id(): array {
⋮----
$all_emails = \WC_Emails::instance()->get_emails();
⋮----
public function get_email_by_id( string $email_id ): ?\WC_Email {
⋮----
return $this->get_emails_by_id()[ $email_id ] ?? null;
⋮----
/**
	 * Retrieves the email post by its type.
	 *
	 * Type here refers to the email type, e.g. 'customer_new_account' from the WC_Email->id property.
	 *
	 * @param string $email_type The type of email to retrieve.
	 * @return \WP_Post|null The email post if found, null otherwise.
	 */
... (62 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/WCTransactionalEmails/WCTransactionalEmails.php">
namespace Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails;
⋮----
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class WCTransactionalEmails {
⋮----
public static $core_transactional_emails = array(
⋮----
final public function init() {
⋮----
public static function get_core_transactional_emails() {
⋮----
if ( FeaturesUtil::feature_is_enabled( 'fulfillments' ) ) {
⋮----
public static function get_transactional_emails() {
$emails = self::get_core_transactional_emails();
⋮----
public function init_email_templates() {
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/BlockEmailRenderer.php">
namespace Automattic\WooCommerce\Internal\EmailEditor;
⋮----
use Automattic\WooCommerce\EmailEditor\Email_Editor_Container;
use Automattic\WooCommerce\EmailEditor\Engine\Personalizer;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\Renderer as EmailRenderer;
use Automattic\WooCommerce\Internal\EmailEditor\EmailTemplates\WooEmailTemplate;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmails;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsGenerator;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsManager;
⋮----
class BlockEmailRenderer {
⋮----
private $renderer;
⋮----
private $personalizer;
⋮----
private $woo_content_processor;
⋮----
private $template_manager;
⋮----
private $file_template_content_cache = array();
⋮----
public function __construct() {
$editor_container       = Email_Editor_Container::container();
$this->renderer         = $editor_container->get( EmailRenderer::class );
$this->personalizer     = $editor_container->get( Personalizer::class );
$this->template_manager = WCTransactionalEmailPostsManager::get_instance();
⋮----
final public function init( WooContentProcessor $woo_content_processor ): void {
⋮----
... (48 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/EmailApiController.php">
namespace Automattic\WooCommerce\Internal\EmailEditor;
⋮----
use Automattic\WooCommerce\EmailEditor\Validator\Builder;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateChangeSummary;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateAutoApplier;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateSelectiveApplier;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsManager;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsGenerator;
use WC_Email;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class EmailApiController {
⋮----
private ?WCTransactionalEmailPostsManager $post_manager = null;
⋮----
private ?WCTransactionalEmailPostsGenerator $posts_generator = null;
⋮----
final public function init(): void {
$this->post_manager    = WCTransactionalEmailPostsManager::get_instance();
⋮----
public function get_email_data( $post_data ): array {
$email_type = $this->post_manager->get_email_type_from_post_id( $post_data['id'] );
$email      = $this->get_email_by_type( $email_type ?? '' );
⋮----
// When the email type is not found, it means that the email type is not supported.
⋮----
$form_fields = $email->get_form_fields();
$enabled     = $email->get_option( 'enabled' );
... (123 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/Integration.php">
namespace Automattic\WooCommerce\Internal\EmailEditor;
⋮----
use Automattic\WooCommerce\EmailEditor\Email_Editor_Container;
use Automattic\WooCommerce\EmailEditor\Engine\Dependency_Check;
use Automattic\WooCommerce\EmailEditor\Engine\Renderer\Renderer;
use Automattic\WooCommerce\EmailEditor\Engine\Send_Preview_Email;
use Automattic\WooCommerce\Internal\Admin\EmailPreview\EmailPreview;
use Automattic\WooCommerce\Internal\EmailEditor\EmailPatterns\PatternsController;
use Automattic\WooCommerce\Internal\EmailEditor\EmailTemplates\TemplatesController;
use Automattic\WooCommerce\Internal\EmailEditor\EmailTemplates\WooEmailTemplate;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsGenerator;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailScratchpadRefresher;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateAutoApplier;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateDivergenceDetector;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateSyncBackfill;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCEmailTemplateSyncTracker;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmails;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsManager;
use Automattic\WooCommerce\Internal\EmailEditor\EmailTemplates\TemplateApiController;
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger;
use WP_Post;
⋮----
class Integration {
⋮----
private PageRenderer $editor_page_renderer;
⋮----
private Dependency_Check $dependency_check;
⋮----
private TemplateApiController $template_api_controller;
⋮----
... (257 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/Logger.php">
namespace Automattic\WooCommerce\Internal\EmailEditor;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Logger\Email_Editor_Logger_Interface;
use WC_Log_Levels;
⋮----
class Logger implements Email_Editor_Logger_Interface {
⋮----
private \WC_Logger_Interface $wc_logger;
⋮----
public function __construct( \WC_Logger_Interface $wc_logger ) {
⋮----
private function should_handle( string $level ): bool {
⋮----
return WC_Log_Levels::get_level_severity( $logging_threshold ) <= WC_Log_Levels::get_level_severity( $level );
⋮----
public function emergency( string $message, array $context = array() ): void {
$this->log( WC_Log_Levels::EMERGENCY, $message, $context );
⋮----
public function alert( string $message, array $context = array() ): void {
$this->log( WC_Log_Levels::ALERT, $message, $context );
⋮----
public function critical( string $message, array $context = array() ): void {
$this->log( WC_Log_Levels::CRITICAL, $message, $context );
⋮----
public function error( string $message, array $context = array() ): void {
$this->log( WC_Log_Levels::ERROR, $message, $context );
⋮----
public function warning( string $message, array $context = array() ): void {
$this->log( WC_Log_Levels::WARNING, $message, $context );
⋮----
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/Package.php">
namespace Automattic\WooCommerce\Internal\EmailEditor;
⋮----
class Package {
⋮----
private static $package_active = false;
⋮----
final public static function init() {
⋮----
self::initialize();
\Automattic\WooCommerce\EmailEditor\Package::init();
⋮----
public static function get_version() {
return \Automattic\WooCommerce\EmailEditor\Package::get_version();
⋮----
public static function get_path() {
return \Automattic\WooCommerce\EmailEditor\Package::get_path();
⋮----
public static function initialize() {
⋮----
$container->get( Integration::class );
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/PageRenderer.php">
namespace Automattic\WooCommerce\Internal\EmailEditor;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\Assets_Manager;
use Automattic\WooCommerce\EmailEditor\Engine\Templates\Template;
use Automattic\WooCommerce\EmailEditor\Engine\Templates\Templates_Registry;
use Automattic\WooCommerce\EmailEditor\Email_Editor_Container;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
⋮----
class PageRenderer {
⋮----
private Templates_Registry $template_registry;
⋮----
private Assets_Manager $assets_manager;
⋮----
public function __construct() {
$editor_container        = Email_Editor_Container::container();
$this->template_registry = $editor_container->get( Templates_Registry::class );
⋮----
$assets_manager = $editor_container->get( Assets_Manager::class );
$assets_manager->set_assets_path( WC_ABSPATH . WC_ADMIN_DIST_JS_FOLDER . 'email-editor/' );
$assets_manager->set_assets_url( WC()->plugin_url() . '/' . WC_ADMIN_DIST_JS_FOLDER . 'email-editor/' );
⋮----
public function render() {
⋮----
$template_id = isset( $_GET['template'] ) ? sanitize_text_field( wp_unslash( $_GET['template'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We are not verifying the nonce here because we are not using the nonce in the function and the data is okay in this context (WP-admin errors out gracefully).
⋮----
$edited_item = $this->get_edited_item( $post_id, $post_type );
⋮----
WCAdminAssets::register_script( 'wp-admin-scripts', 'email-editor-integration', true );
WCAdminAssets::register_style( 'email-editor-integration', 'style', true );
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/PersonalizationTagManager.php">
namespace Automattic\WooCommerce\Internal\EmailEditor;
⋮----
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
use Automattic\WooCommerce\Internal\EmailEditor\PersonalizationTags\CustomerTagsProvider;
use Automattic\WooCommerce\Internal\EmailEditor\PersonalizationTags\OrderTagsProvider;
use Automattic\WooCommerce\Internal\EmailEditor\PersonalizationTags\SiteTagsProvider;
use Automattic\WooCommerce\Internal\EmailEditor\PersonalizationTags\StoreTagsProvider;
⋮----
class PersonalizationTagManager {
⋮----
private $customer_tags_provider;
⋮----
private $order_tags_provider;
⋮----
private $site_tags_provider;
⋮----
private $store_tags_provider;
⋮----
public function __construct() {
⋮----
final public function init(): void {
⋮----
public function register_personalization_tags( Personalization_Tags_Registry $registry ) {
$this->customer_tags_provider->register_tags( $registry );
$this->order_tags_provider->register_tags( $registry );
$this->site_tags_provider->register_tags( $registry );
$this->store_tags_provider->register_tags( $registry );
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/TransactionalEmailPersonalizer.php">
namespace Automattic\WooCommerce\Internal\EmailEditor;
⋮----
use Automattic\WooCommerce\EmailEditor\Email_Editor_Container;
use Automattic\WooCommerce\EmailEditor\Engine\Personalizer;
⋮----
class TransactionalEmailPersonalizer {
⋮----
private Personalizer $personalizer;
⋮----
public function __construct() {
$editor_container   = Email_Editor_Container::container();
$this->personalizer = $editor_container->get( Personalizer::class );
⋮----
public function personalize_transactional_content( string $content, \WC_Email $email, string $rendering_context = Personalizer::RENDERING_CONTEXT_HTML ): string {
$this->configure_context_by_email( $email );
return $this->personalizer->personalize_content( $content, $rendering_context );
⋮----
public function configure_context_by_email( \WC_Email $email ): void {
$prepared_context = $this->prepare_context_data( $this->personalizer->get_context(), $email );
$this->personalizer->set_context( $prepared_context );
⋮----
public function prepare_context_data( array $previous_context, \WC_Email $email ): array {
⋮----
$context['recipient_email'] = $email->get_recipient();
⋮----
$context['wp_user'] = $email->object->get_user();
</file>

<file path="plugins/woocommerce/src/Internal/EmailEditor/WooContentProcessor.php">
namespace Automattic\WooCommerce\Internal\EmailEditor;
⋮----
use Automattic\WooCommerce\EmailEditor\Email_Css_Inliner;
use Automattic\WooCommerce\EmailEditor\Email_Editor_Container;
use Automattic\WooCommerce\EmailEditor\Engine\Theme_Controller;
⋮----
class WooContentProcessor {
⋮----
private $theme_controller;
⋮----
private $css_inliner;
⋮----
public function __construct() {
$this->theme_controller = Email_Editor_Container::container()->get( Theme_Controller::class );
⋮----
public function get_woo_content( \WC_Email $wc_email ): string {
$woo_content          = $this->capture_woo_content( $wc_email );
$woo_content_with_css = $this->inline_css( $woo_content );
return $this->get_html_body_content( $woo_content_with_css );
⋮----
public function prepare_css( string $css ): string {
⋮----
/**
	 * Get the content of the body tag from the HTML.
	 *
	 * @param string $html HTML.
	 * @return string
	 */
private function get_html_body_content( string $html ): string {
// Extract content between <body> and </body> tags using regex.
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Features/OrderDetailRedesign/Init.php">
namespace Automattic\WooCommerce\Internal\Features\OrderDetailRedesign;
⋮----
class Init {
⋮----
public function __construct() {
⋮----
public function handle_admin_body_class( string $classes ): string {
</file>

<file path="plugins/woocommerce/src/Internal/Features/BlockEditorUnifiedAssets.php">
namespace Automattic\WooCommerce\Internal\Features;
⋮----
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
final class BlockEditorUnifiedAssets {
⋮----
public static function is_enabled(): bool {
return FeaturesUtil::feature_is_enabled( self::FEATURE_NAME );
</file>

<file path="plugins/woocommerce/src/Internal/Features/FeaturesController.php">
namespace Automattic\WooCommerce\Internal\Features;
⋮----
use Automattic\WooCommerce\Internal\Admin\EmailPreview\EmailPreview;
use WC_Tracks;
use WC_Site_Tracking;
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Admin\Features\Features as WCAdminFeatures;
use Automattic\WooCommerce\Internal\Admin\Analytics;
use Automattic\WooCommerce\Internal\Caches\ProductCacheController;
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController;
use Automattic\WooCommerce\Internal\ProductGallery\ProductMediaGallery;
use Automattic\WooCommerce\Internal\PushNotifications\PushNotifications;
use Automattic\WooCommerce\Internal\StockNotifications\StockNotifications;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\ArrayUtil;
use Automattic\WooCommerce\Utilities\PluginUtil;
use Automattic\WooCommerce\Enums\FeaturePluginCompatibility;
⋮----
class FeaturesController {
⋮----
private $features = array();
⋮----
private $compatibility_info_by_plugin = array();
⋮----
private $compatibility_info_by_feature = array();
⋮----
private $pending_declarations = array();
⋮----
private $proxy;
... (309 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Integrations/WPConsentAPI.php">
namespace Automattic\WooCommerce\Internal\Integrations;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Traits\ScriptDebug;
use WP_CONSENT_API;
⋮----
class WPConsentAPI {
⋮----
public static $consent_category = 'marketing';
⋮----
public function register() {
⋮----
$this->on_init();
⋮----
protected function on_init() {
⋮----
if ( ! $this->is_wp_consent_api_active() ) {
⋮----
$this->enqueue_consent_api_scripts();
⋮----
protected function is_wp_consent_api_active() {
⋮----
private function enqueue_consent_api_scripts() {
⋮----
"assets/js/frontend/wp-consent-api-integration{$this->get_script_suffix()}.js",
⋮----
Constants::get_constant( 'WC_VERSION' ),
</file>

<file path="plugins/woocommerce/src/Internal/Integrations/WPPostsImporter.php">
namespace Automattic\WooCommerce\Internal\Integrations;
⋮----
class WPPostsImporter {
⋮----
public function register() {
⋮----
public function register_product_attribute_taxonomies( $posts ) {
</file>

<file path="plugins/woocommerce/src/Internal/Jetpack/JetpackConnection.php">
namespace Automattic\WooCommerce\Internal\Jetpack;
⋮----
use Automattic\Jetpack\Connection\Manager;
use WP_Error;
⋮----
class JetpackConnection {
⋮----
private static $manager;
⋮----
public static function get_manager() {
⋮----
public static function get_authorization_url( $redirect_url, $from = '' ) {
$manager = self::get_manager();
⋮----
// Register the site to wp.com.
if ( ! $manager->is_connected() ) {
$result = $manager->try_registration();
⋮----
$errors->add( $result->get_error_code(), $result->get_error_message() );
⋮----
$authorization_url = $manager->get_authorization_url( null, $redirect_url );
$authorization_url = add_query_arg( 'locale', self::get_wpcom_locale(), $authorization_url );
⋮----
'success'      => ! $errors->has_errors(),
'errors'       => $errors->get_error_messages(),
⋮----
private static function get_wpcom_locale() {
</file>

<file path="plugins/woocommerce/src/Internal/LegacyAssets/LegacySelect2UsageTracker.php">
namespace Automattic\WooCommerce\Internal\LegacyAssets;
⋮----
use Automattic\Woocommerce_Analytics\WC_Analytics_Tracking;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use WP_Scripts;
use WC_Site_Tracking;
⋮----
class LegacySelect2UsageTracker implements RegisterHooksInterface {
⋮----
public function register() {
⋮----
if ( WC_Site_Tracking::is_tracking_enabled() ) {
⋮----
public function handle_admin_print_footer_scripts(): void {
$this->track_usage( self::CONTEXT_ADMIN );
⋮----
public function handle_wp_print_footer_scripts(): void {
if ( ! $this->is_frontend_tracking_available() ) {
⋮----
$this->track_usage( self::CONTEXT_FRONTEND );
⋮----
private function track_usage( string $context ): void {
if ( ! $this->is_legacy_select2_printed() ) {
⋮----
$event = $this->get_usage_event( $context );
⋮----
if ( $this->was_recently_checked( $event ) ) {
⋮----
$this->mark_recently_checked( $event );
⋮----
... (88 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Logging/OrderLogsCleanupHelper.php">
namespace Automattic\WooCommerce\Internal\Logging;
⋮----
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\FileController;
use Automattic\WooCommerce\Internal\Admin\Logging\LogHandlerFileV2;
use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer;
use Automattic\WooCommerce\Utilities\LoggingUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
use WC_Logger;
⋮----
class OrderLogsCleanupHelper {
⋮----
private DataSynchronizer $data_synchronizer;
⋮----
final public function init( DataSynchronizer $data_synchronizer ): void {
⋮----
private function get_max_age_in_seconds(): int {
⋮----
public function cleanup(): void {
$max_age = $this->get_max_age_in_seconds();
⋮----
$files_swept_in_bulk = LogHandlerFileV2::class === LoggingUtil::get_default_handler();
⋮----
$more_files  = $files_swept_in_bulk && $this->cleanup_old_log_files( $max_age );
$more_orders = $this->cleanup_dangling_orders( $max_age, $files_swept_in_bulk );
⋮----
$this->schedule_extended_cleanup();
⋮----
private function cleanup_dangling_orders( int $max_age, bool $files_swept_in_bulk ): bool {
$dangling_orders = $this->get_dangling_orders( $max_age );
⋮----
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Logging/OrderLogsDeletionProcessor.php">
namespace Automattic\WooCommerce\Internal\Logging;
⋮----
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessorInterface;
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\StringUtil;
⋮----
class OrderLogsDeletionProcessor implements BatchProcessorInterface {
⋮----
private bool $hpos_in_use = false;
⋮----
private bool $cpt_in_use = false;
⋮----
private LegacyProxy $legacy_proxy;
⋮----
private OrderLogsCleanupHelper $order_logs_cleanup_helper;
⋮----
final public function init( CustomOrdersTableController $hpos_controller, LegacyProxy $legacy_proxy, OrderLogsCleanupHelper $order_logs_cleanup_helper ) {
$this->hpos_in_use = $hpos_controller->custom_orders_table_usage_is_enabled();
⋮----
$this->cpt_in_use = \WC_Order_Data_Store_CPT::class === \WC_Data_Store::load( 'order' )->get_current_class_name();
⋮----
public function get_name(): string {
⋮----
public function get_description(): string {
⋮----
public function get_default_batch_size(): int {
⋮----
public function get_total_pending_count(): int {
⋮----
... (34 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Logging/RemoteLogger.php">
namespace Automattic\WooCommerce\Internal\Logging;
⋮----
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use Automattic\WooCommerce\Utilities\StringUtil;
use Automattic\WooCommerce\Internal\McStats;
use Jetpack_Options;
use WC_Rate_Limiter;
use WC_Log_Levels;
use WC_Site_Tracking;
⋮----
class RemoteLogger extends \WC_Log_Handler {
⋮----
public function handle( $timestamp, $level, $message, $context ) {
⋮----
if ( ! $this->should_handle( $level, $message, $context ) ) {
⋮----
return $this->log( $level, $message, $context );
⋮----
SafeGlobalFunctionProxy::wc_get_logger()->error( 'Failed to handle the log: ' . $e->getMessage(), array( 'source' => 'remote-logging' ) );
⋮----
public function get_formatted_log( $level, $message, $context = array() ) {
⋮----
'message'    => $this->sanitize( $message ),
'host'       => SafeGlobalFunctionProxy::wp_parse_url( SafeGlobalFunctionProxy::home_url(), PHP_URL_HOST ) ?? 'Unable to retrieve host',
⋮----
'wc_version'  => $this->get_wc_version(),
⋮----
'wp_version'  => SafeGlobalFunctionProxy::get_bloginfo( 'version' ) ?? 'Unable to retrieve wp version',
'request_uri' => $this->sanitize_request_uri( filter_input( INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL ) ),
'store_id'    => SafeGlobalFunctionProxy::get_option( \WC_Install::STORE_ID_OPTION, null ) ?? 'Unable to retrieve store id',
... (113 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Logging/SafeGlobalFunctionProxy.php">
namespace Automattic\WooCommerce\Internal\Logging;
⋮----
class SafeGlobalFunctionProxy {
⋮----
private static function maybe_load_missing_function( $name ) {
⋮----
throw new \Exception( sprintf( 'Function %s does not exist and could not be loaded.', esc_html( $name ) ) );
⋮----
public static function __callStatic( $name, $arguments ) {
⋮----
throw new \ErrorException( $sanitized_message, 0, $type, $file, $line );
⋮----
self::maybe_load_missing_function( $name );
⋮----
self::log_wrapper_error( $name, $e->getMessage(), $arguments );
⋮----
protected static function log_wrapper_error( $function_name, $error_message, $context = array() ) {
self::maybe_load_missing_function( 'wc_get_logger' );
⋮----
wc_get_logger()->error(
</file>

<file path="plugins/woocommerce/src/Internal/MCP/Transport/WooCommerceRestTransport.php">
namespace Automattic\WooCommerce\Internal\MCP\Transport;
⋮----
use WP\MCP\Transport\HttpTransport;
use WP\MCP\Transport\Infrastructure\McpTransportContext;
use WP_REST_Request;
use WP_Error;
⋮----
class WooCommerceRestTransport extends HttpTransport {
⋮----
private static $current_mcp_permissions = null;
⋮----
public function __construct( McpTransportContext $context ) {
parent::__construct( $context );
⋮----
public function check_permission( $request = null ) {
return $this->validate_request( $request );
⋮----
public function validate_request( \WP_REST_Request $request ) {
⋮----
return new \WP_Error(
⋮----
$api_key = $request->get_header( 'X-MCP-API-Key' );
⋮----
$result = $this->authenticate( $consumer_key, $consumer_secret );
⋮----
private function authenticate( $consumer_key, $consumer_secret ) {
⋮----
$user_data = $wpdb->get_row(
$wpdb->prepare(
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/MCP/MCPAdapterProvider.php">
namespace Automattic\WooCommerce\Internal\MCP;
⋮----
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use Automattic\WooCommerce\Internal\Abilities\AbilitiesRegistry;
use Automattic\WooCommerce\Internal\Abilities\REST\RestAbilityFactory;
use Automattic\WooCommerce\Internal\MCP\Transport\WooCommerceRestTransport;
⋮----
class MCPAdapterProvider {
⋮----
private bool $initialized = false;
⋮----
public function __construct() {
⋮----
public function maybe_initialize(): void {
⋮----
if ( ! FeaturesUtil::feature_is_enabled( 'mcp_integration' ) ) {
⋮----
$this->initialize_mcp_adapter();
$this->register_hooks();
⋮----
private function initialize_mcp_adapter(): void {
⋮----
wc_get_logger()->warning(
⋮----
\WP\MCP\Core\McpAdapter::instance();
⋮----
private function register_hooks(): void {
⋮----
public function initialize_mcp_server( $adapter ): void {
⋮----
... (26 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/OrderReviews/Endpoint.php">
namespace Automattic\WooCommerce\Internal\OrderReviews;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Enums\OrderStatus;
use WC_Order;
use WP_Post;
⋮----
class Endpoint {
⋮----
final public function init(): void {
⋮----
public function maybe_create_host_page(): void {
⋮----
$canonical = $this->find_canonical_host_page();
⋮----
$this->queue_pending_rewrite_flush();
⋮----
\WC_Install::create_pages();
⋮----
public function inject_review_order_page( $pages ) {
⋮----
private function find_canonical_host_page(): ?WP_Post {
⋮----
public function add_post_state_label( $post_states, $post ) {
⋮----
public function exclude_self_from_page_list( $pages ) {
⋮----
public function maybe_hide_page_title( $title, $post_id = 0 ) {
⋮----
/**
... (144 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/OrderReviews/ItemEligibility.php">
namespace Automattic\WooCommerce\Internal\OrderReviews;
⋮----
use WC_Order;
use WC_Order_Item;
use WC_Order_Item_Product;
use WP_Comment;
⋮----
class ItemEligibility {
⋮----
private static array $review_cache = array();
⋮----
private static array $preloaded = array();
⋮----
final public function init(): void {
⋮----
public static function render_variation_summary( \WP_Comment $comment ): void {
⋮----
/**
	 * Pre-fill the per-request review cache for a set of items in one query.
	 *
	 * Call this from the template before iterating items so each subsequent
	 * `decide()` / `prefill_for_item()` call hits the cache instead of running
	 * its own `get_comments()` query.
	 *
	 * @since 10.8.0
	 *
	 * @param iterable<WC_Order_Item_Product|mixed> $items Order line items.
	 * @param WC_Order                              $order Order being reviewed.
	 */
public static function preload_for_items( iterable $items, WC_Order $order ): void {
... (80 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/OrderReviews/Meta.php">
namespace Automattic\WooCommerce\Internal\OrderReviews;
⋮----
use WC_Order;
⋮----
class Meta {
⋮----
public static function parts_for_order( WC_Order $order ): array {
$date_created    = $order->get_date_created();
$customer_name   = trim( $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() );
$customer_email  = $order->get_billing_email();
$order_number    = $order->get_order_number();
⋮----
/* translators: 1: order number, 2: order date */
⋮----
__( 'Order #%s', 'woocommerce' ),
</file>

<file path="plugins/woocommerce/src/Internal/OrderReviews/Scheduler.php">
namespace Automattic\WooCommerce\Internal\OrderReviews;
⋮----
use Automattic\WooCommerce\Enums\OrderStatus;
use WC_Email_Customer_Review_Request;
use WC_Order;
⋮----
class Scheduler {
⋮----
final public function init(): void {
⋮----
public function handle_status_changed( int $order_id, string $old_status, string $new_status ): void {
⋮----
$this->handle_cancellation( $order_id );
⋮----
public function handle_woocommerce_order_status_completed( int $order_id ): void {
⋮----
$email = $this->get_email();
if ( null === $email || ! $email->is_enabled() ) {
$this->log_skip( $order_id, 'email is disabled' );
⋮----
if ( $order->get_meta( self::SCHEDULED_META_KEY ) ) {
$this->log_skip( $order_id, 'already scheduled' );
⋮----
$this->log_skip( $order_id, 'opt-out filter returned false' );
⋮----
if ( ! ItemEligibility::has_actionable_items( $order ) ) {
$this->log_skip( $order_id, 'no reviewable items' );
⋮----
$when = time() + $email->get_delay_seconds();
⋮----
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/OrderReviews/StarRating.php">
namespace Automattic\WooCommerce\Internal\OrderReviews;
⋮----
class StarRating {
⋮----
public static function render( array $args ): string {
⋮----
'labels'    => self::get_labels(),
⋮----
public static function get_labels(): array {
</file>

<file path="plugins/woocommerce/src/Internal/OrderReviews/SubmissionHandler.php">
namespace Automattic\WooCommerce\Internal\OrderReviews;
⋮----
use Automattic\WooCommerce\Enums\OrderStatus;
use WC_Order;
⋮----
class SubmissionHandler {
⋮----
final public function init(): void {
⋮----
public function handle(): void {
⋮----
// Row-level fields are sanitized inside process_rows(); the array as a whole only needs unslashing.
⋮----
if ( '' === $key || ! hash_equals( $order->get_order_key(), $key ) ) {
⋮----
if ( $order->get_customer_id() && is_user_logged_in() && get_current_user_id() !== $order->get_customer_id() ) {
⋮----
if ( ! in_array( $order->get_status(), $eligible_statuses, true ) ) {
⋮----
$results = $this->process_rows( $order, $rows_in );
⋮----
$this->maybe_mark_order_complete( $order );
⋮----
private function process_rows( WC_Order $order, array $rows_in ): array {
⋮----
$item_index   = $this->index_eligible_order_items( $order );
$author_name  = trim( $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() );
$author_email = $order->get_billing_email();
$author_ip    = $order->get_customer_ip_address();
$author_agent = $order->get_customer_user_agent();
... (57 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Orders/CouponsController.php">
namespace Automattic\WooCommerce\Internal\Orders;
⋮----
use Automattic\WooCommerce\Utilities\ArrayUtil;
use Automattic\WooCommerce\Utilities\StringUtil;
use Exception;
⋮----
class CouponsController {
⋮----
public function add_coupon_discount_via_ajax(): void {
⋮----
$order = $this->add_coupon_discount( $_POST );
⋮----
$notes = wc_get_order_notes( array( 'order_id' => $order->get_id() ) );
⋮----
wp_send_json_error( array( 'error' => $e->getMessage() ) );
⋮----
public function add_coupon_discount( array $post_variables ): object {
⋮----
$coupon = ArrayUtil::get_value_or_default( $post_variables, 'coupon' );
if ( StringUtil::is_null_or_whitespace( $coupon ) ) {
⋮----
$order->set_customer_id( $user_id_arg );
⋮----
$order->set_billing_email( $user_email_arg );
⋮----
$order->calculate_taxes( $calculate_tax_args );
$order->calculate_totals( false );
⋮----
$code = wc_format_coupon_code( wp_unslash( $coupon ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Orders/IppFunctions.php">
namespace Automattic\WooCommerce\Internal\Orders;
⋮----
use WC_Order;
use WC_Gateway_COD;
⋮----
class IppFunctions {
⋮----
public static function is_order_in_person_payment_eligible( WC_Order $order ): bool {
$has_status            = in_array( $order->get_status(), array( 'pending', 'on-hold', 'processing' ), true );
$has_payment_method    = in_array( $order->get_payment_method(), array( WC_Gateway_COD::ID, 'woocommerce_payments', 'none' ), true );
$order_is_not_paid     = null === $order->get_date_paid();
$order_is_not_refunded = empty( $order->get_refunds() );
⋮----
foreach ( $order->get_items() as $item ) {
$product = $item->get_product();
⋮----
if ( is_object( $product ) && $product->is_type( 'subscription' ) ) {
⋮----
public static function is_store_in_person_payment_eligible(): bool {
$is_store_usa_based    = self::has_store_specified_country_currency( 'US', 'USD' );
$is_store_canada_based = self::has_store_specified_country_currency( 'CA', 'CAD' );
⋮----
public static function has_store_specified_country_currency( string $country, string $currency ): bool {
return ( WC()->countries->get_base_country() === $country && get_woocommerce_currency() === $currency );
</file>

<file path="plugins/woocommerce/src/Internal/Orders/MobileMessagingHandler.php">
namespace Automattic\WooCommerce\Internal\Orders;
⋮----
use DateTime;
use Exception;
use WC_Order;
use WC_Tracker;
⋮----
class MobileMessagingHandler {
⋮----
public static function prepare_mobile_message(
⋮----
$last_mobile_used = self::get_closer_mobile_usage_date();
⋮----
$used_app_in_last_month = null !== $last_mobile_used && $last_mobile_used->diff( $now )->days <= self::OPEN_ORDER_INTERVAL_DAYS;
⋮----
if ( IppFunctions::is_store_in_person_payment_eligible() && IppFunctions::is_order_in_person_payment_eligible( $order ) ) {
return self::accept_payment_message( $blog_id, $domain );
⋮----
return self::manage_order_message( $blog_id, $order->get_id(), $domain );
⋮----
return self::no_app_message( $blog_id, $domain );
⋮----
private static function get_closer_mobile_usage_date(): ?DateTime {
$mobile_usage = WC_Tracker::get_woocommerce_mobile_usage();
⋮----
$last_ios_used     = self::get_last_used_or_null( 'ios', $mobile_usage );
$last_android_used = self::get_last_used_or_null( 'android', $mobile_usage );
⋮----
private static function get_last_used_or_null(
⋮----
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Orders/OrderActionsRestController.php">
namespace Automattic\WooCommerce\Internal\Orders;
⋮----
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\RestApiControllerBase;
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
use WC_Data_Exception;
use WC_Email;
use WC_Order;
use WP_Error;
use WP_REST_Request, WP_REST_Response, WP_REST_Server;
⋮----
class OrderActionsRestController extends RestApiControllerBase {
⋮----
protected function get_rest_api_namespace(): string {
⋮----
public function register_routes(): void {
⋮----
'callback'            => fn( $request ) => $this->run( $request, 'get_email_templates' ),
'permission_callback' => fn( $request ) => $this->check_permissions( $request ),
⋮----
'callback'            => fn( $request ) => $this->run( $request, 'send_email' ),
⋮----
'args'                => $this->get_args_for_order_actions( 'send_email', WP_REST_Server::CREATABLE ),
⋮----
'callback'            => fn( $request ) => $this->run( $request, 'send_order_details' ),
⋮----
'args'                => $this->get_args_for_order_actions( 'send_order_details', WP_REST_Server::CREATABLE ),
⋮----
private function validate_order_id( WP_REST_Request $request ) {
$order_id = $request->get_param( 'id' );
... (153 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Orders/OrderAttributionBlocksController.php">
namespace Automattic\WooCommerce\Internal\Orders;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
use Automattic\WooCommerce\StoreApi\Schemas\V1\CheckoutSchema;
use Automattic\WooCommerce\Internal\Traits\ScriptDebug;
use WP_Error;
⋮----
class OrderAttributionBlocksController implements RegisterHooksInterface {
⋮----
private $features_controller;
⋮----
private $extend_schema;
⋮----
private $order_attribution_controller;
⋮----
final public function init(
⋮----
public function register() {
⋮----
public function on_init() {
⋮----
if ( ! $this->features_controller->feature_is_enabled( 'order_attribution' ) ) {
⋮----
$this->extend_api();
⋮----
private function extend_api() {
$this->extend_schema->register_endpoint_data(
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Orders/OrderAttributionController.php">
namespace Automattic\WooCommerce\Internal\Orders;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\Integrations\WPConsentAPI;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Automattic\WooCommerce\Internal\Traits\ScriptDebug;
use Automattic\WooCommerce\Internal\Traits\OrderAttributionMeta;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Exception;
use WC_Customer;
use WC_Log_Levels;
use WC_Logger_Interface;
use WC_Order;
⋮----
class OrderAttributionController implements RegisterHooksInterface {
⋮----
private $consent;
⋮----
private $feature_controller;
⋮----
private $logger;
⋮----
private $proxy;
⋮----
private static $is_stamp_html_called = false;
⋮----
final public function init( LegacyProxy $proxy, FeaturesController $controller, WPConsentAPI $consent ) {
⋮----
... (113 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Orders/OrderNoteGroup.php">
namespace Automattic\WooCommerce\Internal\Orders;
⋮----
final class OrderNoteGroup {
⋮----
public static function get_default_group_title( string $group ): string {
</file>

<file path="plugins/woocommerce/src/Internal/Orders/OrderStatusRestController.php">
namespace Automattic\WooCommerce\Internal\Orders;
⋮----
use Automattic\WooCommerce\Internal\RestApiControllerBase;
use WP_Error;
use WP_REST_Request;
use WP_REST_Server;
⋮----
class OrderStatusRestController extends RestApiControllerBase {
⋮----
protected $namespace = 'wc/v3';
⋮----
protected $rest_base = 'orders/statuses';
⋮----
protected function get_rest_api_namespace(): string {
⋮----
public function register_routes() {
⋮----
$this->get_rest_api_namespace(),
⋮----
public function get_items( WP_REST_Request $request ) {
⋮----
public function get_item_schema() {
</file>

<file path="plugins/woocommerce/src/Internal/Orders/PaymentInfo.php">
namespace Automattic\WooCommerce\Internal\Orders;
⋮----
use Automattic\WooCommerce\Utilities\StringUtil;
use WC_Abstract_Order;
⋮----
class PaymentInfo {
⋮----
public static function get_card_info( WC_Abstract_Order $order ): array {
$method = $order->get_payment_method();
⋮----
$info = self::get_wcpay_card_info( $order );
⋮----
$info['icon'] = self::get_card_icon( $info['brand'] );
⋮----
private static function get_card_icon( ?string $brand ): string {
⋮----
private static function get_wcpay_card_info( WC_Abstract_Order $order ): array {
if ( 'woocommerce_payments' !== $order->get_payment_method() ) {
⋮----
$stored_payment_details = $order->get_meta( $cache_meta_key );
⋮----
$payment_method_id = $order->get_meta( '_payment_method_id' );
⋮----
$payment_details = \WC_Payments::get_payments_api_client()->get_payment_method( $payment_method_id );
⋮----
$order_id = $order->get_id();
$message  = $ex->getMessage();
wc_get_logger()->error(
⋮----
StringUtil::class_name_without_namespace( static::class ),
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Orders/PointOfSaleEmailHandler.php">
namespace Automattic\WooCommerce\Internal\Orders;
⋮----
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use WC_Abstract_Order;
⋮----
class PointOfSaleEmailHandler implements RegisterHooksInterface {
⋮----
public function register(): void {
⋮----
public function maybe_suppress_email( bool $enabled, $order ): bool {
⋮----
if ( PointOfSaleOrderUtil::is_order_paid_at_pos( $order ) ) {
</file>

<file path="plugins/woocommerce/src/Internal/Orders/PointOfSaleOrderUtil.php">
namespace Automattic\WooCommerce\Internal\Orders;
⋮----
use WC_Abstract_Order;
⋮----
class PointOfSaleOrderUtil {
⋮----
public static function is_pos_order( WC_Abstract_Order $order ): bool {
return 'pos-rest-api' === $order->get_created_via();
⋮----
public static function is_order_paid_at_pos( WC_Abstract_Order $order ): bool {
if ( self::is_pos_order( $order ) ) {
⋮----
if ( 'mobile_pos' === $order->get_meta( '_wcpay_ipp_channel' ) ) {
⋮----
if ( 'mobile_pos' === $order->get_meta( '_stripe_ipp_channel' ) ) {
⋮----
if ( '' !== $order->get_meta( '_cash_change_amount' ) ) {
</file>

<file path="plugins/woocommerce/src/Internal/Orders/TaxesController.php">
namespace Automattic\WooCommerce\Internal\Orders;
⋮----
class TaxesController {
⋮----
public function calc_line_taxes_via_ajax(): void {
⋮----
$order = $this->calc_line_taxes( $_POST );
⋮----
public function calc_line_taxes( array $post_variables ): object {
⋮----
// Parse the jQuery serialized items.
⋮----
$order->calculate_taxes( $calculate_tax_args );
$order->calculate_totals( false );
</file>

<file path="plugins/woocommerce/src/Internal/OrderWithdrawal/Emails/OrderWithdrawalEmailDataFormatter.php">
namespace Automattic\WooCommerce\Internal\OrderWithdrawal\Emails;
⋮----
use Automattic\WooCommerce\Internal\OrderWithdrawal\OrderWithdrawalFormProcessor;
⋮----
final class OrderWithdrawalEmailDataFormatter {
⋮----
public function normalize_withdrawal_data( array $data ): ?array {
⋮----
/**
	 * Get the customer's full name for display.
	 *
	 * @param array<string,string> $data Form data.
	 */
public function get_customer_name( array $data ): string {
⋮----
/**
	 * Get the label for a withdrawal type value.
	 *
	 * @param string $withdrawal_type Withdrawal type value.
	 */
public function get_withdrawal_type_label( string $withdrawal_type ): string {
⋮----
/**
	 * Get order withdrawal detail rows for email templates.
	 *
	 * @param array<string,string> $data         Form data.
	 * @param int                  $submitted_at Unix timestamp for the submission.
	 * @return array<string,string>
	 */
public function get_detail_rows( array $data, int $submitted_at ): array {
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/OrderWithdrawal/Emails/OrderWithdrawalEmailPreview.php">
namespace Automattic\WooCommerce\Internal\OrderWithdrawal\Emails;
⋮----
use Automattic\WooCommerce\Internal\OrderWithdrawal\OrderWithdrawalFormProcessor;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use WC_Email_Customer_Order_Withdrawal_Requested;
use WC_Email_Order_Withdrawal_Requested;
use WC_Order;
⋮----
final class OrderWithdrawalEmailPreview implements RegisterHooksInterface {
⋮----
public function register(): void {
⋮----
public function prepare_email_for_preview( $email ) {
⋮----
$order_date                                  = $order->get_date_created();
⋮----
OrderWithdrawalFormProcessor::FIELD_FIRST_NAME => $order->get_billing_first_name(),
OrderWithdrawalFormProcessor::FIELD_LAST_NAME  => $order->get_billing_last_name(),
OrderWithdrawalFormProcessor::FIELD_EMAIL      => $order->get_billing_email(),
OrderWithdrawalFormProcessor::FIELD_ORDER_NUMBER => $order->get_order_number(),
⋮----
$email->submitted_at                         = $order_date ? $order_date->getTimestamp() : time();
$email->placeholders['{order_number}']       = $order->get_order_number();
$email->placeholders['{order_billing_name}'] = $order->get_formatted_billing_full_name();
</file>

<file path="plugins/woocommerce/src/Internal/OrderWithdrawal/OrderWithdrawalController.php">
namespace Automattic\WooCommerce\Internal\OrderWithdrawal;
⋮----
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\OrderWithdrawal\Emails\OrderWithdrawalEmailPreview;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
final class OrderWithdrawalController implements RegisterHooksInterface {
⋮----
private OrderWithdrawalFormProcessor $form_processor;
⋮----
private OrderWithdrawalFormView $form_view;
⋮----
private OrderWithdrawalFeatureHighlightNotification $feature_highlight_notification;
⋮----
private OrderWithdrawalEmailPreview $email_preview;
⋮----
final public function init( OrderWithdrawalFormProcessor $form_processor, OrderWithdrawalFormView $form_view, OrderWithdrawalFeatureHighlightNotification $feature_highlight_notification, OrderWithdrawalEmailPreview $email_preview ): void {
⋮----
public function register(): void {
⋮----
public function register_feature_hooks(): void {
⋮----
if ( ! $this->is_enabled() ) {
$this->feature_highlight_notification->register();
⋮----
$this->email_preview->register();
⋮----
public function is_enabled(): bool {
return FeaturesUtil::feature_is_enabled( self::FEATURE_ID );
... (34 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/OrderWithdrawal/OrderWithdrawalFeatureHighlightNotification.php">
namespace Automattic\WooCommerce\Internal\OrderWithdrawal;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\DataStore as NotesDataStore;
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Exception;
⋮----
final class OrderWithdrawalFeatureHighlightNotification implements RegisterHooksInterface {
⋮----
public function register(): void {
⋮----
public function maybe_add_note_when_store_goes_live( $old_value, $value ): void {
⋮----
$this->possibly_add_note();
⋮----
public function possibly_add_note(): void {
⋮----
if ( $this->has_note_been_created() ) {
⋮----
if ( ! $this->is_applicable() ) {
⋮----
$this->get_note()->save();
⋮----
wc_get_logger()->error(
⋮----
private function is_applicable(): bool {
⋮----
&& $this->store_sells_to_eu_or_all_countries();
⋮----
... (22 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/OrderWithdrawal/OrderWithdrawalFormProcessor.php">
namespace Automattic\WooCommerce\Internal\OrderWithdrawal;
⋮----
use Automattic\WooCommerce\Admin\Notes\Note;
use Automattic\WooCommerce\Admin\Notes\Notes;
use Automattic\WooCommerce\Internal\OrderWithdrawal\Emails\OrderWithdrawalEmailDataFormatter;
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Throwable;
use WC_Email_Customer_Order_Withdrawal_Requested;
use WC_Email_Order_Withdrawal_Requested;
use WC_Geolocation;
use WC_Order;
use WC_Rate_Limiter;
⋮----
final class OrderWithdrawalFormProcessor {
⋮----
private ?OrderWithdrawalEmailDataFormatter $email_data_formatter = null;
⋮----
public function process_current_request(): OrderWithdrawalFormState {
$data   = $this->get_default_form_data();
⋮----
if ( ! $this->is_post_request() ) {
⋮----
if ( ! $this->has_valid_nonce() ) {
⋮----
$data   = $this->get_posted_form_data();
$action = $this->get_posted_action();
⋮----
$errors = $this->validate_form_data( $data );
⋮----
... (226 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/OrderWithdrawal/OrderWithdrawalFormState.php">
namespace Automattic\WooCommerce\Internal\OrderWithdrawal;
⋮----
final class OrderWithdrawalFormState {
⋮----
public string $screen;
⋮----
public array $data;
⋮----
public array $errors;
⋮----
public function __construct( string $screen, array $data, array $errors ) {
</file>

<file path="plugins/woocommerce/src/Internal/OrderWithdrawal/OrderWithdrawalFormView.php">
namespace Automattic\WooCommerce\Internal\OrderWithdrawal;
⋮----
final class OrderWithdrawalFormView {
⋮----
public function get_template_args( OrderWithdrawalFormState $state, string $form_action_url, string $shop_url ): array {
⋮----
'fields'                  => $this->get_prepared_form_fields( $state->errors ),
'withdrawal_type_options' => $this->get_withdrawal_type_options(),
'hidden_fields'           => $this->get_hidden_fields( $state->data ),
'review_rows'             => $this->get_review_rows( $state->data ),
⋮----
private function get_prepared_form_fields( array $errors ): array {
⋮----
foreach ( $this->get_form_field_schema() as $field_key => $field ) {
$field['name']        = OrderWithdrawalFormProcessor::get_field_name( $field_key );
$field['id']          = OrderWithdrawalFormProcessor::get_field_name( $field_key );
⋮----
$field['custom_attributes']['aria-errormessage'] = OrderWithdrawalFormProcessor::get_field_name( $field_key ) . '_error';
⋮----
private function get_hidden_fields( array $data ): array {
⋮----
'name'  => OrderWithdrawalFormProcessor::get_field_name( $field_key ),
⋮----
private function get_review_rows( array $data ): array {
⋮----
'value' => $this->get_customer_name( $data ),
⋮----
'value' => $this->get_withdrawal_type_label( $data[ OrderWithdrawalFormProcessor::FIELD_WITHDRAWAL_TYPE ] ),
⋮----
private function get_form_field_schema(): array {
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/POS/Capabilities.php">
namespace Automattic\WooCommerce\Internal\POS;
⋮----
use Automattic\WooCommerce\Internal\Utilities\Users;
use WP_User;
⋮----
class Capabilities {
⋮----
public static function all_pos_capabilities(): array {
⋮----
public static function has_pos_access( int $user_id ): bool {
⋮----
foreach ( self::all_pos_capabilities() as $cap ) {
⋮----
public static function get_pos_preset( int $user_id ): ?string {
$meta = Users::get_site_user_meta( $user_id, self::POS_PRESET_META_KEY, true );
if ( in_array( $meta, POSPreset::get_all(), true ) ) {
⋮----
public static function pos_staff_user_query_args(): array {
⋮----
'capability__in' => self::all_pos_capabilities(),
⋮----
private static function preset_definitions(): array {
⋮----
public static function capabilities_for_preset( string $preset ): array {
$definitions = self::preset_definitions();
⋮----
public static function set_pos_preset( int $user_id, ?string $preset ): bool {
⋮----
if ( null !== $preset && ! in_array( $preset, POSPreset::get_all(), true ) ) {
⋮----
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/POS/POSController.php">
namespace Automattic\WooCommerce\Internal\POS;
⋮----
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
⋮----
class POSController implements RegisterHooksInterface {
⋮----
private FeaturesController $features_controller;
⋮----
final public function init( FeaturesController $features_controller ): void {
⋮----
public function register(): void {
⋮----
public function on_init(): void {
if ( ! $this->features_controller->feature_is_enabled( self::FEATURE_FLAG ) ) {
</file>

<file path="plugins/woocommerce/src/Internal/POS/POSPreset.php">
namespace Automattic\WooCommerce\Internal\POS;
⋮----
final class POSPreset {
⋮----
public static function get_all(): array {
</file>

<file path="plugins/woocommerce/src/Internal/ProductAttributes/AttributeSlugLength.php">
namespace Automattic\WooCommerce\Internal\ProductAttributes;
⋮----
class AttributeSlugLength {
⋮----
public static function get_character_estimate( string $locale = '' ): int {
⋮----
// Admin screens render in the user's profile language (get_user_locale()),
</file>

<file path="plugins/woocommerce/src/Internal/ProductAttributes/VisualAttributeTermAdmin.php">
namespace Automattic\WooCommerce\Internal\ProductAttributes;
⋮----
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
⋮----
class VisualAttributeTermAdmin implements RegisterHooksInterface {
⋮----
public function register(): void {
⋮----
return $this->add_term_visual_column( $columns, $taxonomy );
⋮----
return $this->render_term_visual_column( $content, $column, $term_id, $taxonomy );
⋮----
public function add_visual_data_to_attribute_terms( $terms, string $taxonomy ) {
if ( is_wp_error( $terms ) || empty( $terms ) || ! VisualAttributeTermMeta::is_visual_attribute_taxonomy( $taxonomy ) ) {
⋮----
$visuals  = VisualAttributeTermMeta::get_term_visuals( $term_ids );
⋮----
$term->visual = $visuals[ $term->term_id ] ?? VisualAttributeTermMeta::get_empty_visual();
⋮----
public function add_product_attribute_term_fields( $taxonomy ): void {
if ( ! VisualAttributeTermMeta::is_visual_attribute_taxonomy( $taxonomy ) ) {
⋮----
self::render_div_visual_attribute_fields( 'term-' );
⋮----
public function edit_product_attribute_term_fields( $term ): void {
if ( ! VisualAttributeTermMeta::is_visual_attribute_taxonomy( $term->taxonomy ) ) {
⋮----
self::render_table_visual_attribute_fields( $term );
⋮----
... (99 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductAttributes/VisualAttributeTermMeta.php">
namespace Automattic\WooCommerce\Internal\ProductAttributes;
⋮----
class VisualAttributeTermMeta {
⋮----
public static function get_empty_visual(): array {
⋮----
/**
	 * Get the normalized visual value for a term.
	 *
	 * @param int    $term_id Term ID.
	 * @param string $image_size Image size for image visual URLs.
	 * @return array{type: string, value: string}
	 *
	 * @since 10.9.0
	 */
public static function get_term_visual( int $term_id, string $image_size = 'thumbnail' ): array {
return self::build_term_visual( $term_id, $image_size );
⋮----
public static function get_term_visuals( array $term_ids, string $image_size = 'thumbnail' ): array {
⋮----
$term_ids = self::prime_term_visual_caches( $term_ids );
⋮----
$visuals[ $term_id ] = self::build_term_visual( $term_id, $image_size );
⋮----
public static function prime_term_visual_caches( array $term_ids ): array {
⋮----
private static function build_term_visual( int $term_id, string $image_size ): array {
⋮----
return self::get_empty_visual();
⋮----
... (60 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductAttributesLookup/CLIRunner.php">
namespace Automattic\WooCommerce\Internal\ProductAttributesLookup;
⋮----
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use WP_CLI;
⋮----
class CLIRunner {
⋮----
private DataRegenerator $data_regenerator;
⋮----
private LookupDataStore $lookup_data_store;
⋮----
public function __construct() {
⋮----
$this->data_regenerator  = $container->get( DataRegenerator::class );
$this->lookup_data_store = $container->get( LookupDataStore::class );
⋮----
public function enable( array $args = array(), array $assoc_args = array() ) {
return $this->invoke( 'enable_core', $args, $assoc_args );
⋮----
private function enable_core( array $args, array $assoc_args ) {
$table_name = $this->lookup_data_store->get_lookup_table_name();
⋮----
$this->warning( "The usage of the of the %W{$table_name}%n table is already enabled." );
⋮----
if ( $this->lookup_data_store->regeneration_is_in_progress() ) {
$this->warning( "The regeneration of the %W{$table_name}%n table is currently in process." );
} elseif ( $this->lookup_data_store->regeneration_was_aborted() ) {
$this->warning( "The regeneration of the %W{$table_name}%n table was aborted." );
} elseif ( 0 === $this->get_lookup_table_info()['total_rows'] ) {
... (177 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductAttributesLookup/DataRegenerator.php">
namespace Automattic\WooCommerce\Internal\ProductAttributesLookup;
⋮----
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
⋮----
class DataRegenerator {
⋮----
private $data_store;
⋮----
private $lookup_table_name;
⋮----
private $last_regeneration_step_failed;
⋮----
public function __construct() {
⋮----
final public function init( LookupDataStore $data_store ) {
⋮----
public function get_last_regeneration_step_failed() {
⋮----
public function initiate_regeneration( bool $in_background = true ): int {
$this->check_can_do_lookup_table_regeneration();
⋮----
$this->enable_or_disable_lookup_table_usage( false );
⋮----
$this->delete_all_attributes_lookup_data( true );
$last_product_id = $this->initialize_table_and_data();
⋮----
$this->data_store->set_regeneration_in_progress_flag();
⋮----
$this->enqueue_regeneration_step_run();
⋮----
... (135 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductAttributesLookup/Filterer.php">
namespace Automattic\WooCommerce\Internal\ProductAttributesLookup;
⋮----
class Filterer {
⋮----
private $data_store;
⋮----
private $lookup_table_name;
⋮----
final public function init( LookupDataStore $data_store ) {
⋮----
$this->lookup_table_name = $data_store->get_lookup_table_name();
⋮----
public function filtering_via_lookup_table_is_active() {
⋮----
public function filter_by_attribute_post_clauses( array $args, \WP_Query $wp_query, array $attributes_to_filter_by ) {
⋮----
$enable_filtering = apply_filters( 'woocommerce_enable_post_clause_filtering', $wp_query->is_main_query(), $wp_query );
⋮----
if ( ! $enable_filtering || ! $this->filtering_via_lookup_table_is_active() ) {
⋮----
public function get_filtered_term_product_counts( $term_ids, $taxonomy, $query_type ) {
⋮----
$tax_query  = \WC_Query::get_main_tax_query();
$meta_query = \WC_Query::get_main_meta_query();
⋮----
$meta_query = new \WP_Meta_Query( $meta_query );
⋮----
if ( $this->filtering_via_lookup_table_is_active() ) {
$query = $this->get_product_counts_query_using_lookup_table( $tax_query, $meta_query, $taxonomy, $term_ids );
⋮----
... (28 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductAttributesLookup/LookupDataStore.php">
namespace Automattic\WooCommerce\Internal\ProductAttributesLookup;
⋮----
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\CatalogVisibility;
use Automattic\WooCommerce\Utilities\ArrayUtil;
use Automattic\WooCommerce\Utilities\StringUtil;
⋮----
class LookupDataStore {
⋮----
private $lookup_table_name;
⋮----
private bool $optimized_db_access_is_enabled;
⋮----
private bool $last_create_operation_failed = false;
⋮----
public function __construct() {
⋮----
$this->can_use_optimized_db_access() &&
⋮----
$this->init_hooks();
⋮----
private function init_hooks() {
⋮----
public function can_use_optimized_db_access() {
⋮----
return is_a( \WC_Data_Store::load( 'product' )->get_current_class_name(), 'WC_Product_Data_Store_CPT', true );
⋮----
public function check_lookup_table_exists() {
⋮----
... (208 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductAttributesLookup/TaxQuery.php">
namespace Automattic\WooCommerce\Internal\ProductAttributesLookup;
⋮----
class TaxQuery extends \WP_Tax_Query {
⋮----
public function get_sql_for_clause( &$clause, $parent_query ) {
⋮----
return parent::get_sql_for_clause( $clause, $parent_query );
⋮----
$fallback = parent::get_sql_for_clause( $clause, $parent_query );
</file>

<file path="plugins/woocommerce/src/Internal/ProductDownloads/ApprovedDirectories/Admin/SyncUI.php">
namespace Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Admin;
⋮----
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register;
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Synchronize;
use Automattic\WooCommerce\Internal\Utilities\Users;
⋮----
class SyncUI {
⋮----
private $register;
⋮----
final public function init( Register $register ) {
⋮----
final public function init_hooks() {
if ( ! Users::is_site_administrator() ) {
⋮----
public function add_tools( array $tools ): array {
$sync = wc_get_container()->get( Synchronize::class );
⋮----
if ( ! $sync->in_progress() ) {
⋮----
$sync->get_progress()
⋮----
public function trigger_sync() {
$this->security_check();
wc_get_container()->get( Synchronize::class )->start();
⋮----
public function clear_existing_entries() {
⋮----
$this->register->delete_all();
⋮----
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductDownloads/ApprovedDirectories/Admin/Table.php">
namespace Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Admin;
⋮----
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register;
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\StoredUrl;
use WP_List_Table;
use WP_Screen;
⋮----
class Table extends WP_List_Table {
⋮----
public function __construct() {
parent::__construct(
⋮----
$this->items_per_page();
⋮----
private function items_per_page() {
⋮----
public function set_items_per_page( $default, string $option, int $value ) {
⋮----
public function no_items() {
⋮----
public function render_views() {
$register = wc_get_container()->get( Register::class );
⋮----
$enabled_count  = $register->count( true );
$disabled_count = $register->count( false );
⋮----
$all_url   = esc_url( add_query_arg( 'view', 'all', $this->get_base_url() ) );
⋮----
/* translators: %s is the count of approved directory list entries. */
⋮----
... (60 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductDownloads/ApprovedDirectories/Admin/UI.php">
namespace Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Admin;
⋮----
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register;
use Automattic\WooCommerce\Internal\Utilities\Users;
use Exception;
use WC_Admin_Settings;
⋮----
class UI {
⋮----
private $register;
⋮----
private $table;
⋮----
final public function init( Register $register ) {
⋮----
final public function init_hooks() {
if ( ! Users::is_site_administrator() ) {
⋮----
public function add_section( array $sections ): array {
⋮----
public function setup() {
if ( ! $this->is_download_urls_screen() ) {
⋮----
$this->admin_notices();
$this->handle_search();
$this->process_actions();
⋮----
public function render() {
if ( null === $this->table || ! $this->is_download_urls_screen() ) {
⋮----
... (95 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductDownloads/ApprovedDirectories/ApprovedDirectoriesException.php">
namespace Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories;
⋮----
use Exception;
⋮----
class ApprovedDirectoriesException extends Exception {
</file>

<file path="plugins/woocommerce/src/Internal/ProductDownloads/ApprovedDirectories/Register.php">
namespace Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories;
⋮----
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Admin\SyncUI;
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Admin\UI;
use Automattic\WooCommerce\Internal\Utilities\URL;
use Automattic\WooCommerce\Internal\Utilities\URLException;
⋮----
class Register {
⋮----
private $mode_option = 'wc_downloads_approved_directories_mode';
⋮----
private $cache = array();
⋮----
final public function init() {
⋮----
wc_get_container()->get( SyncUI::class )->init_hooks();
wc_get_container()->get( UI::class )->init_hooks();
⋮----
wc_get_container()->get( Synchronize::class )->init_hooks();
⋮----
public function get_table(): string {
⋮----
public function get_mode(): string {
⋮----
public function set_mode( string $mode ): bool {
⋮----
public function add_approved_directory( string $url, bool $enabled = true ): int {
$url      = $this->prepare_url_for_upsert( $url );
$existing = $this->get_by_url( $url );
⋮----
... (84 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductDownloads/ApprovedDirectories/StoredUrl.php">
namespace Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories;
⋮----
class StoredUrl {
⋮----
private $id;
⋮----
private $url;
⋮----
private $enabled;
⋮----
public function __construct( int $id, string $url, bool $enabled ) {
⋮----
public function get_id(): int {
⋮----
public function get_url(): string {
⋮----
public function is_enabled(): bool {
</file>

<file path="plugins/woocommerce/src/Internal/ProductDownloads/ApprovedDirectories/Synchronize.php">
namespace Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories;
⋮----
use ActionScheduler_Store;
use Exception;
use Automattic\WooCommerce\Internal\Utilities\URL;
use WC_Admin_Notices;
use WC_Product;
use WC_Queue_Interface;
⋮----
class Synchronize {
⋮----
private $queue;
⋮----
private $register;
⋮----
final public function init( Register $register ) {
$this->queue    = WC()->get_instance_of( WC_Queue_Interface::class );
⋮----
final public function init_hooks() {
⋮----
public function init_feature( bool $synchronize = true, bool $enable_feature = true ) {
⋮----
$this->add_default_directories();
⋮----
$this->start();
⋮----
wc_get_logger()->log( 'warning', __( 'It was not possible to synchronize download directories following the most recent update.', 'woocommerce' ) );
⋮----
$this->register->set_mode(
⋮----
... (63 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Feed/FeedInterface.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Feed;
⋮----
interface FeedInterface {
⋮----
public function start(): void;
⋮----
public function add_entry( array $entry ): void;
⋮----
public function end(): void;
⋮----
public function get_file_path(): ?string;
⋮----
public function get_file_url(): ?string;
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Feed/FeedLockException.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Feed;
⋮----
use Exception;
⋮----
class FeedLockException extends Exception {}
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Feed/FeedValidatorInterface.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Feed;
⋮----
interface FeedValidatorInterface {
⋮----
public function validate_entry( array $row, \WC_Product $product ): array;
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Feed/ProductLoader.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Feed;
⋮----
class ProductLoader {
⋮----
public function get_products( array $args ) {
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Feed/ProductMapperInterface.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Feed;
⋮----
use Automattic\WooCommerce\Internal\ProductFeed\Mapping\ProductShapeMapperInterface;
⋮----
interface ProductMapperInterface extends ProductShapeMapperInterface {
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Feed/ProductWalker.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Feed;
⋮----
use Automattic\WooCommerce\Internal\ProductFeed\Integrations\IntegrationInterface;
use Automattic\WooCommerce\Internal\ProductFeed\Mapping\ProductShapeMapperInterface;
use Automattic\WooCommerce\Internal\ProductFeed\Utils\MemoryManager;
⋮----
class ProductWalker {
⋮----
private ProductLoader $product_loader;
⋮----
private ProductShapeMapperInterface $mapper;
⋮----
private FeedInterface $feed;
⋮----
private FeedValidatorInterface $validator;
⋮----
private MemoryManager $memory_manager;
⋮----
private int $per_page = 100;
⋮----
private int $time_limit = 0;
⋮----
private array $query_args;
⋮----
private function __construct(
⋮----
public static function from_integration(
⋮----
$integration->get_product_feed_query_args()
⋮----
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Feed/ResumableFeedInterface.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Feed;
⋮----
interface ResumableFeedInterface extends FeedInterface {
⋮----
public function open( ?string $resume_identifier = null, int $entries_written = 0 ): string;
⋮----
public function flush(): void;
⋮----
public function delete( string $identifier ): void;
⋮----
public function get_entry_count(): int;
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Feed/WalkerProgress.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Feed;
⋮----
final class WalkerProgress {
⋮----
public int $total_count;
⋮----
public int $total_batch_count;
⋮----
public int $processed_items = 0;
⋮----
public int $processed_batches = 0;
⋮----
public static function from_wc_get_products_result( \stdClass $result ): self {
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Integrations/POSCatalog/ApiController.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Integrations\POSCatalog;
⋮----
use Automattic\WooCommerce\Container;
use Automattic\WooCommerce\Internal\ProductFeed\Storage\JsonFileFeed;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class ApiController {
⋮----
private $container;
⋮----
final public function init( Container $container ): void {
⋮----
public function register_routes(): void {
⋮----
public function is_authorized() {
⋮----
public function generate_feed( WP_REST_Request $request ): WP_REST_Response {
$generator = $this->container->get( AsyncGenerator::class );
⋮----
$response = $request->get_param( 'force' )
? $generator->force_regeneration( $params )
: $generator->get_status( $params );
⋮----
$file_url = JsonFileFeed::get_file_url_for_identifier( $file_name );
⋮----
wc_get_logger()->error(
⋮----
array( 'error' => $e->getMessage() )
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Integrations/POSCatalog/AsyncGenerator.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Integrations\POSCatalog;
⋮----
use ActionScheduler_AsyncRequest_QueueRunner;
use ActionScheduler_Store;
use Automattic\WooCommerce\Internal\ProductFeed\Feed\FeedLockException;
use Automattic\WooCommerce\Internal\ProductFeed\Feed\ProductWalker;
use Automattic\WooCommerce\Internal\ProductFeed\Feed\ResumableFeedInterface;
use Automattic\WooCommerce\Internal\ProductFeed\Feed\WalkerProgress;
⋮----
class AsyncGenerator {
⋮----
private $integration;
⋮----
final public function init( POSIntegration $integration ): void {
⋮----
public function register_hooks(): void {
⋮----
public function get_status( ?array $args = null ): array {
$option_key = $this->get_option_key( $args );
⋮----
if ( $this->validate_status( $status ) ) {
⋮----
$this->discard_feed( $status );
⋮----
// A stuck in-progress job most likely died because its chunk was too large for this host;
// step the size down so the restart is more likely to fit.
$this->reduce_chunk_size_if_stuck( $status, $option_key );
⋮----
// Whatever made the status invalid (stuck, expired, …), discard the partial feed and start fresh.
⋮----
... (160 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Integrations/POSCatalog/FeedValidator.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Integrations\POSCatalog;
⋮----
use Automattic\WooCommerce\Internal\ProductFeed\Feed\FeedValidatorInterface;
⋮----
final class FeedValidator implements FeedValidatorInterface {
⋮----
public function validate_entry( array $entry, \WC_Product $product ): array {
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Integrations/POSCatalog/POSIntegration.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Integrations\POSCatalog;
⋮----
use Automattic\WooCommerce\Container;
use Automattic\WooCommerce\Internal\ProductFeed\Feed\FeedInterface;
use Automattic\WooCommerce\Internal\ProductFeed\Feed\FeedValidatorInterface;
use Automattic\WooCommerce\Internal\ProductFeed\Feed\ResumableFeedInterface;
use Automattic\WooCommerce\Internal\ProductFeed\Integrations\IntegrationInterface;
use Automattic\WooCommerce\Internal\ProductFeed\Storage\JsonFileFeed;
⋮----
class POSIntegration implements IntegrationInterface {
⋮----
private Container $container;
⋮----
final public function init( Container $container ): void {
⋮----
public function get_id(): string {
⋮----
public function get_product_feed_query_args(): array {
⋮----
public function register_hooks(): void {
⋮----
$this->container->get( AsyncGenerator::class )->register_hooks();
$this->container->get( POSProductVisibilitySync::class )->register_hooks();
⋮----
public function rest_api_init(): void {
⋮----
$this->container->get( ApiController::class )->register_routes();
⋮----
public function activate(): void {
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Integrations/POSCatalog/POSProductVisibilitySync.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Integrations\POSCatalog;
⋮----
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class POSProductVisibilitySync {
⋮----
public function register_hooks(): void {
⋮----
public function is_product_supported( \WC_Product $product ): bool {
return $product->is_type( array( ProductType::SIMPLE, ProductType::VARIABLE ) ) && ! $product->is_downloadable();
⋮----
public function set_product_pos_visibility( int $product_id, bool $visible_in_pos ): void {
⋮----
if ( $product && $product->is_type( 'variable' ) ) {
$this->sync_pos_visibility_to_variations( $product, $visible_in_pos );
⋮----
private function sync_pos_visibility_to_variations( \WC_Product $product, bool $visible_in_pos ): void {
$variation_ids = $product->get_children();
⋮----
$variation->save();
⋮----
public function inherit_parent_pos_visibility( $variation_id, $variation ): void {
⋮----
$parent_id = $variation->get_parent_id();
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Integrations/POSCatalog/ProductMapper.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Integrations\POSCatalog;
⋮----
use Automattic\WooCommerce\Internal\ProductFeed\Mapping\ProductShapeMapperInterface;
use WC_Product;
use WC_REST_Products_Controller;
use WC_REST_Product_Variations_Controller;
use WP_REST_Request;
⋮----
class ProductMapper implements ProductShapeMapperInterface {
⋮----
private ?string $fields = null;
⋮----
private ?string $variation_fields = null;
⋮----
private ?WC_REST_Products_Controller $products_controller = null;
⋮----
private ?WC_REST_Product_Variations_Controller $variations_controller = null;
⋮----
private ?WP_REST_Request $products_request = null;
⋮----
private ?WP_REST_Request $variations_request = null;
⋮----
final public function init(): void {
⋮----
public function set_fields( ?string $fields = null ): void {
⋮----
public function set_variation_fields( ?string $fields = null ): void {
⋮----
public function map_product( WC_Product $product ): array {
$is_variation = $product->is_type( 'variation' );
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Integrations/IntegrationInterface.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Integrations;
⋮----
use Automattic\WooCommerce\Internal\ProductFeed\Feed\FeedInterface;
use Automattic\WooCommerce\Internal\ProductFeed\Feed\FeedValidatorInterface;
use Automattic\WooCommerce\Internal\ProductFeed\Mapping\ProductShapeMapperInterface;
⋮----
interface IntegrationInterface {
⋮----
public function get_id(): string;
⋮----
public function register_hooks(): void;
⋮----
public function activate(): void;
⋮----
public function deactivate(): void;
⋮----
public function get_product_feed_query_args(): array;
⋮----
public function create_feed(): FeedInterface;
⋮----
public function get_product_mapper(): ProductShapeMapperInterface;
⋮----
public function get_feed_validator(): FeedValidatorInterface;
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Integrations/IntegrationRegistry.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Integrations;
⋮----
class IntegrationRegistry {
⋮----
private array $integrations = array();
⋮----
public function register_integration( IntegrationInterface $integration ): void {
$this->integrations[ $integration->get_id() ] = $integration;
⋮----
public function get_integration( string $id ): ?IntegrationInterface {
⋮----
public function get_integrations(): array {
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Mapping/ProductShapeMapperInterface.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Mapping;
⋮----
interface ProductShapeMapperInterface {
⋮----
public function map_product( \WC_Product $product ): array;
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Storage/JsonFileFeed.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Storage;
⋮----
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
use Automattic\WooCommerce\Internal\ProductFeed\Feed\FeedInterface;
use Automattic\WooCommerce\Internal\ProductFeed\Feed\FeedLockException;
use Automattic\WooCommerce\Internal\ProductFeed\Feed\ResumableFeedInterface;
use Exception;
⋮----
class JsonFileFeed implements ResumableFeedInterface {
⋮----
private $entry_count = 0;
⋮----
private $base_name;
⋮----
private $file_name;
⋮----
private $file_path;
⋮----
private $file_handle = null;
⋮----
private $file_completed = false;
⋮----
private $file_url = null;
⋮----
private $prepared_upload_dir = null;
⋮----
public function __construct( string $base_name ) {
⋮----
public function start(): void {
$this->open();
... (65 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Utils/MemoryManager.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Utils;
⋮----
class MemoryManager {
⋮----
public function get_available_memory(): int {
⋮----
public function flush_caches(): void {
⋮----
$wp_object_cache->__remoteset();
⋮----
$this->collect_garbage();
⋮----
private function collect_garbage(): void {
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/Utils/StringHelper.php">
namespace Automattic\WooCommerce\Internal\ProductFeed\Utils;
⋮----
class StringHelper {
⋮----
public static function bool_string( $value ): string {
⋮----
public static function truncate( string $text, int $max_length ): string {
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/ProductFeed.php">
namespace Automattic\WooCommerce\Internal\ProductFeed;
⋮----
use Automattic\WooCommerce\Internal\ProductFeed\Integrations\IntegrationInterface;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Automattic\WooCommerce\Internal\ProductFeed\Integrations\IntegrationRegistry;
use Automattic\WooCommerce\Internal\ProductFeed\Integrations\POSCatalog\POSIntegration;
⋮----
final class ProductFeed implements RegisterHooksInterface {
⋮----
private IntegrationRegistry $integration_registry;
⋮----
public function init(
⋮----
$this->integration_registry->register_integration( $pos_integration );
⋮----
public function register_integration( IntegrationInterface $integration ): void {
$this->integration_registry->register_integration( $integration );
⋮----
public function register(): void {
⋮----
foreach ( $this->integration_registry->get_integrations() as $integration ) {
$integration->register_hooks();
⋮----
public function activate(): void {
⋮----
$integration->activate();
⋮----
public function deactivate(): void {
⋮----
$integration->deactivate();
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductFeed/README.md">
# Product Feed framework

The Product Feed framework provides reusable building blocks for exposing the product catalog to external systems. It separates two concerns that integrations frequently need:

1. **Product-shape mapping** — turning a `WC_Product` into an array shape that a consumer understands.
2. **Feed delivery** — assembling the mapped shapes into a file (JSON, CSV, …) and handing it off to a destination.

Push-feed integrations (for example, the built-in POS Catalog integration or the Stripe Agentic Commerce feed) use both. Pull/live-query integrations (for example, UCP catalog endpoints that run a fresh query on every request) only need the mapping concern and can use it without taking any dependency on file or CSV delivery.

## Directory layout

```text
ProductFeed/
├── ProductFeed.php                  # Entry point; integration registration
├── Mapping/
│   └── ProductShapeMapperInterface.php  # Delivery-agnostic mapping contract
├── Feed/
│   ├── ProductMapperInterface.php   # Deprecated alias of the mapping contract
│   ├── FeedInterface.php            # Feed assembly (start / add_entry / end)
│   ├── FeedValidatorInterface.php   # Per-entry validation for feeds
│   ├── ProductWalker.php            # Batched iteration of the catalog into a feed
│   ├── ProductLoader.php            # Thin wrapper around wc_get_products()
│   └── WalkerProgress.php           # Progress data for walker callbacks
├── Integrations/
│   ├── IntegrationInterface.php     # Contract for push-feed integrations
│   ├── IntegrationRegistry.php      # Holds registered integrations
│   └── POSCatalog/                  # Built-in POS catalog integration
├── Storage/
│   └── JsonFileFeed.php             # File-backed JSON feed implementation
└── Utils/                           # Memory and string helpers
... (90 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductFilters/Interfaces/FilterUrlParam.php">
namespace Automattic\WooCommerce\Internal\ProductFilters\Interfaces;
⋮----
interface FilterUrlParam {
⋮----
public function get_param_keys(): array;
⋮----
public function get_param( string $type ): array;
</file>

<file path="plugins/woocommerce/src/Internal/ProductFilters/Interfaces/MainQueryClausesGenerator.php">
namespace Automattic\WooCommerce\Internal\ProductFilters\Interfaces;
⋮----
interface MainQueryClausesGenerator {
⋮----
public function add_query_clauses_for_main_query( array $args, \WP_Query $wp_query ): array;
</file>

<file path="plugins/woocommerce/src/Internal/ProductFilters/Interfaces/QueryClausesGenerator.php">
namespace Automattic\WooCommerce\Internal\ProductFilters\Interfaces;
⋮----
interface QueryClausesGenerator {
⋮----
public function add_query_clauses( array $args, \WP_Query $wp_query ): array;
</file>

<file path="plugins/woocommerce/src/Internal/ProductFilters/CacheController.php">
namespace Automattic\WooCommerce\Internal\ProductFilters;
⋮----
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Automattic\WooCommerce\Internal\ProductFilters\TaxonomyHierarchyData;
use WC_Cache_Helper;
⋮----
class CacheController implements RegisterHooksInterface {
⋮----
private $taxonomy_hierarchy_data;
⋮----
final public function init( TaxonomyHierarchyData $taxonomy_hierarchy_data ): void {
⋮----
public function register() {
if ( ! $this->need_cleanup() ) {
⋮----
public function invalidate_filter_data_cache(): void {
WC_Cache_Helper::get_transient_version( self::CACHE_GROUP, true );
WC_Cache_Helper::invalidate_cache_group( self::CACHE_GROUP );
⋮----
public function clear_taxonomy_hierarchy_cache( $term_id, $term_taxonomy_id, $taxonomy ) {
⋮----
$this->taxonomy_hierarchy_data->clear_cache( $taxonomy );
⋮----
public function clear_taxonomy_hierarchy_cache_on_meta_update( $meta_id, $term_id, $meta_key, $meta_value ): void {
⋮----
$this->taxonomy_hierarchy_data->clear_cache( $term->taxonomy );
⋮----
public function delete_filter_data_transients(): void {
⋮----
$wpdb->query(
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductFilters/FilterData.php">
namespace Automattic\WooCommerce\Internal\ProductFilters;
⋮----
use Automattic\WooCommerce\Internal\ProductFilters\Interfaces\QueryClausesGenerator;
use Automattic\WooCommerce\Internal\ProductFilters\TaxonomyHierarchyData;
use WC_Cache_Helper;
⋮----
class FilterData {
⋮----
private $query_clauses;
⋮----
private $taxonomy_hierarchy_data;
⋮----
public function __construct( QueryClausesGenerator $query_clauses, TaxonomyHierarchyData $taxonomy_hierarchy_data ) {
⋮----
public function get_filtered_price( array $query_vars ) {
⋮----
$transient_key = $this->get_transient_key( $query_vars, 'price' );
$cached_data   = $this->get_cache( $transient_key );
⋮----
$product_ids = $this->get_cached_product_ids( $query_vars );
⋮----
$results = (array) $wpdb->get_row( $price_filter_sql );
⋮----
$this->set_cache( $transient_key, $results );
⋮----
public function get_stock_status_counts( array $query_vars, array $statuses ) {
⋮----
$transient_key = $this->get_transient_key( $query_vars, 'stock' );
⋮----
foreach ( $wpdb->get_results( $sql ) as $row ) {
... (54 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductFilters/FilterDataProvider.php">
namespace Automattic\WooCommerce\Internal\ProductFilters;
⋮----
use Automattic\WooCommerce\Internal\ProductFilters\Interfaces\QueryClausesGenerator;
use Automattic\WooCommerce\Internal\ProductFilters\TaxonomyHierarchyData;
⋮----
class FilterDataProvider {
⋮----
private $providers = array();
⋮----
private $taxonomy_hierarchy_data;
⋮----
final public function init( TaxonomyHierarchyData $taxonomy_hierarchy_data ): void {
⋮----
public function with( QueryClausesGenerator $query_clauses_generator ) {
</file>

<file path="plugins/woocommerce/src/Internal/ProductFilters/MainQueryController.php">
namespace Automattic\WooCommerce\Internal\ProductFilters;
⋮----
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
⋮----
class MainQueryController implements RegisterHooksInterface {
⋮----
private $query_clauses;
⋮----
private $params;
⋮----
final public function init( QueryClauses $query_clauses, Params $params ): void {
⋮----
public function register(): void {
⋮----
public function add_query_vars( array $query_vars ): array {
return array_merge( $query_vars, $this->params->get_param_keys() );
</file>

<file path="plugins/woocommerce/src/Internal/ProductFilters/Params.php">
namespace Automattic\WooCommerce\Internal\ProductFilters;
⋮----
use Automattic\WooCommerce\Internal\ProductFilters\Interfaces\FilterUrlParam;
⋮----
class Params implements FilterUrlParam {
⋮----
private static $params = array();
⋮----
public function get_param_keys(): array {
⋮----
$this->init_params();
⋮----
public function get_param( string $type ): array {
⋮----
private function init_params(): void {
⋮----
'attribute' => $this->get_attribute_params(),
'taxonomy'  => $this->get_taxonomy_params(),
⋮----
private function get_attribute_params(): array {
⋮----
private function get_taxonomy_params(): array {
</file>

<file path="plugins/woocommerce/src/Internal/ProductFilters/QueryClauses.php">
namespace Automattic\WooCommerce\Internal\ProductFilters;
⋮----
use Automattic\WooCommerce\Enums\TaxDisplayMode;
use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore;
use Automattic\WooCommerce\Internal\ProductFilters\Interfaces\QueryClausesGenerator;
use Automattic\WooCommerce\Internal\ProductFilters\Interfaces\MainQueryClausesGenerator;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use WC_Tax;
use WC_Cache_Helper;
⋮----
class QueryClauses implements QueryClausesGenerator, MainQueryClausesGenerator {
⋮----
private $params;
⋮----
final public function init( Params $params ): void {
⋮----
public function add_query_clauses( array $args, \WP_Query $wp_query ): array {
if ( $wp_query->get( 'filter_stock_status' ) ) {
$stock_statuses = trim( $wp_query->get( 'filter_stock_status' ) );
⋮----
$args = $this->add_stock_clauses( $args, $stock_statuses );
⋮----
if ( $wp_query->get( 'min_price' ) || $wp_query->get( 'max_price' ) ) {
⋮----
'min_price' => $wp_query->get( 'min_price' ),
'max_price' => $wp_query->get( 'max_price' ),
⋮----
$args        = $this->add_price_clauses( $args, $price_range );
⋮----
$args = $this->add_attribute_clauses(
... (88 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductFilters/README.md">
# ProductFilters

## Decisions

This section contains all the decisions we've made for this service.

Decisions here are never final. But these documents should serve as a record for whenever we wonder why certain decisions were made.

### Using WP_Query arguments to calculate contextual filter data

#### Context

Current filter blocks and former filter widgets only care about the product catalog query or the query that returns all products. For example, even when added to the Hoodies category, the filter blocks still show data for all products, including ones belonging to the T-shirts category.

Before Gutenberg, we have product archive contexts including Catalog, Taxonomy, Attribute, and Search. With blocks, we have StoreAPI and Product Collection. All types of context can be customized by altering the product archive query, passing more parameters, or adding Product Collection backend filters.

WooCommerce has some solutions, but each has its own limitations:

-   `Filterer` and `WC_Query`, which power filter widgets, return contextual filter data but only work with the main query.
-   `ProductCollectionData`, which powers filter blocks, returns contextual data only for StoreAPI requests.

We need a more robust solution to show only relevant filter data under the current context, regardless of complexity or how heavily customized it is. The new solution should be able to work with any context, including main queries, custom queries, and REST requests.

#### Decision

Learning from `WC_Query`, `Filterer`, and `ProductCollectionData`, we create a new service named it `ProducFilters`, which can be used in all contexts. The key difference between the new service and existing solutions is the data we pass to the service: `WP_Query` arguments.

Every loop in WordPress is powered by `WP_Query`. By taking the common contract (query arguments) to recreate the product query being requested we can ensure a safe boundary for filter data calculation. In other words, filter data is always calculated from the set of products being displayed, which eliminates the possibility of data mismatch between filter data and actual products.

#### Consequences
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductFilters/TaxonomyHierarchyData.php">
namespace Automattic\WooCommerce\Internal\ProductFilters;
⋮----
class TaxonomyHierarchyData {
⋮----
private $hierarchy_data = array();
⋮----
public function get_hierarchy_map( string $taxonomy ): array {
⋮----
if ( ! empty( $cached_map ) && $this->validate_cache( $cached_map ) ) {
⋮----
$map = $this->build_full_hierarchy_map( $taxonomy );
⋮----
public function get_descendants( int $term_id, string $taxonomy ): array {
$map = $this->get_hierarchy_map( $taxonomy );
⋮----
public function get_ancestors( int $term_id, string $taxonomy ): array {
⋮----
public function clear_cache( string $taxonomy ): void {
⋮----
private function validate_cache( $data ) {
⋮----
private function build_full_hierarchy_map( string $taxonomy ): array {
⋮----
$map['descendants'][ $term_id ] = $this->compute_descendants( $term_id, $temp_children );
$map['ancestors'][ $term_id ]   = $this->compute_ancestors( $term_id, $temp_parents );
⋮----
$this->build_term_tree( $map['tree'], $term_id, $temp_children, $temp_terms );
⋮----
private function build_term_tree( &$tree, $term_id, $children, $temp_terms, $depth = 0 ) {
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductGallery/ProductMediaGallery.php">
namespace Automattic\WooCommerce\Internal\ProductGallery;
⋮----
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use WC_Product;
⋮----
class ProductMediaGallery {
⋮----
public static function is_feature_enabled(): bool {
return FeaturesUtil::feature_is_enabled( self::FEATURE_ID );
⋮----
public static function get_product_media_gallery_items( WC_Product $product, array $args = array() ): array {
⋮----
$media_items           = self::get_product_image_media_items( $product, $include_product_image, $context );
⋮----
if ( self::is_feature_enabled() ) {
$video_gallery = self::normalize_video_gallery_items(
self::get_stored_video_gallery_items( $product )
⋮----
$media_items = self::merge_positioned_video_gallery_items(
⋮----
self::get_video_position_offset( $product, $include_product_image, $context )
⋮----
$media_items = self::deduplicate_media_items( $media_items );
⋮----
$media_items = self::resolve_video_poster_ids( $media_items );
⋮----
public static function get_product_media_gallery_items_for_display( WC_Product $product ): array {
$media_items = self::get_product_media_gallery_items(
⋮----
self::prime_attachment_caches( $media_items, true );
... (118 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ProductImage/MatchImageBySKU.php">
namespace Automattic\WooCommerce\Internal\ProductImage;
⋮----
class MatchImageBySKU {
⋮----
private $setting_name = 'woocommerce_product_match_featured_image_by_sku';
⋮----
public function __construct() {
$this->init_hooks();
⋮----
private function init_hooks() {
⋮----
public function is_enabled() {
⋮----
public function add_product_image_sku_setting( array $settings, string $section_id ): array {
</file>

<file path="plugins/woocommerce/src/Internal/Products/ProductsOrderingMoveService.php">
namespace Automattic\WooCommerce\Internal\Products;
⋮----
final class ProductsOrderingMoveService {
⋮----
private ProductsOrderingReindexService $reindex_service;
⋮----
final public function init( ProductsOrderingReindexService $reindex_service ): void {
⋮----
public function move( int $previous_id, int $product_id, int $next_id ): object {
⋮----
$anchor_positions = $this->compose_anchor_positions( $previous_id, $product_id, $next_id );
if ( ! $this->has_moved( $anchor_positions, $previous_id, $product_id, $next_id ) ) {
⋮----
$map              = $this->compose_move_map( $previous_id, $product_id, $next_id, $anchor_positions );
⋮----
$result['reindexed'] = $this->reindex_service->reindex_products();
⋮----
$result['moved'] = $this->apply( $map, $result['reindexed'] );
⋮----
private function apply( object $map, array $reindexed ): array {
⋮----
$range_ids          = array_merge( array( $map->product_id ), $this->compose_range_ids( $map, $reindexed ) );
⋮----
$updated_count += (int) $wpdb->query(
⋮----
$wpdb->prepare(
⋮----
$updated_count += (int) $wpdb->update( $wpdb->posts, array( 'menu_order' => $map->new_position ), array( 'ID' => $map->product_id ) );
⋮----
$wpdb->get_results(
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Products/ProductsOrderingReindexService.php">
namespace Automattic\WooCommerce\Internal\Products;
⋮----
final class ProductsOrderingReindexService {
⋮----
public function reindex_products( int $batch_size = 250 ): array {
⋮----
$product_ids = array_map( 'intval', $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'product' ORDER BY menu_order ASC, post_title ASC, ID ASC" ) );
⋮----
$updated = (int) $wpdb->query( "UPDATE {$wpdb->posts} SET menu_order = CASE ID {$batch_branches} END WHERE ID IN ( {$in_values} )" );
</file>

<file path="plugins/woocommerce/src/Internal/ProductVariations/SelectedVariationName.php">
namespace Automattic\WooCommerce\Internal\ProductVariations;
⋮----
use Automattic\WooCommerce\Enums\ProductType;
use WC_Data_Store;
use WC_Product;
⋮----
class SelectedVariationName {
⋮----
public function get_product_name( WC_Product $product, array $variation_attributes, bool $filter_custom_attributes = false ): string {
if ( ! $product->is_type( ProductType::VARIATION ) || empty( $variation_attributes ) ) {
return $product->get_name();
⋮----
$product_name       = $product->get_name();
$product_attributes = (array) $product->get_attributes();
⋮----
$data_store = $product->get_data_store();
⋮----
// Stores without the shared title policy keep the stored variation name.
if ( ! $data_store instanceof WC_Data_Store || ! $data_store->has_callable( 'should_include_attributes_in_title' ) ) {
⋮----
if ( ! $data_store->should_include_attributes_in_title( $product ) ) {
⋮----
/**
				 * Filters the display name for a selected variation option.
				 *
				 * @since 3.4.0
				 * @param string          $value Selected variation option value.
				 * @param WP_Term|null    $term Term object when available.
				 * @param string          $name Attribute taxonomy name.
				 * @param WC_Product|null $product Product object.
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Controllers/NotificationPreferencesRestController.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Controllers;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Services\NotificationPreferencesService;
use Automattic\WooCommerce\Internal\PushNotifications\Traits\AuthorizesPushNotificationRequests;
use Automattic\WooCommerce\Internal\PushNotifications\Traits\ConvertsExceptionsToWpError;
use Automattic\WooCommerce\Internal\RestApiControllerBase;
use Exception;
use WP_Error;
use WP_Http;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
⋮----
class NotificationPreferencesRestController extends RestApiControllerBase {
⋮----
protected string $route_namespace = 'wc-push-notifications';
⋮----
protected string $rest_base = 'preferences';
⋮----
private NotificationPreferencesService $preferences_service;
⋮----
final public function init( NotificationPreferencesService $preferences_service ): void {
⋮----
protected function get_rest_api_namespace(): string {
⋮----
public function register_routes(): void {
⋮----
'callback'            => fn ( WP_REST_Request $request ) => $this->run( $request, 'get_preferences' ),
⋮----
'callback'            => fn ( WP_REST_Request $request ) => $this->run( $request, 'update_preferences' ),
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Controllers/PushNotificationRestController.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Controllers;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Notifications\Notification;
use Automattic\WooCommerce\Internal\PushNotifications\PushNotifications;
use Automattic\WooCommerce\Internal\PushNotifications\Services\NotificationProcessor;
use Automattic\WooCommerce\StoreApi\Utilities\JsonWebToken;
use Exception;
use WP_Error;
use WP_Http;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
⋮----
class PushNotificationRestController {
⋮----
public function register(): void {
⋮----
public function register_routes(): void {
⋮----
public function create( WP_REST_Request $request ) {
⋮----
$body             = json_decode( $request->get_body(), true );
⋮----
wc_get_logger()->warning(
⋮----
$processor = wc_get_container()->get( NotificationProcessor::class );
⋮----
$notification = Notification::from_array( $data );
$processor->process( $notification );
⋮----
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Controllers/PushNotificationStatusRestController.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Controllers;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Services\DriverAvailabilityService;
use Automattic\WooCommerce\Internal\PushNotifications\Traits\AuthorizesPushNotificationRequests;
use Automattic\WooCommerce\Internal\RestApiControllerBase;
use WP_Error;
use WP_Http;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
⋮----
class PushNotificationStatusRestController extends RestApiControllerBase {
⋮----
protected string $route_namespace = 'wc-push-notifications';
⋮----
protected string $rest_base = 'status';
⋮----
private DriverAvailabilityService $driver_availability_service;
⋮----
final public function init( DriverAvailabilityService $driver_availability_service ): void {
⋮----
protected function get_rest_api_namespace(): string {
⋮----
public function register_routes(): void {
⋮----
'callback'            => fn ( WP_REST_Request $request ) => $this->run( $request, 'get_status' ),
⋮----
public function get_schema(): array {
⋮----
public function get_status() {
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Controllers/PushTokenRestController.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Controllers;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\DataStores\PushTokensDataStore;
use Automattic\WooCommerce\Internal\PushNotifications\Entities\PushToken;
use Automattic\WooCommerce\Internal\PushNotifications\Exceptions\PushTokenNotFoundException;
use Automattic\WooCommerce\Internal\PushNotifications\PushNotifications;
use Automattic\WooCommerce\Internal\PushNotifications\Traits\AuthorizesPushNotificationRequests;
use Automattic\WooCommerce\Internal\PushNotifications\Traits\ConvertsExceptionsToWpError;
use Automattic\WooCommerce\Internal\PushNotifications\Validators\PushTokenValidator;
use Automattic\WooCommerce\Internal\RestApiControllerBase;
use Exception;
use WC_Data_Exception;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use WP_Http;
⋮----
class PushTokenRestController extends RestApiControllerBase {
⋮----
protected string $route_namespace = 'wc-push-notifications';
⋮----
protected string $rest_base = 'push-tokens';
⋮----
protected function get_rest_api_namespace(): string {
⋮----
public function register_routes(): void {
⋮----
'callback'            => fn ( WP_REST_Request $request ) => $this->run( $request, 'index' ),
⋮----
... (68 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/DataStores/NotificationPreferencesDataStore.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\DataStores;
⋮----
use Automattic\WooCommerce\Internal\Utilities\Users;
use WC_Data_Exception;
use WP_Http;
⋮----
class NotificationPreferencesDataStore {
⋮----
public function read( int $user_id ): ?array {
$stored = Users::get_site_user_meta( $user_id, self::META_KEY );
⋮----
$stored = $this->migrate( $stored, $stored_version );
$this->write( $user_id, $stored );
⋮----
public function write( int $user_id, array $envelope ): void {
⋮----
$result = Users::update_site_user_meta( $user_id, self::META_KEY, $envelope );
⋮----
public function migrate( array $data, int $from_version ): array {
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/DataStores/PushTokensDataStore.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\DataStores;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Entities\PushToken;
use Automattic\WooCommerce\Internal\PushNotifications\Exceptions\PushTokenInvalidDataException;
use Automattic\WooCommerce\Internal\PushNotifications\Exceptions\PushTokenNotFoundException;
use Exception;
use WC_Data_Exception;
use WP_Http;
use WP_Query;
⋮----
class PushTokensDataStore {
⋮----
private array $tokens_by_roles_cache = array();
⋮----
public function create( array $data ): PushToken {
⋮----
if ( ! $push_token->can_be_created() ) {
⋮----
'post_author' => (int) $push_token->get_user_id(),
⋮----
'meta_input'  => $this->build_meta_array_from_token( $push_token ),
⋮----
(string) $id->get_error_code(),
$id->get_error_message(),
⋮----
$push_token->set_id( $id );
⋮----
public function read( int $id ): PushToken {
⋮----
$post       = get_post( $push_token->get_id() );
... (59 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Dispatchers/InternalNotificationDispatcher.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Dispatchers;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Notifications\Notification;
use Automattic\WooCommerce\Internal\PushNotifications\PushNotifications;
use Automattic\WooCommerce\StoreApi\Utilities\JsonWebToken;
⋮----
class InternalNotificationDispatcher {
⋮----
public function dispatch( array $notifications ): void {
⋮----
$encoded = array_map( fn ( Notification $notification ) => $notification->to_array(), $notifications );
⋮----
wc_get_logger()->error(
⋮----
$token = JsonWebToken::create(
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Dispatchers/WpcomNotificationDispatcher.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Dispatchers;
⋮----
use Automattic\Jetpack\Connection\Client as Jetpack_Connection_Client;
use Automattic\WooCommerce\Internal\PushNotifications\Entities\PushToken;
use Automattic\WooCommerce\Internal\PushNotifications\Notifications\Notification;
use Automattic\WooCommerce\Internal\PushNotifications\PushNotifications;
use Jetpack_Options;
use WP_Error;
use WP_Http;
⋮----
class WpcomNotificationDispatcher {
⋮----
public function dispatch( Notification $notification, array $tokens ): array {
$site_id = class_exists( Jetpack_Options::class ) ? Jetpack_Options::get_option( 'id' ) : null;
⋮----
wc_get_logger()->error(
⋮----
$payload = $notification->to_payload();
⋮----
$notification->get_type(),
$notification->get_resource_id()
⋮----
$response = $this->make_request( $site_id, $payload, $tokens );
⋮----
$response->get_error_message()
⋮----
/**
	 * Makes the WPCOM API request via the Jetpack connection.
	 *
	 * @param int         $site_id The Jetpack site ID.
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Entities/PushToken.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Entities;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Exceptions\PushTokenInvalidDataException;
use Automattic\WooCommerce\Internal\PushNotifications\Validators\PushTokenValidator;
⋮----
class PushToken {
⋮----
private ?int $id = null;
⋮----
private ?int $user_id = null;
⋮----
private ?string $token = null;
⋮----
private ?string $device_uuid = null;
⋮----
private ?string $platform = null;
⋮----
private ?string $origin = null;
⋮----
private ?string $device_locale = null;
⋮----
private ?array $metadata = null;
⋮----
public function __construct( array $data = array() ) {
⋮----
$this->set_id( (int) $data['id'] );
⋮----
$this->set_user_id( (int) $data['user_id'] );
⋮----
$this->set_token( (string) $data['token'] );
... (76 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Exceptions/PushTokenInvalidDataException.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Exceptions;
⋮----
use WC_Data_Exception;
use WP_Http;
⋮----
class PushTokenInvalidDataException extends WC_Data_Exception {
⋮----
public function __construct( string $message ) {
parent::__construct(
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Exceptions/PushTokenNotFoundException.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Exceptions;
⋮----
use WC_Data_Exception;
use WP_Http;
⋮----
class PushTokenNotFoundException extends WC_Data_Exception {
⋮----
public function __construct() {
parent::__construct(
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Notifications/NewOrderNotification.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Notifications;
⋮----
use WC_Order;
⋮----
class NewOrderNotification extends Notification {
⋮----
public function get_type(): string {
⋮----
public function to_payload(): ?array {
$order = WC()->call_function( 'wc_get_order', $this->get_resource_id() );
⋮----
'type'        => $this->get_type(),
⋮----
'resource_id' => $this->get_resource_id(),
⋮----
wp_strip_all_tags( $order->get_formatted_order_total() ),
⋮----
'order_id' => $this->get_resource_id(),
⋮----
public function should_send_to_user( $pref_value ): bool {
if ( ! parent::should_send_to_user( $pref_value ) ) {
⋮----
return (float) $order->get_total() >= $min_amount;
⋮----
public function has_meta( string $key ): bool {
⋮----
return $order instanceof WC_Order && $order->meta_exists( $key );
⋮----
public function write_meta( string $key ): void {
⋮----
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Notifications/NewReviewNotification.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Notifications;
⋮----
use WP_Comment;
⋮----
class NewReviewNotification extends Notification {
⋮----
public function get_type(): string {
⋮----
public function should_send_to_user( $pref_value ): bool {
if ( ! parent::should_send_to_user( $pref_value ) ) {
⋮----
$comment = WC()->call_function( 'get_comment', $this->get_resource_id() );
⋮----
$rating = WC()->call_function( 'get_comment_meta', $this->get_resource_id(), 'rating', true );
⋮----
public function to_payload(): ?array {
⋮----
'type'        => $this->get_type(),
⋮----
'resource_id' => $this->get_resource_id(),
⋮----
'comment_id' => $this->get_resource_id(),
⋮----
public function has_meta( string $key ): bool {
return WC()->call_function( 'metadata_exists', 'comment', $this->get_resource_id(), $key );
⋮----
public function write_meta( string $key ): void {
WC()->call_function( 'update_comment_meta', $this->get_resource_id(), $key, (string) time() );
⋮----
public function delete_meta( string $key ): void {
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Notifications/Notification.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Notifications;
⋮----
use InvalidArgumentException;
⋮----
abstract class Notification {
⋮----
private int $resource_id;
⋮----
public function __construct( int $resource_id ) {
⋮----
abstract public function get_type(): string;
⋮----
abstract public function to_payload(): ?array;
⋮----
abstract public function has_meta( string $key ): bool;
⋮----
abstract public function write_meta( string $key ): void;
⋮----
abstract public function delete_meta( string $key ): void;
⋮----
public function to_array(): array {
⋮----
'type'        => $this->get_type(),
⋮----
public static function from_array( array $data ): self {
⋮----
$instance = new $class( $resource_id );
⋮----
$instance->hydrate( $data );
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Notifications/StockNotification.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Notifications;
⋮----
use InvalidArgumentException;
use WC_Product;
⋮----
class StockNotification extends Notification {
⋮----
private string $event_type;
⋮----
private ?int $stock_quantity_at_trigger;
⋮----
public function __construct( int $resource_id, string $event_type = self::EVENT_LOW_STOCK, ?int $stock_quantity_at_trigger = null ) {
parent::__construct( $resource_id );
⋮----
public function hydrate( array $data ): void {
⋮----
public function get_type(): string {
⋮----
public function get_event_type(): string {
⋮----
public function get_identifier(): string {
⋮----
$this->get_type(),
⋮----
$this->get_resource_id()
⋮----
public function get_safety_net_args(): array {
⋮----
$this->get_resource_id(),
⋮----
... (40 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Services/DriverAvailabilityService.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Services;
⋮----
use Automattic\Jetpack\Connection\Manager as JetpackConnectionManager;
use Automattic\WooCommerce\Internal\PushNotifications\PushNotifications;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Error;
use Throwable;
use WC_Logger_Interface;
⋮----
class DriverAvailabilityService {
⋮----
private array $failed_checks = array();
⋮----
public function get_status(): array {
⋮----
if ( $this->is_jetpack_sync_installed() ) {
$installed_drivers[ self::DRIVER_JETPACK_SYNC ] = $this->driver_status(
$this->resolve( $this->has_user_connection(), self::CHECK_USER_CONNECTION ),
$this->resolve( $this->is_jetpack_sync_enabled(), self::CHECK_SYNC_ENABLED )
⋮----
$installed_drivers[ self::DRIVER_REMOTE_PROXY ] = $this->driver_status(
$this->resolve( $this->has_blog_connection(), self::CHECK_BLOG_CONNECTION ),
$this->resolve( $this->is_remote_proxy_enabled(), self::CHECK_PROXY_ENABLED )
⋮----
'preferred_driver'  => $this->get_preferred_driver( $installed_drivers ),
⋮----
private function driver_status( ?bool $connected, ?bool $enabled ): array {
⋮----
private function resolve( bool $result, string $check_key ): ?bool {
⋮----
... (52 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Services/NotificationPreferencesService.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Services;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\DataStores\NotificationPreferencesDataStore;
use Automattic\WooCommerce\Internal\PushNotifications\Notifications\Notification;
⋮----
class NotificationPreferencesService {
⋮----
private NotificationPreferencesDataStore $data_store;
⋮----
final public function init( NotificationPreferencesDataStore $data_store ): void {
⋮----
public function get_preferences( int $user_id ): array {
$envelope = $this->data_store->read( $user_id );
⋮----
return $this->get_defaults();
⋮----
return $this->sanitize( array_replace_recursive( $this->get_defaults(), $stored ) );
⋮----
public function save_preferences( int $user_id, array $preferences ): array {
$current = $this->get_preferences( $user_id );
$merged  = $this->sanitize( array_replace_recursive( $current, $preferences ) );
⋮----
$this->data_store->write(
⋮----
public function get_defaults(): array {
⋮----
private function sanitize( array $preferences ): array {
$allowed   = $this->get_defaults();
⋮----
$sanitized[ $key ] = $this->sanitize_value( $key, $value, $default_shape );
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Services/NotificationProcessor.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Services;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\DataStores\PushTokensDataStore;
use Automattic\WooCommerce\Internal\PushNotifications\Entities\PushToken;
use Automattic\WooCommerce\Internal\PushNotifications\Dispatchers\WpcomNotificationDispatcher;
use Automattic\WooCommerce\Internal\PushNotifications\Notifications\Notification;
use Automattic\WooCommerce\Internal\PushNotifications\PushNotifications;
use Exception;
⋮----
class NotificationProcessor {
⋮----
private WpcomNotificationDispatcher $dispatcher;
⋮----
private PushTokensDataStore $data_store;
⋮----
private NotificationPreferencesService $preferences_service;
⋮----
private NotificationRetryHandler $retry_handler;
⋮----
final public function init(
⋮----
public function register(): void {
⋮----
public function process( Notification $notification, bool $is_retry = false, int $attempt = 0 ): bool {
⋮----
if ( $notification->has_meta( self::SENT_META_KEY ) ) {
⋮----
if ( $notification->has_meta( self::CLAIMED_META_KEY ) ) {
⋮----
$notification->write_meta( self::CLAIMED_META_KEY );
... (37 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Services/NotificationRetryHandler.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Services;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Notifications\Notification;
use Automattic\WooCommerce\Internal\PushNotifications\PushNotifications;
use Exception;
⋮----
class NotificationRetryHandler {
⋮----
public function register(): void {
⋮----
public function schedule( Notification $notification, ?int $retry_after, int $current_attempt ): void {
⋮----
wc_get_logger()->error(
⋮----
$notification->get_type(),
$notification->get_resource_id()
⋮----
wc_get_logger()->warning(
⋮----
'type'        => $notification->get_type(),
'resource_id' => $notification->get_resource_id(),
⋮----
public function handle_retry( string $type, int $resource_id, int $attempt ): void {
⋮----
$notification = Notification::from_array(
⋮----
sprintf( 'Retry failed: %s', $e->getMessage() ),
⋮----
wc_get_container()->get( NotificationProcessor::class )->process(
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Services/PendingNotificationStore.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Services;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Dispatchers\InternalNotificationDispatcher;
use Automattic\WooCommerce\Internal\PushNotifications\Notifications\Notification;
use Automattic\WooCommerce\Internal\PushNotifications\Services\NotificationProcessor;
⋮----
class PendingNotificationStore {
⋮----
private bool $enabled = false;
⋮----
private InternalNotificationDispatcher $dispatcher;
⋮----
private array $pending = array();
⋮----
private bool $shutdown_registered = false;
⋮----
final public function init( InternalNotificationDispatcher $dispatcher ): void {
⋮----
public function register(): void {
⋮----
public function add( Notification $notification ): void {
⋮----
$key = $notification->get_identifier();
⋮----
$this->schedule_safety_net( $notification );
⋮----
private function schedule_safety_net( Notification $notification ): void {
⋮----
$args = $notification->get_safety_net_args();
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Traits/AuthorizesPushNotificationRequests.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Traits;
⋮----
use Automattic\Jetpack\Connection\Rest_Authentication;
use Automattic\WooCommerce\Internal\PushNotifications\PushNotifications;
use WP_Error;
use WP_REST_Request;
⋮----
trait AuthorizesPushNotificationRequests {
⋮----
public function authorize_as_authenticated( WP_REST_Request $request ) {
$authorized = $this->authorize_as_authenticated_ignoring_enablement( $request );
⋮----
return wc_get_container()->get( PushNotifications::class )->should_be_enabled();
⋮----
public function authorize_as_from_wpcom_or_allowed_user( WP_REST_Request $request ) {
if ( $this->is_signed_with_blog_token() ) {
⋮----
return $this->authorize_as_authenticated_ignoring_enablement( $request );
⋮----
private function authorize_as_authenticated_ignoring_enablement( WP_REST_Request $request ) {
⋮----
fn ( $carry, $role ) => $this->check_permission( $request, $role ) === true ? true : $carry,
⋮----
protected function is_signed_with_blog_token(): bool {
return class_exists( Rest_Authentication::class ) && Rest_Authentication::is_signed_with_blog_token();
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Traits/ConvertsExceptionsToWpError.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Traits;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\PushNotifications;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Exception;
use WC_Data_Exception;
use WP_Error;
use WP_Http;
⋮----
trait ConvertsExceptionsToWpError {
⋮----
protected function convert_exception_to_wp_error( Exception $e ): WP_Error {
⋮----
&& $e->getCode() !== WP_Http::INTERNAL_SERVER_ERROR
⋮----
$e->getErrorCode(),
$e->getMessage(),
$e->getErrorData()
⋮----
->get( LegacyProxy::class )
->call_function( 'wc_get_logger' )
->error( $e->getMessage(), array( 'source' => PushNotifications::FEATURE_NAME ) );
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Triggers/NewOrderNotificationTrigger.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Triggers;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Notifications\NewOrderNotification;
use Automattic\WooCommerce\Internal\PushNotifications\Services\PendingNotificationStore;
use WC_Order;
⋮----
class NewOrderNotificationTrigger {
⋮----
public function register(): void {
⋮----
public function on_new_order( int $order_id, WC_Order $order ): void {
if ( ! in_array( $order->get_status(), self::NOTIFIABLE_STATUSES, true ) ) {
⋮----
wc_get_container()->get( PendingNotificationStore::class )->add(
⋮----
public function on_order_status_changed(
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Triggers/NewReviewNotificationTrigger.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Triggers;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Notifications\NewReviewNotification;
use Automattic\WooCommerce\Internal\PushNotifications\Services\PendingNotificationStore;
⋮----
class NewReviewNotificationTrigger {
⋮----
public function register(): void {
⋮----
public function on_comment_post( int $comment_id, $comment_approved, array $commentdata ): void {
⋮----
wc_get_container()->get( PendingNotificationStore::class )->add(
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Triggers/StockNotificationRecoveryHandler.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Triggers;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Notifications\StockNotification;
use Automattic\WooCommerce\Internal\PushNotifications\Services\NotificationProcessor;
use WC_Product;
⋮----
class StockNotificationRecoveryHandler {
⋮----
public function register(): void {
⋮----
public function on_stock_change( WC_Product $product ): void {
$product_id = $product->get_id();
⋮----
$stock_quantity = $product->get_stock_quantity();
⋮----
$this->clear_meta( $product_id, StockNotification::EVENT_LOW_STOCK );
⋮----
$this->clear_meta( $product_id, StockNotification::EVENT_OUT_OF_STOCK );
⋮----
$this->clear_meta( $product_id, StockNotification::EVENT_ON_BACKORDER );
⋮----
private function clear_meta( int $product_id, string $event_type ): void {
( new StockNotification( $product_id, $event_type ) )->delete_meta( NotificationProcessor::SENT_META_KEY );
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Triggers/StockNotificationTrigger.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Triggers;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Notifications\StockNotification;
use Automattic\WooCommerce\Internal\PushNotifications\Services\PendingNotificationStore;
use WC_Product;
⋮----
class StockNotificationTrigger {
⋮----
public function register(): void {
⋮----
public function on_low_stock( WC_Product $product ): void {
$stock = $product->get_stock_quantity();
$this->add_notification(
$product->get_id(),
⋮----
public function on_no_stock( WC_Product $product ): void {
$this->add_notification( $product->get_id(), StockNotification::EVENT_OUT_OF_STOCK );
⋮----
public function on_backorder( array $args ): void {
⋮----
$this->add_notification( $product->get_id(), StockNotification::EVENT_ON_BACKORDER );
⋮----
private function add_notification( int $product_id, string $event_type, ?int $stock_quantity_at_trigger = null ): void {
⋮----
wc_get_container()->get( PendingNotificationStore::class )->add(
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/Validators/PushTokenValidator.php">
namespace Automattic\WooCommerce\Internal\PushNotifications\Validators;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Entities\PushToken;
use WP_Error;
⋮----
class PushTokenValidator {
⋮----
public static function validate( array $data, ?array $fields = array() ) {
⋮----
private static function validate_id( $value, ?array $context = array() ) {
⋮----
private static function validate_user_id( $value, ?array $context = array() ) {
⋮----
private static function validate_origin( $value, ?array $context = array() ) {
⋮----
/**
	 * Validates device UUID.
	 *
	 * @since 10.6.0
	 *
	 * @param mixed      $value The value to validate.
	 * @param array|null $context An array of other values included as context for the validation.
	 * @return bool|WP_Error
	 */
private static function validate_device_uuid( $value, ?array $context = array() ) {
/**
		 * We may or may not have platform; if we don't have it, we can skip the
		 * platform-specific checks and allow the platform validation to trigger
		 * the failure.
		 */
... (34 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/PushNotifications.php">
namespace Automattic\WooCommerce\Internal\PushNotifications;
⋮----
use Automattic\WooCommerce\Internal\PushNotifications\Controllers\NotificationPreferencesRestController;
use Automattic\WooCommerce\Internal\PushNotifications\Controllers\PushNotificationRestController;
use Automattic\WooCommerce\Internal\PushNotifications\Controllers\PushNotificationStatusRestController;
use Automattic\WooCommerce\Internal\PushNotifications\Controllers\PushTokenRestController;
use Automattic\WooCommerce\Internal\PushNotifications\Entities\PushToken;
use Automattic\WooCommerce\Internal\PushNotifications\Services\DriverAvailabilityService;
use Automattic\WooCommerce\Internal\PushNotifications\Services\NotificationProcessor;
use Automattic\WooCommerce\Internal\PushNotifications\Services\NotificationRetryHandler;
use Automattic\WooCommerce\Internal\PushNotifications\Services\PendingNotificationStore;
use Automattic\WooCommerce\Internal\PushNotifications\Triggers\NewOrderNotificationTrigger;
use Automattic\WooCommerce\Internal\PushNotifications\Triggers\NewReviewNotificationTrigger;
use Automattic\WooCommerce\Internal\PushNotifications\Triggers\StockNotificationRecoveryHandler;
use Automattic\WooCommerce\Internal\PushNotifications\Triggers\StockNotificationTrigger;
⋮----
class PushNotifications {
⋮----
private ?bool $enabled = null;
⋮----
public function register(): void {
⋮----
public function on_init(): void {
⋮----
wc_get_container()->get( PushNotificationStatusRestController::class )->register();
⋮----
if ( ! $this->should_be_enabled() ) {
⋮----
$this->register_post_types();
⋮----
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/PushNotifications/ROADMAP.md">
# WooCommerce-driven Push Notification: Roadmap

This document is intended to describe the purpose and planned changes for the WooCommerce: Self-driven Push Notifications project, to assist folks in reviewing related PRs and understanding the wider context of the changes.

The following terms have been used in this post to mean:

- **"WPCOM"**: WordPress.com hosted infrastructure, including the public API, databases, and asynchronous jobs system
- **"Remote WooCommerce Site"**: the blog running WordPress and WooCommerce, which could be self-hosted, a WordPress.com hosted simple site, a WP Cloud hosted site, etc

## Contents

- Goals
- Key Flows
    - Before
    - After
- Data models
    - Push Token
    - Push Notification Preferences
- API Surface
- Steps
    - Add foundations to support the push notification functionality
    - Add token registration/unregistration endpoint
    - Add asynchronous internal send endpoint
    - Add send functionality
    - Add retry functionality
    - Add new booking notification
    - Update notification setting controls
- Notes
    - Failures/retries
    - Users who don't connect Jetpack
... (210 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ReceiptRendering/Templates/order-receipt-css.php">

</file>

<file path="plugins/woocommerce/src/Internal/ReceiptRendering/Templates/order-receipt.php">

</file>

<file path="plugins/woocommerce/src/Internal/ReceiptRendering/ReceiptRenderingEngine.php">
namespace Automattic\WooCommerce\Internal\ReceiptRendering;
⋮----
use Automattic\WooCommerce\Enums\OrderItemType;
use Automattic\WooCommerce\Internal\Orders\PaymentInfo;
use Automattic\WooCommerce\Internal\TransientFiles\TransientFilesEngine;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\ArrayUtil;
use Exception;
use WC_Abstract_Order;
⋮----
class ReceiptRenderingEngine {
⋮----
private $transient_files_engine;
⋮----
private $legacy_proxy;
⋮----
final public function init( TransientFilesEngine $transient_files_engine, LegacyProxy $legacy_proxy ) {
⋮----
public function generate_receipt( $order, $expiration_date = null, bool $force_new = false ): ?string {
⋮----
$existing_receipt_filename = $this->get_existing_receipt( $order );
⋮----
$this->legacy_proxy->call_function(
⋮----
$data = apply_filters( 'woocommerce_printable_order_receipt_data', $this->get_order_data( $order ), $order );
⋮----
$file_name = $this->transient_files_engine->create_transient_file( $rendered_template, $expiration_date );
⋮----
$order->update_meta_data( self::RECEIPT_FILE_NAME_META_KEY, $file_name );
$order->save_meta_data();
... (72 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ReceiptRendering/ReceiptRenderingRestController.php">
namespace Automattic\WooCommerce\Internal\ReceiptRendering;
⋮----
use Automattic\WooCommerce\Internal\TransientFiles\TransientFilesEngine;
use \WP_REST_Server;
use \WP_REST_Request;
use \WP_Error;
use Automattic\WooCommerce\Internal\RestApiControllerBase;
⋮----
class ReceiptRenderingRestController extends RestApiControllerBase {
⋮----
protected function get_rest_api_namespace(): string {
⋮----
public function register_routes() {
⋮----
'callback'            => fn( $request ) => $this->run( $request, 'create_order_receipt' ),
'permission_callback' => fn( $request ) => $this->check_permission( $request, 'read_shop_order', $request->get_param( 'id' ) ),
'args'                => $this->get_args_for_create_order_receipt(),
'schema'              => $this->get_schema_for_get_and_post_order_receipt(),
⋮----
'callback'            => fn( $request ) => $this->run( $request, 'get_order_receipt' ),
⋮----
'args'                => $this->get_args_for_get_order_receipt(),
⋮----
public function get_order_receipt( WP_REST_Request $request ) {
$order_id = $request->get_param( 'id' );
$filename = wc_get_container()->get( ReceiptRenderingEngine::class )->get_existing_receipt( $order_id );
⋮----
$this->get_response_for_file( $filename );
⋮----
public function create_order_receipt( WP_REST_Request $request ) {
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Customers/CollectionQuery.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Customers;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractCollectionQuery;
use WP_REST_Request;
use WP_User_Query;
⋮----
final class CollectionQuery extends AbstractCollectionQuery {
⋮----
public function get_query_schema(): array {
⋮----
public function get_query_args( WP_REST_Request $request ): array {
⋮----
public function get_query_results( array $query_args, WP_REST_Request $request ): array {
⋮----
$data_store             = \WC_Data_Store::load( 'customer' );
$customer_query_results = $data_store->query_customers( $method_args );
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Customers/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Customers;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\StoreApi\Utilities\Pagination;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Customers\CustomerSchema;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Customers\CollectionQuery;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Customers\UpdateUtils;
use WP_Http;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
use WC_Customer;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'customers';
⋮----
protected $item_schema;
⋮----
protected $collection_query;
⋮----
protected $update_utils;
⋮----
final public function init( CustomerSchema $item_schema, CollectionQuery $collection_query, UpdateUtils $update_utils ) {
⋮----
protected function get_schema(): array {
return $this->item_schema->get_item_schema();
⋮----
protected function get_query_schema(): array {
... (109 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Customers/CustomerSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Customers;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use WC_Customer;
use WP_REST_Request;
⋮----
class CustomerSchema extends AbstractSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
public function get_item_response( $item, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
$data = $item->get_data();
⋮----
$last_active = $item->get_meta( 'wc_last_active' );
⋮----
'id'                 => $item->get_id(),
'date_created'       => wc_rest_prepare_date_response( $item->get_date_created(), false ),
'date_created_gmt'   => wc_rest_prepare_date_response( $item->get_date_created() ),
'date_modified'      => wc_rest_prepare_date_response( $item->get_date_modified(), false ),
'date_modified_gmt'  => wc_rest_prepare_date_response( $item->get_date_modified() ),
⋮----
'orders_count'       => $is_field_included( 'orders_count' ) ? $item->get_order_count() : null,
'total_spent'        => $is_field_included( 'total_spent' ) ? $item->get_total_spent() : null,
'avatar_url'         => $is_field_included( 'avatar_url' ) ? $item->get_avatar_url() : null,
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Customers/UpdateUtils.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Customers;
⋮----
use WC_Customer;
use WC_REST_Exception;
use WP_REST_Request;
⋮----
final class UpdateUtils {
⋮----
public function update_customer_from_request( WC_Customer $customer, WP_REST_Request $request, bool $creating = false ): void {
⋮----
$customer->set_email( sanitize_email( $request['email'] ) );
⋮----
$customer->set_password( $request['password'] );
⋮----
$customer->set_first_name( wc_clean( $request['first_name'] ) );
⋮----
$customer->set_last_name( wc_clean( $request['last_name'] ) );
⋮----
$this->update_customer_address( $customer, $request['billing'], 'billing' );
⋮----
$this->update_customer_address( $customer, $request['shipping'], 'shipping' );
⋮----
$customer->save();
⋮----
$user_data = get_userdata( $customer->get_id() );
⋮----
$this->update_additional_fields_for_object( $user_data, $request );
⋮----
$user_data->add_role( 'customer' );
⋮----
... (13 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Fulfillments/Schema/FulfillmentSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Fulfillments\Schema;
⋮----
use Automattic\WooCommerce\Admin\Features\Fulfillments\Fulfillment;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use WP_REST_Request;
⋮----
class FulfillmentSchema extends AbstractSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
public function get_item_response( $fulfillment, WP_REST_Request $request, array $include_fields = array() ): array {
$date_updated = $fulfillment->get_date_updated();
$date_deleted = $fulfillment->get_date_deleted();
⋮----
'id'           => $fulfillment->get_id(),
'entity_type'  => $fulfillment->get_entity_type(),
'entity_id'    => (string) $fulfillment->get_entity_id(),
'status'       => $fulfillment->get_status(),
'is_fulfilled' => $fulfillment->get_is_fulfilled(),
'date_updated' => $this->format_utc_iso8601( $date_updated ),
'date_deleted' => $this->format_utc_iso8601( $date_deleted ),
'meta_data'    => $this->prepare_meta_data_for_response( $fulfillment->get_raw_meta_data() ),
⋮----
private function format_utc_iso8601( ?string $date ): ?string {
⋮----
private function prepare_meta_data_for_response( array $meta_data ): array {
⋮----
$meta['value'] = $this->format_utc_iso8601( $meta['value'] );
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Fulfillments/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Fulfillments;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings\Exceptions\ApiException;
use Automattic\WooCommerce\Admin\Features\Fulfillments\Fulfillment;
use Automattic\WooCommerce\Admin\Features\Fulfillments\OrderFulfillmentsRestController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Fulfillments\Schema\FulfillmentSchema;
use WP_Http;
use WP_Error;
use WC_Order;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'fulfillments';
⋮----
protected $item_schema;
⋮----
protected $order_fulfillments_controller;
⋮----
final public function init( FulfillmentSchema $item_schema, OrderFulfillmentsRestController $order_fulfillments_controller ) {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
... (96 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/OrderNotes/Schema/OrderNoteSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\OrderNotes\Schema;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
use WP_REST_Request;
⋮----
class OrderNoteSchema extends AbstractSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
public function get_item_response( $note, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
$title = OrderNoteGroup::get_default_group_title( $group );
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/OrderNotes/CollectionQuery.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\OrderNotes;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractCollectionQuery;
use WP_REST_Request;
use WC_Order;
⋮----
final class CollectionQuery extends AbstractCollectionQuery {
⋮----
public function get_query_schema(): array {
⋮----
public function get_query_args( WP_REST_Request $request ): array {
⋮----
public function get_query_results( array $query_args, WP_REST_Request $request ): array {
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/OrderNotes/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\OrderNotes;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\OrderNotes\Schema\OrderNoteSchema;
use WP_Http;
use WP_Error;
use WP_Comment;
use WC_Order;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'order-notes';
⋮----
protected $item_schema;
⋮----
protected $query_utils;
⋮----
final public function init( OrderNoteSchema $item_schema, CollectionQuery $query_utils ) {
⋮----
protected function get_schema(): array {
return $this->item_schema->get_item_schema();
⋮----
protected function get_query_schema(): array {
return $this->collection_query->get_query_schema();
⋮----
public function register_routes() {
⋮----
... (80 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/Schema/AbstractLineItemSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Schema;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use WC_Order_Item;
use WP_REST_Request;
⋮----
abstract class AbstractLineItemSchema extends AbstractSchema {
⋮----
protected function get_meta_data_schema(): array {
⋮----
protected function prepare_meta_data( $order_item ) {
$formatted_meta_data = $order_item->get_all_formatted_meta_data( null );
⋮----
protected function get_taxes_schema(): array {
⋮----
protected function prepare_taxes( $order_item, WP_REST_Request $request ) {
$taxes  = $order_item->get_taxes();
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/Schema/OrderCouponSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Schema;
⋮----
use WC_Coupon;
use WC_Order_Item_Coupon;
use WP_REST_Request;
⋮----
class OrderCouponSchema extends AbstractLineItemSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
'meta_data'      => $this->get_meta_data_schema(),
⋮----
public function get_item_response( $order_item, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
$coupon = WC_Coupon::from_order_item( $order_item );
⋮----
'id'             => $order_item->get_id(),
'code'           => $order_item->get_code(),
'discount'       => wc_format_decimal( $order_item->get_discount(), $dp ),
'discount_tax'   => wc_format_decimal( $order_item->get_discount_tax(), $dp ),
'discount_type'  => $coupon->get_discount_type(),
'nominal_amount' => (float) $coupon->get_amount(),
'free_shipping'  => $coupon->get_free_shipping(),
'meta_data'      => $this->prepare_meta_data( $order_item ),
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/Schema/OrderFeeSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Schema;
⋮----
use WC_Order_Item_Fee;
use WP_REST_Request;
⋮----
class OrderFeeSchema extends AbstractLineItemSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
'taxes'           => $this->get_taxes_schema(),
'meta_data'       => $this->get_meta_data_schema(),
⋮----
public function get_item_response( $order_item, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
'id'         => $order_item->get_id(),
'name'       => $order_item->get_name(),
'tax_class'  => $order_item->get_tax_class(),
'tax_status' => $order_item->get_tax_status(),
'total'      => wc_format_decimal( $order_item->get_total(), $dp ),
'total_tax'  => wc_format_decimal( $order_item->get_total_tax(), $dp ),
'taxes'      => $this->prepare_taxes( $order_item, $request ),
'meta_data'  => $this->prepare_meta_data( $order_item ),
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/Schema/OrderItemSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Schema;
⋮----
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
use Automattic\WooCommerce\Utilities\OrderUtil;
use WC_Order_Item_Product;
use WP_REST_Request;
use WC_Product;
⋮----
class OrderItemSchema extends AbstractLineItemSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
'properties'  => $this->get_product_data_schema(),
⋮----
'taxes'           => $this->get_taxes_schema(),
'meta_data'       => $this->get_meta_data_schema(),
⋮----
if ( $this->cogs_is_enabled() ) {
$schema = $this->add_cogs_related_schema( $schema );
⋮----
private function add_cogs_related_schema( array $schema ): array {
⋮----
public function get_item_response( $order_item, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
$quantity_amount = (float) $order_item->get_quantity();
$currency        = $order_item->get_order()->get_currency();
⋮----
'id'              => $order_item->get_id(),
'name'            => $order_item->get_name(),
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/Schema/OrderSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Schema;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use Automattic\WooCommerce\Enums\OrderItemType;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\OrderLineMetaValidator;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Refunds\DataUtils;
use Automattic\WooCommerce\Utilities\NumberUtil;
use Automattic\WooCommerce\Utilities\OrderUtil;
use WC_Order;
use WP_REST_Request;
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
⋮----
class OrderSchema extends AbstractSchema {
⋮----
private $order_item_schema;
⋮----
private $order_coupon_schema;
⋮----
private $order_fee_schema;
⋮----
private $order_tax_schema;
⋮----
private $order_shipping_schema;
⋮----
private $data_utils;
⋮----
final public function init( OrderItemSchema $order_item_schema, OrderCouponSchema $order_coupon_schema, OrderFeeSchema $order_fee_schema, OrderTaxSchema $order_tax_schema, OrderShippingSchema $order_shipping_schema, DataUtils $data_utils ) {
⋮----
... (134 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/Schema/OrderShippingSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Schema;
⋮----
use WC_Order_Item_Shipping;
use WP_REST_Request;
⋮----
class OrderShippingSchema extends AbstractLineItemSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
'taxes'           => $this->get_taxes_schema(),
'meta_data'       => $this->get_meta_data_schema(),
⋮----
public function get_item_response( $order_item, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
'id'           => $order_item->get_id(),
'method_title' => $order_item->get_method_title(),
'method_id'    => $order_item->get_method_id(),
'instance_id'  => $order_item->get_instance_id(),
'total'        => wc_format_decimal( $order_item->get_total(), $dp ),
'total_tax'    => wc_format_decimal( $order_item->get_total_tax(), $dp ),
'taxes'        => $this->prepare_taxes( $order_item, $request ),
'meta_data'    => $this->prepare_meta_data( $order_item ),
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/Schema/OrderTaxSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Schema;
⋮----
use WC_Order_Item_Tax;
use WP_REST_Request;
⋮----
class OrderTaxSchema extends AbstractLineItemSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
'meta_data'          => $this->get_meta_data_schema(),
⋮----
public function get_item_response( $order_item, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
'id'                 => $order_item->get_id(),
'rate_code'          => $order_item->get_rate_code(),
'rate_id'            => $order_item->get_rate_id(),
'label'              => $order_item->get_label(),
'compound'           => $order_item->get_compound(),
'tax_total'          => wc_format_decimal( $order_item->get_tax_total(), $dp ),
'shipping_tax_total' => wc_format_decimal( $order_item->get_shipping_tax_total(), $dp ),
'meta_data'          => $this->prepare_meta_data( $order_item ),
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/ActionController.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders;
⋮----
use WC_REST_Exception;
use WP_REST_Request;
use WP_Error;
use WC_Order;
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
⋮----
class ActionController {
⋮----
public function get_endpoint_args_for_actions(): array {
⋮----
public function run_actions( WC_Order $order, WP_REST_Request $request ) {
$valid_actions = array_keys( $this->get_endpoint_args_for_actions() );
⋮----
$param    = $request->get_param( $action );
⋮----
throw new WC_REST_Exception( 'woocommerce_rest_invalid_action', esc_html( $result->get_error_message() ) );
⋮----
private function action_reset_download_permissions( $action_value, WC_Order $order, WP_REST_Request $request ) {
⋮----
$data_store = \WC_Data_Store::load( 'customer-download' );
⋮----
$data_store->delete_by_order_id( $order->get_id() );
⋮----
wc_downloadable_product_permissions( $order->get_id(), true );
⋮----
$user_agent = esc_html( $request->get_header( 'User-Agent' ) );
$order->add_order_note(
⋮----
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/CollectionQuery.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders;
⋮----
use WP_REST_Request;
use WP_Http;
use WP_Error;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractCollectionQuery;
use Automattic\WooCommerce\Enums\OrderItemType;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Utilities\OrderUtil;
use WC_Order_Query;
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
⋮----
class CollectionQuery extends AbstractCollectionQuery {
⋮----
public function get_query_schema(): array {
⋮----
$total_field = wp_parse_list( $request->get_param( 'total' ) );
⋮----
'enum' => array_keys( FulfillmentUtils::get_order_fulfillment_statuses() ),
⋮----
public function get_query_args( WP_REST_Request $request ): array {
⋮----
$order_ids      = $wpdb->get_col(
$wpdb->prepare(
⋮----
if ( ! OrderUtil::custom_orders_table_usage_is_enabled() && ! empty( $args['s'] ) ) {
⋮----
if ( FulfillmentUtils::is_valid_order_fulfillment_status( $status ) ) {
⋮----
public function get_query_results( array $query_args, WP_REST_Request $request ): array {
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\StoreApi\Utilities\Pagination;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Schema\OrderSchema;
use WP_Http;
use WP_Error;
use WC_Order;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'orders';
⋮----
protected $post_type = 'shop_order';
⋮----
protected $item_schema;
⋮----
protected $query_utils;
⋮----
protected $update_utils;
⋮----
protected $action_controller;
⋮----
final public function init( OrderSchema $item_schema, CollectionQuery $query_utils, UpdateUtils $update_utils, ActionController $action_controller ) {
⋮----
protected function get_schema(): array {
return $this->item_schema->get_item_schema();
... (135 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/OrderLineMetaValidator.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders;
⋮----
use Automattic\WooCommerce\Utilities\MetaDataUtil;
use WC_REST_Exception;
use WP_Error;
use WP_REST_Request;
⋮----
class OrderLineMetaValidator {
⋮----
public static function validate_request_arg( $value, $request, $param ) {
⋮----
if ( is_array( $line ) && self::has_serialized_meta_value( $line['meta_data'] ?? null ) ) {
⋮----
self::get_serialized_meta_value_error_message(),
⋮----
public static function assert_no_serialized_meta_value( array $meta_data ): void {
if ( self::has_serialized_meta_value( $meta_data ) ) {
throw new WC_REST_Exception( 'woocommerce_rest_invalid_order_item_meta_key', esc_html( self::get_serialized_meta_value_error_message() ), 400 );
⋮----
private static function has_serialized_meta_value( $meta_data ): bool {
⋮----
foreach ( MetaDataUtil::normalize( $meta_data ) as $meta ) {
⋮----
private static function get_serialized_meta_value_error_message(): string {
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Orders/UpdateUtils.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders;
⋮----
use Automattic\WooCommerce\Internal\Orders\OrderNoteGroup;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Schema\OrderSchema;
use Automattic\WooCommerce\Enums\OrderItemType;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
use Automattic\WooCommerce\Utilities\ArrayUtil;
use Automattic\WooCommerce\Utilities\MetaDataUtil;
use Automattic\WooCommerce\Utilities\StringUtil;
use Automattic\WooCommerce\Internal\Utilities\Users;
use WC_REST_Exception;
use WC_Order;
use WP_REST_Request;
use WP_Http;
use WC_Order_Item_Product;
use WC_Order_Item_Shipping;
use WC_Order_Item_Fee;
use WC_Order_Item_Coupon;
⋮----
class UpdateUtils {
⋮----
private $order_schema;
⋮----
final public function init( OrderSchema $order_schema ) {
⋮----
public function update_order_from_request( WC_Order $order, WP_REST_Request $request ) {
⋮----
$data_keys   = array_diff( array_keys( $this->order_schema->get_writable_item_schema_properties() ), $ignore_keys );
⋮----
... (120 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Products/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Products;
⋮----
use Automattic\WooCommerce\Enums\CatalogVisibility;
use Automattic\WooCommerce\Enums\DimensionUnit;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductTaxStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\WeightUnit;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareRestControllerTrait;
use Automattic\WooCommerce\Internal\RestApi\ProductRequestPreparationTrait;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use Automattic\WooCommerce\Utilities\I18nUtil;
use Automattic\WooCommerce\Utilities\MetaDataUtil;
use WC_REST_Products_V2_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use WC_Admin_Duplicate_Product;
use WC_REST_CRUD_Controller;
use WC_Data_Store;
use WC_Product_Attribute;
use WC_REST_Exception;
⋮----
class Controller extends WC_REST_Products_V2_Controller {
⋮----
protected $namespace = 'wc/v4';
⋮----
private $search_sku_arg_value = '';
... (387 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Products/README.md">
# WooCommerce REST API v4 - Products Endpoint

This directory contains the implementation of the WooCommerce REST API v4 Products endpoint (`/wp-json/wc/v4/products`).

## Overview

The v4 Products endpoint starts as a **copy-paste of the v3 implementation** and will be incrementally enhanced with new features. This approach allows for rapid development while maintaining backward compatibility (for now) and enables easy tracking of changes through dedicated PRs.

**Current Status**: Experimental feature requiring the `rest-api-v4` feature flag.

## Architecture

- **Namespace**: `wc/v4`
- **Future Goal**: Migrate to extend WP_REST_Controller directly instead of WooCommerce base classes, and move the API codebase under the src directory with the Automattic\WooCommerce namespace.

## Development Philosophy

As discussed in the team conversation:

- **Copy-paste first**: Start with exact v3 functionality 
- **Separate PRs for changes**: Each enhancement gets its own PR for easy tracking and review
- **Incremental improvements**: Add new fields and functionality gradually
- **Future breaking changes expected**: As v4 evolves, breaking changes may be introduced for improved functionality

## Change Log

### 2026-05-19 - Support multiple stock status filters

**Summary**: Updated the collection `stock_status` query parameter to accept an array of stock statuses, enabling clients to request products matching any selected stock status. The endpoint now validates each value against WooCommerce stock status options, sanitizes the parameter with `wp_parse_list`, and applies the filter with an `_stock_status IN (...)` meta query. Single stock status values remain supported through list parsing.

... (76 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Refunds/Schema/RefundPreviewSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Refunds\Schema;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use WP_REST_Request;
⋮----
class RefundPreviewSchema extends AbstractSchema {
⋮----
public function get_item_response( $item, WP_REST_Request $request, array $include_fields = array() ): array {
throw new \LogicException(
⋮----
public function get_item_schema_properties(): array {
⋮----
'products' => $this->get_section_schema( 'products' ),
'shipping' => $this->get_section_schema( 'shipping' ),
'fees'     => $this->get_section_schema( 'fees' ),
⋮----
private function get_section_schema( string $section_key ): array {
⋮----
'items'       => 'products' === $section_key ? $this->get_product_item_schema() : $this->get_base_item_schema(),
⋮----
private function get_base_item_schema(): array {
⋮----
private function get_product_item_schema(): array {
$schema                             = $this->get_base_item_schema();
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Refunds/Schema/RefundSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Refunds\Schema;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use Automattic\WooCommerce\Enums\OrderItemType;
use Automattic\WooCommerce\Internal\CostOfGoodsSold\CogsAwareTrait;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Schema\OrderItemSchema;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Schema\OrderFeeSchema;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Schema\OrderTaxSchema;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders\Schema\OrderShippingSchema;
use WC_Order_Refund;
use WP_REST_Request;
⋮----
class RefundSchema extends AbstractSchema {
⋮----
private $order_item_schema;
⋮----
private $order_fee_schema;
⋮----
private $order_tax_schema;
⋮----
private $order_shipping_schema;
⋮----
final public function init( OrderItemSchema $order_item_schema, OrderFeeSchema $order_fee_schema, OrderTaxSchema $order_tax_schema, OrderShippingSchema $order_shipping_schema ) {
⋮----
public function get_item_schema_properties(): array {
⋮----
if ( $this->cogs_is_enabled() ) {
$schema = $this->add_cogs_related_schema( $schema );
⋮----
... (44 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Refunds/CollectionQuery.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Refunds;
⋮----
use WP_REST_Request;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractCollectionQuery;
use WC_Order_Query;
⋮----
class CollectionQuery extends AbstractCollectionQuery {
⋮----
public function get_query_schema(): array {
⋮----
public function get_query_args( WP_REST_Request $request ): array {
⋮----
public function get_query_results( array $query_args, WP_REST_Request $request ): array {
⋮----
$results = $query->get_orders();
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Refunds/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Refunds;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\StoreApi\Utilities\Pagination;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Refunds\Schema\RefundPreviewSchema;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Refunds\Schema\RefundSchema;
use Automattic\WooCommerce\Utilities\MetaDataUtil;
use WP_Http;
use WP_Error;
use WC_Order;
use WC_Order_Refund;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'refunds';
⋮----
protected $post_type = 'shop_order_refund';
⋮----
protected $item_schema;
⋮----
protected $preview_schema;
⋮----
protected $collection_query;
⋮----
protected $data_utils;
⋮----
final public function init( RefundSchema $item_schema, RefundPreviewSchema $preview_schema, CollectionQuery $collection_query, DataUtils $data_utils ) {
... (120 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Refunds/DataUtils.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Refunds;
⋮----
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Utilities\NumberUtil;
use WC_Order;
use WC_Order_Item_Fee;
use WC_Order_Item_Product;
use WC_Order_Item_Shipping;
use WP_Error;
use WP_Http;
⋮----
class DataUtils {
⋮----
public function convert_line_items_to_internal_format( $line_items, WC_Order $order ) {
⋮----
$original_item = $order->get_item( $line_item['line_item_id'] );
⋮----
$split = $this->split_inclusive_by_stored_ratio( (float) $line_item['refund_total'], $original_item, wc_get_price_decimals() );
⋮----
$line_item['refund_tax']   = $this->convert_proportional_taxes_to_schema_format( $split['taxes'] );
⋮----
'refund_tax'   => $this->convert_line_item_taxes_to_internal_format( $line_item['refund_tax'] ?? array() ),
⋮----
protected function convert_line_item_taxes_to_internal_format( $line_item_taxes ) {
⋮----
public function calculate_refund_amount( array $line_items ): ?float {
⋮----
return (float) NumberUtil::round( $amount, wc_get_price_decimals() );
⋮----
public function validate_line_items( $line_items, WC_Order $order ) {
... (172 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Account/Schema/AccountSettingsSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Account\Schema;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use WP_REST_Request;
⋮----
class AccountSettingsSchema extends AbstractSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
'items'       => $this->get_field_schema(),
⋮----
private function get_field_schema(): array {
⋮----
public function get_item_response( $item, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
// Handle section titles - start of a new group.
⋮----
$field = $this->transform_setting_to_field( $setting );
⋮----
$values[ $field['id'] ] = $this->validate_field_value( $raw_value, $field['type'] );
⋮----
private function transform_setting_to_field( array $setting ): ?array {
⋮----
'type'  => $this->normalize_field_type( $setting_type ),
⋮----
// Add options for select fields.
⋮----
$field['options'] = $this->get_field_options( $setting_id );
⋮----
private function get_field_options( string $field_id ): array {
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Account/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Account;
⋮----
use WP_Error;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Account\Schema\AccountSettingsSchema;
use WC_Settings_Accounts;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'settings/account';
⋮----
protected $settings_account_instance;
⋮----
protected $schema;
⋮----
final public function init( AccountSettingsSchema $schema ) {
⋮----
private function get_settings_account_instance() {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_item_permissions_check( $request ) {
⋮----
public function update_item_permissions_check( $request ) {
⋮----
... (37 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Email/Schema/EmailSettingsSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Email\Schema;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use WP_REST_Request;
⋮----
class EmailSettingsSchema extends AbstractSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
'items'       => $this->get_field_schema(),
⋮----
private function get_field_schema(): array {
⋮----
public function get_item_response( $item, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
// Handle section titles and email_color_palette - start of a new group.
⋮----
$api_type = $this->map_setting_type_to_api_type( $setting_type );
⋮----
// Convert checkbox values to boolean for API.
⋮----
private function map_setting_type_to_api_type( string $setting_type ): string {
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Email/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Email;
⋮----
use WP_Error;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Email\Schema\EmailSettingsSchema;
use WC_Settings_Emails;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'settings/email';
⋮----
protected $settings_emails_instance;
⋮----
protected $schema;
⋮----
final public function init( EmailSettingsSchema $schema ) {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
private function get_settings_emails_instance() {
⋮----
private function get_all_settings(): array {
$settings_instance = $this->get_settings_emails_instance();
$sections          = $settings_instance->get_sections();
⋮----
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Schema/EmailsSettingsSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Emails\Schema;
⋮----
use Automattic\WooCommerce\EmailEditor\Email_Editor_Container;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use Automattic\WooCommerce\Internal\EmailEditor\WCTransactionalEmails\WCTransactionalEmailPostsManager;
use Automattic\WooCommerce\EmailEditor\Engine\PersonalizationTags\Personalization_Tags_Registry;
use WC_Email;
use WP_Error;
use WP_REST_Request;
⋮----
class EmailsSettingsSchema extends AbstractSchema {
⋮----
private $personalization_tags_registry;
⋮----
private $cached_prefixes = null;
⋮----
final public function init() {
$this->personalization_tags_registry = Email_Editor_Container::container()->get( Personalization_Tags_Registry::class );
⋮----
public function get_item_schema_properties(): array {
⋮----
'items'       => $this->get_field_schema(),
⋮----
private function get_field_schema(): array {
⋮----
public function get_item_response( $email, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
$email_post_manager = WCTransactionalEmailPostsManager::get_instance();
$post_id            = $email_post_manager->get_email_template_post_id( $email->id ?? '' );
// Convert false to null, ensure int otherwise.
... (79 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Emails/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Emails;
⋮----
use WP_Error;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Emails\Schema\EmailsSettingsSchema;
use WC_Emails;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'settings/emails';
⋮----
protected $schema;
⋮----
final public function init( EmailsSettingsSchema $schema ) {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_item_permissions_check( $request ) {
return $this->get_items_permissions_check( $request );
⋮----
public function update_item_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
... (43 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/General/Schema/GeneralSettingsSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\General\Schema;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use WP_REST_Request;
⋮----
class GeneralSettingsSchema extends AbstractSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
'items'       => $this->get_field_schema(),
⋮----
private function get_field_schema(): array {
⋮----
public function get_item_response( $item, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
// Handle section titles - start of a new group.
⋮----
$field = $this->transform_setting_to_field( $setting );
⋮----
$values[ $field['id'] ] = $this->validate_field_value( $raw_value, $field['type'] );
⋮----
private function transform_setting_to_field( array $setting ): ?array {
⋮----
'type'  => $this->normalize_field_type( $setting_type ),
⋮----
// Add options for select fields.
⋮----
$field['options'] = $this->get_field_options( $setting_id );
⋮----
private function get_field_options( string $field_id ): array {
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/General/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\General;
⋮----
use WP_Error;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\General\Schema\GeneralSettingsSchema;
use WC_Settings_General;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'settings/general';
⋮----
protected $settings_general_instance;
⋮----
protected $schema;
⋮----
final public function init( GeneralSettingsSchema $schema ) {
⋮----
private function get_settings_general_instance() {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_item_permissions_check( $request ) {
⋮----
public function update_item_permissions_check( $request ) {
⋮----
... (49 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/OfflinePaymentMethods/Schema/OfflinePaymentMethodSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\OfflinePaymentMethods\Schema;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use WP_REST_Request;
⋮----
class OfflinePaymentMethodSchema extends AbstractSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
public function get_item_response( $item, WP_REST_Request $request, array $include_fields = array() ): array {
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/OfflinePaymentMethods/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\OfflinePaymentMethods;
⋮----
use Automattic\WooCommerce\Internal\Admin\Settings\Payments;
use Automattic\WooCommerce\Internal\Admin\Settings\PaymentsProviders;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\OfflinePaymentMethods\Schema\OfflinePaymentMethodSchema;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'settings/payments/offline-methods';
⋮----
protected $payments;
⋮----
protected $item_schema;
⋮----
final public function init( Payments $payments, OfflinePaymentMethodSchema $schema ) {
⋮----
public function register_routes() {
⋮----
$this->get_collection_params(),
⋮----
public function get_items_permissions_check( $request ) {
⋮----
public function get_items( $request ) {
⋮----
$offline_methods = $this->get_offline_payment_methods_data( $request );
... (24 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/PaymentGateways/Schema/AbstractPaymentGatewaySettingsSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\PaymentGateways\Schema;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use WC_Payment_Gateway;
use WP_Error;
use WP_REST_Request;
⋮----
abstract class AbstractPaymentGatewaySettingsSchema extends AbstractSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
'items'       => $this->get_field_schema(),
⋮----
private function get_field_schema(): array {
⋮----
private function get_values( WC_Payment_Gateway $gateway ): array {
⋮----
$gateway->init_form_fields();
⋮----
// Skip non-data fields.
⋮----
// Add special fields for this gateway.
$special_fields = $this->get_special_field_values( $gateway );
⋮----
/**
	 * Get values for gateway-specific special fields.
	 *
	 * Override this method in gateway-specific schema classes to provide special field values.
	 *
	 * @param WC_Payment_Gateway $gateway Gateway instance.
... (93 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/PaymentGateways/Schema/BacsGatewaySettingsSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\PaymentGateways\Schema;
⋮----
use WC_Payment_Gateway;
use WP_Error;
⋮----
class BacsGatewaySettingsSchema extends AbstractPaymentGatewaySettingsSchema {
⋮----
protected function get_custom_groups_for_gateway( WC_Payment_Gateway $gateway ): array {
⋮----
$fields = $this->build_fields_from_form_fields( $gateway, $core_field_overrides, array( 'account_details' ) );
⋮----
protected function get_special_field_values( WC_Payment_Gateway $gateway ): array {
⋮----
public function is_special_field( string $field_id ): bool {
⋮----
public function validate_and_sanitize_special_fields( WC_Payment_Gateway $gateway, array $values ) {
⋮----
$validated[ $field_id ] = $this->validate_bacs_accounts( $value );
⋮----
public function update_special_fields( WC_Payment_Gateway $gateway, array $values ): void {
⋮----
private function validate_bacs_accounts( $value ) {
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/PaymentGateways/Schema/ChequeGatewaySettingsSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\PaymentGateways\Schema;
⋮----
use WC_Payment_Gateway;
⋮----
class ChequeGatewaySettingsSchema extends AbstractPaymentGatewaySettingsSchema {
⋮----
protected function get_custom_groups_for_gateway( WC_Payment_Gateway $gateway ): array {
⋮----
$fields = $this->build_fields_from_form_fields( $gateway, $core_field_overrides );
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/PaymentGateways/Schema/CodGatewaySettingsSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\PaymentGateways\Schema;
⋮----
use WC_Data_Store;
use WC_Payment_Gateway;
use WC_Shipping_Zone;
⋮----
class CodGatewaySettingsSchema extends AbstractPaymentGatewaySettingsSchema {
⋮----
private ?array $shipping_method_options = null;
⋮----
protected function get_custom_groups_for_gateway( WC_Payment_Gateway $gateway ): array {
⋮----
'options' => $this->load_shipping_method_options(),
⋮----
$fields = $this->build_fields_from_form_fields( $gateway, $core_field_overrides );
⋮----
private function load_shipping_method_options(): array {
⋮----
$data_store = WC_Data_Store::load( 'shipping-zone' );
$raw_zones  = $data_store->get_zones();
⋮----
foreach ( WC()->shipping()->load_shipping_methods() as $method ) {
⋮----
$options[ $method->get_method_title() ] = array();
⋮----
$options[ $method->get_method_title() ][ $method->id ] = sprintf( __( 'Any &quot;%1$s&quot; method', 'woocommerce' ), $method->get_method_title() );
⋮----
$shipping_method_instances = $zone->get_shipping_methods();
⋮----
$option_id = $shipping_method_instance->get_rate_id();
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/PaymentGateways/Schema/PaymentGatewaySettingsSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\PaymentGateways\Schema;
⋮----
class PaymentGatewaySettingsSchema extends AbstractPaymentGatewaySettingsSchema {
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/PaymentGateways/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\PaymentGateways;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\PaymentGateways\Schema\AbstractPaymentGatewaySettingsSchema;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\PaymentGateways\Schema\BacsGatewaySettingsSchema;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\PaymentGateways\Schema\ChequeGatewaySettingsSchema;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\PaymentGateways\Schema\CodGatewaySettingsSchema;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\PaymentGateways\Schema\PaymentGatewaySettingsSchema;
use WC_Payment_Gateway;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'settings/payment-gateways';
⋮----
protected string $post_type = 'payment_gateways';
⋮----
protected function get_schema(): array {
⋮----
return $schema->get_item_schema();
⋮----
public function register_routes() {
⋮----
public function get_item( $request ) {
⋮----
$payment_gateways = WC()->payment_gateways->payment_gateways();
⋮----
... (38 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/PaymentGateways/README.md">
# Payment Gateways Settings API

REST API endpoint for managing payment gateway settings in WooCommerce.

## Endpoint

```http
GET  /wc/v4/settings/payment-gateways/{gateway_id}
PUT  /wc/v4/settings/payment-gateways/{gateway_id}
```

## Response Structure

### GET Response

When retrieving a payment gateway's settings, the response includes:

```json
{
  "id": "bacs",
  "title": "Direct bank transfer",
  "description": "Make your payment directly into our bank account.",
  "order": 1,
  "enabled": false,
  "method_title": "BACS",
  "method_description": "Allows payments by BACS...",
  "method_supports": ["products"],
  "values": {
    "enabled": "no",
    "title": "Direct bank transfer",
... (385 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Products/Schema/ProductSettingsSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Products\Schema;
⋮----
use Automattic\WooCommerce\Enums\WeightUnit;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use WP_REST_Request;
⋮----
class ProductSettingsSchema extends AbstractSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
'items'       => $this->get_field_schema(),
⋮----
private function get_field_schema(): array {
⋮----
public function get_item_response( $item, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
// Handle section titles - start of a new group.
⋮----
$field = $this->transform_setting_to_field( $setting );
⋮----
$values[ $field['id'] ] = $this->validate_field_value( $raw_value, $field['type'] );
⋮----
private function transform_setting_to_field( array $setting ): ?array {
⋮----
'type'  => $this->normalize_field_type( $setting_type ),
⋮----
// Add options for select fields.
⋮----
$field['options'] = $this->get_field_options( $setting_id );
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Products/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Products;
⋮----
use WP_Error;
use Automattic\WooCommerce\Enums\DimensionUnit;
use Automattic\WooCommerce\Enums\WeightUnit;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Products\Schema\ProductSettingsSchema;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WC_Settings_Products;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'settings/products';
⋮----
protected $schema;
⋮----
protected $settings_products_instance;
⋮----
final public function init( ProductSettingsSchema $schema ) {
⋮----
private function get_settings_products_instance() {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_item_permissions_check( $request ) {
⋮----
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Tax/Schema/TaxSettingsSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Tax\Schema;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use WP_REST_Request;
⋮----
class TaxSettingsSchema extends AbstractSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
'items'       => $this->get_field_schema(),
⋮----
private function get_field_schema(): array {
⋮----
public function get_item_response( $item, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
// Handle section titles - start of a new group.
⋮----
$field = $this->transform_setting_to_field( $setting );
⋮----
$values[ $field['id'] ] = $this->validate_field_value( $raw_value, $field['type'] );
⋮----
private function transform_setting_to_field( array $setting ): ?array {
⋮----
'type'  => $this->normalize_field_type( $setting_type ),
⋮----
// Add options for select/radio fields.
⋮----
private function normalize_field_type( string $wc_type ): string {
⋮----
private function validate_field_value( $value, string $type ) {
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/Tax/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Tax;
⋮----
use WP_Error;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\Settings\Tax\Schema\TaxSettingsSchema;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WC_Settings_Tax;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'settings/tax';
⋮----
protected $settings_tax_instance;
⋮----
protected $item_schema;
⋮----
final public function init( TaxSettingsSchema $item_schema ) {
⋮----
private function get_settings_tax_instance() {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
public function get_item_permissions_check( $request ) {
⋮----
return $this->get_authentication_error_by_method( $request->get_method() );
⋮----
... (32 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/Settings/README.md">
# WooCommerce Settings REST API - v4

> This is an internal API only. Do not use it in production.

The WooCommerce Settings REST API provides a consistent interface for managing various WooCommerce settings. All settings endpoints share a common response schema that organizes settings into logical groups with standardized field types.

## Response Schema

Each settings endpoint returns data in the following structure:

```json
{
  "id": "string",          // Unique identifier for the settings group
  "title": "string",       // Settings title
  "description": "string", // Settings description
  "values": {             // Flat key-value mapping of all setting field values
    "field_id": "value"   // Values can be string, number, array, boolean...
  },
  "groups": {             // Collection of setting groups
    "group_id": {
      "title": "string",       // Group title
      "description": "string", // Group description
      "order": 0,             // Display order for the group
      "fields": [             // Array of setting fields
        {
          "id": "string",     // Setting field ID
          "label": "string",  // Setting field label
          "type": "string",   // Field type (text, number, select, multiselect, checkbox)
          "options": {},      // Available options for select/multiselect fields
          "desc": "string"    // Field description
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/ShippingZoneMethod/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\ShippingZoneMethod;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\ShippingZoneMethod\ShippingZoneMethodService;
use WC_Shipping_Zones;
use WC_Shipping_Zone;
use WP_Http;
use WP_REST_Request;
use WP_REST_Server;
use WP_Error;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'shipping-zone-method';
⋮----
protected $method_schema;
⋮----
protected $shipping_method_service;
⋮----
final public function init( ShippingMethodSchema $method_schema, ShippingZoneMethodService $shipping_method_service ) {
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::DELETABLE ),
⋮----
public function check_permissions( $request ) {
... (69 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/ShippingZoneMethod/ShippingMethodSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\ShippingZoneMethod;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use WP_REST_Request;
⋮----
class ShippingMethodSchema extends AbstractSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
public function get_item_response( $method, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
$data_store = \WC_Data_Store::load( 'shipping-zone' );
$zone_id    = $data_store->get_zone_id_by_instance_id( $method->instance_id );
⋮----
'settings'    => $this->get_method_settings( $method ),
⋮----
protected function get_method_settings( $method ): array {
⋮----
$settings['title'] = $method->get_title();
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/ShippingZoneMethod/ShippingZoneMethodService.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\ShippingZoneMethod;
⋮----
use WP_Error;
use WC_Cache_Helper;
use WC_Shipping_Method;
⋮----
class ShippingZoneMethodService {
⋮----
public function update_shipping_method_settings( $method, $settings ) {
⋮----
return new \WP_Error(
⋮----
$method->init_instance_settings();
⋮----
$field_key               = $method->get_field_key( $key );
⋮----
$form_fields = $method->get_instance_form_fields();
⋮----
$instance_settings[ $key ] = $method->get_field_value( $key, $form_fields[ $key ], $post_data );
⋮----
$e->getMessage(),
⋮----
$result            = update_option( $method->get_instance_option_key(), $filtered_settings );
⋮----
public function update_shipping_zone_method( $method, $instance_id, $data, $zone_id = null ) {
⋮----
$result = $this->update_shipping_method_settings( $method, $data['settings'] );
⋮----
$result = $wpdb->update(
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/ShippingZones/Controller.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\ShippingZones;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractController;
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\ShippingZones\ShippingZoneService;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use WP_Http;
use WC_Shipping_Zone;
use WC_Shipping_Zones;
⋮----
class Controller extends AbstractController {
⋮----
protected $rest_base = 'shipping-zones';
⋮----
protected $item_schema;
⋮----
protected $shipping_zone_service;
⋮----
final public function init( ShippingZoneSchema $zone_schema, ShippingZoneService $shipping_zone_service ) {
⋮----
protected function get_schema(): array {
return $this->item_schema->get_item_schema();
⋮----
public function register_routes() {
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
⋮----
'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
... (64 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/ShippingZones/ShippingZoneSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\ShippingZones;
⋮----
use Automattic\WooCommerce\Internal\RestApi\Routes\V4\AbstractSchema;
use WC_Shipping_Zone;
use WP_REST_Request;
⋮----
class ShippingZoneSchema extends AbstractSchema {
⋮----
public function get_item_schema_properties(): array {
⋮----
public function get_item_response( $zone, WP_REST_Request $request, array $include_fields = array() ): array {
⋮----
'id'        => $zone->get_id(),
'name'      => $zone->get_zone_name(),
'order'     => $zone->get_zone_order(),
'locations' => $this->get_formatted_zone_locations( $zone ),
'methods'   => $this->get_formatted_zone_methods( $zone ),
⋮----
protected function get_formatted_zone_locations( WC_Shipping_Zone $zone ): array {
if ( 0 === $zone->get_id() ) {
⋮----
$locations           = $zone->get_zone_locations();
⋮----
'name' => $this->get_location_name( $location ),
⋮----
protected function get_formatted_zone_methods( $zone ) {
$methods           = $zone->get_shipping_methods( false, 'json' );
⋮----
'settings'    => $this->get_method_settings( $method ),
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/ShippingZones/ShippingZoneService.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4\ShippingZones;
⋮----
use WC_Shipping_Zones;
use WC_Shipping_Zone;
use WP_Error;
use WP_Http;
⋮----
class ShippingZoneService {
⋮----
public function get_sorted_shipping_zones() {
$zones             = WC_Shipping_Zones::get_zones();
$rest_of_the_world = WC_Shipping_Zones::get_zone_by( 'zone_id', 0 );
⋮----
$rest_data                            = $rest_of_the_world->get_data();
$rest_data['zone_id']                 = $rest_of_the_world->get_id();
⋮----
$rest_data['shipping_methods']        = $rest_of_the_world->get_shipping_methods( false, 'admin' );
⋮----
public function create_shipping_zone( $params ) {
⋮----
$result = $this->update_shipping_zone( $zone, $params );
⋮----
public function update_shipping_zone( $zone, $params ) {
⋮----
$is_rest_of_world = 0 === $zone->get_id();
⋮----
$zone->set_zone_name( $name );
⋮----
$zone->set_zone_order( $params['order'] );
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/AbstractCollectionQuery.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4;
⋮----
use WP_REST_Request;
use WC_Order;
⋮----
abstract class AbstractCollectionQuery {
⋮----
abstract public function get_query_schema(): array;
⋮----
abstract public function get_query_args( WP_REST_Request $request ): array;
⋮----
abstract public function get_query_results( array $query_args, WP_REST_Request $request ): array;
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/AbstractController.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4;
⋮----
use WP_Error;
use WP_Http;
use WP_REST_Controller;
use WP_REST_Response;
use WP_REST_Request;
⋮----
abstract class AbstractController extends WP_REST_Controller {
⋮----
protected $namespace = 'wc/v4';
⋮----
protected $rest_base = '';
⋮----
/**
	 * Cache for the item schema populated after calling get_item_schema().
	 *
	 * @var array
	 */
protected $schema;
⋮----
/**
	 * Get the schema for the current resource. This use consumed by the AbstractController to generate the item schema
	 * after running various hooks on the response.
	 *
	 * This should return the full schema object, not just the properties.
	 *
	 * @return array The full item schema.
	 */
abstract protected function get_schema(): array;
... (71 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/V4/AbstractSchema.php">
namespace Automattic\WooCommerce\Internal\RestApi\Routes\V4;
⋮----
use WP_REST_Request;
⋮----
abstract class AbstractSchema {
⋮----
/**
	 * Context for the item schema - view, edit, and embed.
	 *
	 * @var array
	 * @since 10.2.0
	 */
⋮----
public function get_item_schema(): array {
⋮----
'properties' => $this->get_item_schema_properties(),
⋮----
abstract public function get_item_response( $item, WP_REST_Request $request, array $include_fields = array() ): array;
⋮----
public function get_item_schema_properties(): array {
⋮----
public function get_writable_item_schema_properties(): array {
return array_filter( $this->get_item_schema_properties(), array( $this, 'filter_writable_props' ) );
⋮----
protected function filter_writable_props( array $schema ): bool {
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/Routes/README.md">
# REST API Route Controllers

This directory contains route controllers and schemas for WooCommerce REST API endpoints, organized by major version.

## Version Structure

Each major version of the REST API has its own directory:

- `V4/` - REST API v4 controllers and schemas
- `V5/` - REST API v5 controllers and schemas (future)
- `V6/` - REST API v6 controllers and schemas (future)

## Legacy API Versions

Previous versions of the REST API (v1, v2, v3) can be found in the legacy includes directory:

```markdown
plugins/woocommerce/includes/rest-api/
```

These legacy controllers are maintained for backwards compatibility and should not be modified for new features.

## V4 Controllers and Schemas

Route controllers and schemas for the WooCommerce REST API V4 endpoints are placed in the `V4/` directory.

### Directory Structure

Each route should have its own directory containing both controller and schema files:

... (59 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/ProductRequestPreparationTrait.php">
namespace Automattic\WooCommerce\Internal\RestApi;
⋮----
use Automattic\WooCommerce\Enums\ProductType;
⋮----
trait ProductRequestPreparationTrait {
⋮----
private function get_product_for_rest_request( $request ) {
⋮----
return new \WP_Error(
⋮----
$existing_product_type = isset( $request['type'] ) && $id ? \WC_Product_Factory::get_product_type( $id ) : false;
⋮----
return $this->get_invalid_product_id_error( true );
⋮----
$classname = \WC_Product_Factory::get_classname_from_product_type( (string) $request['type'] );
⋮----
? \WC_Product_Factory::get_product_classname( $id, $existing_product_type )
⋮----
$product = new $classname( $id );
⋮----
&& ( new \ReflectionClass( \WC_Product_Data_Store_CPT::class ) )->getFileName() === $e->getFile();
⋮----
return $this->get_invalid_product_id_error( 'product_variation' === $target_post_type );
⋮----
$product = new \WC_Product_Simple();
⋮----
return $this->get_invalid_product_id_error();
⋮----
return ProductType::VARIATION === $product->get_type()
? $this->get_invalid_product_id_error( true )
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApi/README.md">
# WooCommerce REST API (v4 and above)

**⚠️ IMPORTANT: REST API v4 is currently in development and is NOT public.**

This directory contains the implementation of WooCommerce's REST API v4, which represents a complete architectural rewrite of the REST API system.

---

**Note**: This API is not ready for production use. Do not use in production environments.
</file>

<file path="plugins/woocommerce/src/Internal/Settings/OptionSanitizer.php">
namespace Automattic\WooCommerce\Internal\Settings;
⋮----
class OptionSanitizer {
⋮----
public function __construct() {
⋮----
public function sanitize_color_option( $value, $option ) {
⋮----
public function sanitize_price_separator_setting( $value, $raw_value ) {
⋮----
\WC_Admin_Settings::add_error( __( 'Thousand and decimal separators cannot contain numbers.', 'woocommerce' ) );
</file>

<file path="plugins/woocommerce/src/Internal/Settings/PointOfSaleDefaultSettings.php">
namespace Automattic\WooCommerce\Internal\Settings;
⋮----
class PointOfSaleDefaultSettings {
⋮----
public static function get_default_store_email() {
⋮----
public static function get_default_store_name() {
⋮----
public static function get_default_store_address() {
⋮----
WC()->countries->get_formatted_address(
⋮----
'address_1' => WC()->countries->get_base_address(),
'address_2' => WC()->countries->get_base_address_2(),
'city'      => WC()->countries->get_base_city(),
'state'     => WC()->countries->get_base_state(),
'postcode'  => WC()->countries->get_base_postcode(),
'country'   => WC()->countries->get_base_country(),
</file>

<file path="plugins/woocommerce/src/Internal/ShopperLists/Privacy/Privacy.php">
namespace Automattic\WooCommerce\Internal\ShopperLists\Privacy;
⋮----
use Automattic\WooCommerce\Internal\ShopperLists\ShopperList;
use Automattic\WooCommerce\Internal\ShopperLists\ShopperListItem;
use Automattic\WooCommerce\Internal\ShopperLists\ShopperListsController;
use Automattic\WooCommerce\Internal\Utilities\Users;
⋮----
class Privacy extends \WC_Abstract_Privacy {
⋮----
public function __construct() {
parent::__construct();
⋮----
public function register_exporters_and_erasers(): void {
⋮----
$this->add_exporter( self::REGISTRATION_ID, $label, array( $this, 'export_data' ) );
$this->add_eraser( self::REGISTRATION_ID, $label, array( $this, 'erase_data' ) );
⋮----
public function export_data( string $email_address ): array {
⋮----
$controller = wc_get_container()->get( ShopperListsController::class );
⋮----
foreach ( $controller->get_supported_slugs() as $slug ) {
$list = ShopperList::get_by_slug_raw( $slug, $user_id );
if ( ! $list || ! $list->get_items() ) {
⋮----
foreach ( $list->get_items() as $item ) {
⋮----
'item_id'     => $item->get_key(),
'data'        => self::item_export_rows( $item ),
⋮----
... (26 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ShopperLists/ShopperList.php">
namespace Automattic\WooCommerce\Internal\ShopperLists;
⋮----
use Automattic\WooCommerce\Internal\Utilities\Users;
⋮----
class ShopperList {
⋮----
private $user_id;
⋮----
private $slug;
⋮----
private $date_created_gmt;
⋮----
private $items;
⋮----
private function __construct(
⋮----
public static function get_by_slug( string $slug, ?int $user_id = null ) {
if ( ! wc_get_container()->get( ShopperListsController::class )->is_enabled( $slug ) ) {
⋮----
return self::get_by_slug_raw( $slug, $user_id );
⋮----
public static function get_by_slug_raw( string $slug, ?int $user_id = null ) {
if ( ! in_array( $slug, wc_get_container()->get( ShopperListsController::class )->get_supported_slugs(), true ) ) {
⋮----
$stored = Users::get_site_user_meta( $user_id, self::META_KEY_PREFIX . $slug );
⋮----
return self::from_array( $stored, $user_id );
⋮----
public static function get_all_for_user( ?int $user_id = null ): array {
⋮----
... (34 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ShopperLists/ShopperListItem.php">
namespace Automattic\WooCommerce\Internal\ShopperLists;
⋮----
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
⋮----
class ShopperListItem {
⋮----
private $key;
⋮----
private $product_id;
⋮----
private $variation_id;
⋮----
private $variation;
⋮----
private $quantity;
⋮----
private $date_added_gmt;
⋮----
private $product_title_at_save;
⋮----
private $product = null;
⋮----
private function __construct(
⋮----
public static function from_array( array $data ): self {
⋮----
throw new \Exception( 'Shopper list item requires "key" (string), "product_id" (int), and "quantity" (int).' );
⋮----
/**
... (82 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ShopperLists/ShopperListRenderer.php">
namespace Automattic\WooCommerce\Internal\ShopperLists;
⋮----
final class ShopperListRenderer {
⋮----
public static function render_grid_wrapper( array $wrapper_attrs, string $list_class, string $inner, string $before_list = '' ): string {
⋮----
/**
	 * Wrap `$row_inner_markup` in a `<template data-wp-each>` element that
	 * iAPI uses to render new rows. `$row_inner_markup` is the inner HTML
	 * for the `<li>` — everything between `<li>` and `</li>`.
	 *
	 * Trust contract: caller is responsible for ensuring `$row_inner_markup`
	 * contains only safe, escaped HTML.
	 *
	 * @param string $row_inner_markup Inner markup for the `<li>`.
	 * @return string
	 */
public static function render_each_template( string $row_inner_markup ): string {
⋮----
/**
	 * Wrap `$row_inner_markup` in an SSR `<li data-wp-each-child>` element
	 * seeded with the per-row iAPI context derived from `$item`. iAPI's
	 * hydration treats this as a no-op diff against the `<template>` if
	 * the inner markup matches.
	 *
	 * Trust contract: caller is responsible for ensuring `$row_inner_markup`
	 * contains only safe, escaped HTML.
	 *
	 * @param array<string, mixed> $item             Schema-shape item.
	 * @param string               $row_inner_markup Inner markup for the `<li>`.
... (41 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/ShopperLists/ShopperListsController.php">
namespace Automattic\WooCommerce\Internal\ShopperLists;
⋮----
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Automattic\WooCommerce\Internal\ShopperLists\Privacy\Privacy;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
final class ShopperListsController implements RegisterHooksInterface {
⋮----
public function get_wishlist_endpoint(): string {
⋮----
public function is_enabled( ?string $list_slug = null ): bool {
⋮----
if ( FeaturesUtil::feature_is_enabled( $feature ) ) {
⋮----
return null !== $feature && FeaturesUtil::feature_is_enabled( $feature );
⋮----
public function get_enabled_slugs(): array {
⋮----
static fn( string $feature ): bool => FeaturesUtil::feature_is_enabled( $feature )
⋮----
public function get_supported_slugs(): array {
⋮----
public function register(): void {
⋮----
wc_get_container()->get( Privacy::class );
⋮----
public function maybe_register_wishlist_endpoint(): void {
if ( ! $this->is_enabled( 'wishlist' ) ) {
⋮----
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Admin/Templates/html-admin-notification-create.php">
use Automattic\WooCommerce\Internal\StockNotifications\Admin\NotificationsPage;
⋮----
// phpcs:disable WordPress.Security.NonceVerification.Recommended
⋮----
$email = isset( $_REQUEST['user_email'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['user_email'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
⋮----
$product->get_parent_id() ? $product->get_name() : $product->get_title(),
absint( $product->get_id() )
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Admin/Templates/html-admin-notification-edit.php">
use Automattic\WooCommerce\Internal\StockNotifications\Admin\NotificationsPage;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
⋮----
<?php if ( $notification->get_status() === NotificationStatus::ACTIVE ) : ?>
⋮----
<?php elseif ( $notification->get_status() === NotificationStatus::PENDING ) : ?>
⋮----
<?php elseif ( $notification->get_status() === NotificationStatus::CANCELLED ) : ?>
⋮----
<?php elseif ( $notification->get_status() === NotificationStatus::SENT ) : ?>
⋮----
<a class="submitdelete deletion" href="<?php echo esc_url( wp_nonce_url( admin_url( sprintf( NotificationsPage::PAGE_URL . '&notification_action=delete&notification_id=%d', $notification->get_id() ) ), 'delete_customer_stock_notification' ) ); ?>"><?php esc_html_e( 'Delete permanently', 'woocommerce' ); ?></a>
⋮----
echo esc_html( sprintf( __( 'Notification #%d details', 'woocommerce' ), $notification->get_id() ) );
⋮----
if ( $notification->get_status() === NotificationStatus::PENDING ) {
⋮----
} elseif ( $notification->get_status() === NotificationStatus::CANCELLED ) {
⋮----
} elseif ( $notification->get_status() === NotificationStatus::SENT ) {
⋮----
$user_id     = $notification->get_user_id();
⋮----
} elseif ( filter_var( $notification->get_user_email(), FILTER_VALIDATE_EMAIL ) ) {
$user_string = $notification->get_user_email();
⋮----
<a href="<?php echo esc_url( admin_url( NotificationsPage::PAGE_URL . '&s=' . rawurlencode( $notification->get_user_email() ) ) ); ?>"><?php esc_html_e( 'View notifications &rarr;', 'woocommerce' ); ?></a>
⋮----
$product = $notification->get_product();
⋮----
... (12 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Admin/Templates/html-admin-notifications.php">
use Automattic\WooCommerce\Internal\StockNotifications\Admin\NotificationsPage;
⋮----
$table->views();
⋮----
<input type="search" placeholder="<?php echo esc_attr__( 'Search by user e-mail', 'woocommerce' ); ?>" value="<?php echo isset( $_REQUEST['s'] ) ? esc_attr( wc_clean( wp_unslash( $_REQUEST['s'] ) ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>" name="s" id="customer-stock-notifications-search-input">
⋮----
<input type="hidden" name="page" value="<?php echo isset( $_REQUEST['page'] ) ? esc_attr( wc_clean( wp_unslash( $_REQUEST['page'] ) ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>"/>
<?php $table->display(); ?>
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Admin/Templates/html-product-data-admin.php">
$image              = wp_get_attachment_image_src( (int) $product->get_image_id(), 'woocommerce_thumbnail' );
⋮----
$stock_availability = $product->get_availability();
⋮----
<a target="_blank" href="<?php echo esc_url( admin_url( sprintf( 'post.php?post=%d&action=edit', $product->get_parent_id() ? $product->get_parent_id() : $product->get_id() ) ) ); ?>"><span class="dashicons dashicons-external"></span></a>
⋮----
<?php echo wp_kses_post( $product->get_price_html( 'edit' ) ); ?>
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Admin/AdminManager.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Admin;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Admin\MenusController;
use Automattic\Jetpack\Constants;
⋮----
class AdminManager {
⋮----
final public function __construct() {
⋮----
$container->get( MenusController::class );
⋮----
public static function admin_resources() {
⋮----
$suffix    = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min';
$version   = Constants::get_constant( 'WC_VERSION' );
⋮----
wp_register_script( 'wc-admin-customer-stock-notifications', WC()->plugin_url() . '/assets/js/admin/wc-customer-stock-notifications' . $suffix . '.js', array( 'jquery' ), $version, true );
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Admin/ListTable.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Admin;
⋮----
use Automattic\WooCommerce\Internal\DataStores\StockNotifications\StockNotificationsDataStore;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
use Automattic\WooCommerce\Internal\StockNotifications\Admin\NotificationsPage;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EligibilityService;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EmailNormalizer;
⋮----
class ListTable extends \WP_List_Table {
⋮----
public $total_items = 0;
⋮----
public $total_active_items = 0;
⋮----
public $total_pending_items = 0;
⋮----
public $total_cancelled_items = 0;
⋮----
public $total_sent_items = 0;
⋮----
public $has_stock_notifications = false;
⋮----
public $data_store;
⋮----
public $eligibility_service;
⋮----
final public function init( EligibilityService $eligibility_service ) {
⋮----
... (170 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Admin/MenusController.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Admin;
⋮----
class MenusController {
⋮----
private $notifications_page;
⋮----
final public function init( NotificationsPage $notifications_page ): void {
⋮----
public function __construct() {
⋮----
public function add_menu() {
⋮----
public function add_screen_options(): void {
⋮----
public function set_screen_option( $status, $option, $value ): int {
⋮----
public function notifications_page() {
⋮----
$action = isset( $_GET['notification_action'] ) ? sanitize_text_field( wp_unslash( $_GET['notification_action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
⋮----
$this->notifications_page->create();
⋮----
$this->notifications_page->edit();
⋮----
$this->notifications_page->output();
⋮----
public static function add_screen_ids( $screen_ids ): array {
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Admin/NotificationCreatePage.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Admin;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
use Automattic\WooCommerce\Internal\StockNotifications\Admin\NotificationsPage;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EmailNormalizer;
⋮----
class NotificationCreatePage {
⋮----
public function output() {
$this->process_create_form();
⋮----
public function process_create_form() {
⋮----
NotificationsPage::add_notice( __( 'Please select a product.', 'woocommerce' ), 'error' );
⋮----
NotificationsPage::add_notice( __( 'Please select a customer.', 'woocommerce' ), 'error' );
⋮----
$posted_data['user_email'] = is_a( $user, 'WP_User' ) ? EmailNormalizer::normalize( $user->user_email ) : '';
⋮----
$posted_data['user_email'] = is_email( $posted_email ) ? EmailNormalizer::normalize( $posted_email ) : '';
⋮----
NotificationsPage::add_notice( __( 'Please enter a valid email address.', 'woocommerce' ), 'error' );
⋮----
$notification_ids = \WC_Data_Store::load( 'stock_notification' )->query( $posted_data );
⋮----
NotificationsPage::add_notice( $notice_message, 'error' );
⋮----
$notification->set_status( NotificationStatus::ACTIVE );
$notification->set_product_id( $posted_data['product_id'] );
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Admin/NotificationEditPage.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Admin;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
use Automattic\WooCommerce\Internal\StockNotifications\Admin\NotificationsPage;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
use Automattic\WooCommerce\Internal\StockNotifications\Emails\EmailManager;
use Automattic\WooCommerce\Internal\StockNotifications\Admin\ListTable;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationCancellationSource;
⋮----
class NotificationEditPage {
⋮----
private EmailManager $email_manager;
⋮----
final public function init( EmailManager $email_manager ): void {
⋮----
public function output() {
⋮----
$notification = Factory::get_notification( $notification_id );
⋮----
NotificationsPage::add_notice( $notice_message, 'error' );
⋮----
$this->process_edit_form( $notification );
$table->process_delete_action();
⋮----
$signed_up_customers = $table->data_store->query(
⋮----
'product_id' => $notification->get_product_id(),
⋮----
public function process_edit_form( Notification $notification ) {
... (31 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Admin/NotificationsPage.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Admin;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Admin\ListTable;
use Automattic\WooCommerce\Internal\StockNotifications\Admin\NotificationCreatePage;
use Automattic\WooCommerce\Internal\StockNotifications\Admin\NotificationEditPage;
⋮----
class NotificationsPage {
⋮----
public function output() {
$table = wc_get_container()->get( ListTable::class );
$table->process_actions();
$this->output_admin_notice();
$table->prepare_items();
⋮----
public function create() {
⋮----
$create_page->output();
⋮----
public function edit() {
$edit_page = wc_get_container()->get( NotificationEditPage::class );
$edit_page->output();
⋮----
public static function add_notice( $message, $type = 'info' ) {
⋮----
public function output_admin_notice(): void {
⋮----
\wp_admin_notice(
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Admin/SettingsController.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Admin;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Config;
use Automattic\WooCommerce\Internal\StockNotifications\Frontend\MyAccountEndpoint;
⋮----
class SettingsController {
⋮----
public function __construct() {
⋮----
public function add_my_account_endpoint_setting( $settings, $section_id ) {
⋮----
/**
	 * Add a 'Customer stock notifications' section to Products settings.
	 *
	 * @param array $sections Products settings sections.
	 * @return array New Products settings sections.
	 */
public function add_customer_stock_notifications_section( $sections ) {
⋮----
public function add_customer_stock_notifications_settings( $settings, $section_id ) {
⋮----
'default' => Config::get_unverified_deletion_days_threshold(),
⋮----
public function output_admin_notices() {
⋮----
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && Config::allows_signups() ) {
⋮----
public function add_disable_stock_notifications_checkbox() {
⋮----
if ( ! Config::allows_signups() ) {
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/AsyncTasks/CycleStateService.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\AsyncTasks;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\AsyncTasks\JobManager;
⋮----
class CycleStateService {
⋮----
private $logger;
⋮----
public function __construct() {
$this->logger = \wc_get_logger();
⋮----
public function get_or_initialize_cycle_state( int $product_id ): array {
⋮----
throw new \Exception( 'Product ID is required.' );
⋮----
$cycle_state = $this->get_raw_cycle_state( $product_id );
⋮----
throw new \Exception( 'Invalid cycle state.' );
⋮----
private function get_raw_cycle_state( int $product_id ): array {
$cycle_state = get_option( $this->get_option_name( $product_id ), false );
⋮----
public function complete_cycle( int $product_id, array $cycle_state ): void {
⋮----
$this->logger->info(
⋮----
$this->save_cycle_state( $product_id, array() );
⋮----
public function save_cycle_state( int $product_id, array $cycle_state ): bool {
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/AsyncTasks/JobManager.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\AsyncTasks;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationCancellationSource;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
use Automattic\WooCommerce\Internal\StockNotifications\Config;
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\NotificationQuery;
use Automattic\WooCommerce\Internal\StockNotifications\Emails\EmailManager;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EligibilityService;
use WC_Product;
use Exception;
⋮----
class JobManager {
⋮----
private $logger;
⋮----
private $queue;
⋮----
public function __construct() {
$this->logger = \wc_get_logger();
$this->queue  = \WC()->queue();
⋮----
public function schedule_initial_job_for_product( int $product_id ): bool {
⋮----
if ( $this->queue->get_next( self::AS_JOB_SEND_STOCK_NOTIFICATIONS, $args, self::AS_JOB_GROUP ) ) {
⋮----
$action_id = $this->queue->schedule_single(
⋮----
$this->logger->info(
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/AsyncTasks/NotificationsProcessor.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\AsyncTasks;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\AsyncTasks\JobManager;
use Automattic\WooCommerce\Internal\StockNotifications\AsyncTasks\CycleStateService;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EligibilityService;
use Automattic\WooCommerce\Internal\StockNotifications\Emails\EmailManager;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\NotificationQuery;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationCancellationSource;
use WC_Product;
⋮----
class NotificationsProcessor {
⋮----
private EmailManager $email_manager;
⋮----
private $logger;
⋮----
private EligibilityService $eligibility_service;
⋮----
private JobManager $job_manager;
⋮----
private CycleStateService $cycle_state_service;
⋮----
final public function init(
⋮----
public function __construct() {
$this->logger = \wc_get_logger();
⋮----
... (55 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Emails/CustomerStockNotificationEmail.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Emails;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\UtmHelper;
use WC_Email;
⋮----
class CustomerStockNotificationEmail extends WC_Email {
⋮----
public function __construct() {
⋮----
// Call parent constructor.
parent::__construct();
⋮----
/**
	 * Get email subject.
	 *
	 * @return string
	 */
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function get_default_intro_content() {
⋮----
public function get_default_additional_content() {
⋮----
public function get_intro_content() {
⋮----
return apply_filters( 'woocommerce_email_stock_notification_intro_content', $this->format_string( $this->get_option_or_transient( 'intro_content', $this->get_default_intro_content() ) ), $this->object, $this );
... (60 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Emails/CustomerStockNotificationVerifiedEmail.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Emails;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\UtmHelper;
use WC_Email;
⋮----
class CustomerStockNotificationVerifiedEmail extends WC_Email {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function get_default_intro_content() {
⋮----
public function get_default_additional_content() {
⋮----
public function get_intro_content() {
⋮----
return apply_filters( 'woocommerce_email_stock_notification_intro_content', $this->format_string( $this->get_option_or_transient( 'intro_content', $this->get_default_intro_content() ) ), $this->object, $this );
⋮----
public function get_content_html() {
⋮----
$this->get_additional_template_args(),
⋮----
'product'            => $this->object->get_product(),
... (50 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Emails/CustomerStockNotificationVerifyEmail.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Emails;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Config;
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\UtmHelper;
use WC_Email;
⋮----
class CustomerStockNotificationVerifyEmail extends WC_Email {
⋮----
public function __construct() {
⋮----
parent::__construct();
⋮----
public function get_default_subject() {
⋮----
public function get_default_heading() {
⋮----
public function get_default_intro_content() {
⋮----
public function get_default_additional_content() {
⋮----
public function get_intro_content() {
⋮----
return apply_filters( 'woocommerce_email_stock_notification_intro_content', $this->format_string( $this->get_option_or_transient( 'intro_content', $this->get_default_intro_content() ) ), $this->object, $this );
⋮----
public function get_content_html() {
⋮----
$this->get_additional_template_args(),
⋮----
... (53 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Emails/EmailActionController.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Emails;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationCancellationSource;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
⋮----
class EmailActionController {
⋮----
private EmailManager $email_manager;
⋮----
public function __construct() {
⋮----
final public function init( EmailManager $email_manager ): void {
⋮----
public function maybe_process_email_action(): void {
⋮----
$this->validate_and_maybe_process_request( $notification_id, $action_key, $action );
⋮----
public function validate_and_maybe_process_request( int $notification_id, string $email_link_action_key, string $action = '' ): void {
⋮----
// An empty $action means the caller omitted the routing argument — a
// programming error, not a mis-routed email. Return silently so the
// debug branch in the switch is reserved for genuinely-unknown
// tokens arriving in the wild.
⋮----
$notification = $this->get_notification_to_be_processed( $notification_id );
⋮----
$this->process_verification_action( $notification, $email_link_action_key );
⋮----
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Emails/EmailManager.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Emails;
⋮----
use Automattic\WooCommerce\Enums\TaxDisplayMode;
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
use Automattic\WooCommerce\Internal\StockNotifications\Emails\CustomerStockNotificationEmail;
use Automattic\WooCommerce\Internal\StockNotifications\Emails\CustomerStockNotificationVerifyEmail;
use Automattic\WooCommerce\Internal\StockNotifications\Emails\CustomerStockNotificationVerifiedEmail;
use Automattic\WooCommerce\Internal\StockNotifications\Emails\EmailTemplatesController;
⋮----
class EmailManager {
⋮----
public static $email_ids = array(
⋮----
final public function init() {
⋮----
$container->get( EmailTemplatesController::class );
⋮----
public function email_classes( $emails ) {
⋮----
public function add_transactional_emails( $actions ) {
⋮----
public function maybe_restore_customer_tax_location_data( $notification ) {
⋮----
$location = $notification->get_meta( '_customer_location_data' );
⋮----
public function add_stylesheets( $css, $email = null ) {
⋮----
public function add_intro_content_to_preview_settings( $setting_ids, $email_id ) {
⋮----
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Emails/EmailTemplatesController.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Emails;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
⋮----
class EmailTemplatesController {
⋮----
final public function init() {
⋮----
public function register_template_hooks() {
⋮----
public function email_product_image( $product, $notification, $plain_text = false ) {
⋮----
$image     = wp_get_attachment_image_src( (int) $product->get_image_id(), 'woocommerce_thumbnail' );
⋮----
<img src="<?php echo esc_attr( $image_src ); ?>" alt="<?php echo esc_attr( $product->get_title() ); ?>" width="220"/>
⋮----
/**
	 * Email product title.
	 *
	 * @param WC_Product   $product The product object.
	 * @param Notification $notification The notification object.
	 * @param bool         $plain_text Whether the email is plain text.
	 */
public function email_product_title( $product, $notification, $plain_text = false ) {
⋮----
<div id="notification__product__title"><?php echo esc_html( $product->get_name() ); ?></div>
⋮----
/**
	 * Email product attributes.
	 *
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Enums/NotificationCancellationSource.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Enums;
⋮----
final class NotificationCancellationSource {
⋮----
public static function get_valid_cancellation_sources(): array {
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Enums/NotificationStatus.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Enums;
⋮----
final class NotificationStatus {
⋮----
public static function get_valid_statuses(): array {
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Frontend/FormHandlerService.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Frontend;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Config;
⋮----
class FormHandlerService {
⋮----
private SignupService $signup_service;
⋮----
private $logger;
⋮----
final public function init( SignupService $signup_service ) {
⋮----
$this->logger         = \wc_get_logger();
⋮----
public function __construct() {
⋮----
public function handle_signup() {
⋮----
if ( ! Config::allows_signups() ) {
⋮----
if ( self::requires_nonce_check() ) {
⋮----
wc_add_notice( $this->signup_service->get_error_message( SignupService::ERROR_INVALID_REQUEST ), 'error' );
⋮----
$data = $this->signup_service->parse( $_POST );
if ( \is_wp_error( $data ) ) {
wc_add_notice( $this->signup_service->get_error_message( $data->get_error_code() ), 'error' );
⋮----
$result = $this->signup_service->signup(
⋮----
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Frontend/MyAccountEndpoint.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Frontend;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationCancellationSource;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\NotificationQuery;
⋮----
class MyAccountEndpoint {
⋮----
public static function get_endpoint_slug(): string {
⋮----
public static function get_nonce_action( string $action, int $notification_id ): string {
⋮----
public static function get_action_url( string $action, int $notification_id, int $page = 1 ): string {
⋮----
$url = add_query_arg( $args, self::get_endpoint_url() );
⋮----
return wp_nonce_url( $url, self::get_nonce_action( $action, $notification_id ) );
⋮----
public static function get_cancellable_statuses(): array {
⋮----
public static function is_cancellable( Notification $notification ): bool {
return in_array( (string) $notification->get_status(), self::get_cancellable_statuses(), true );
⋮----
public static function can_resend( Notification $notification ): bool {
return NotificationStatus::PENDING === (string) $notification->get_status();
⋮----
private NotificationManagementService $notification_management_service;
⋮----
... (108 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Frontend/MyAccountView.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Frontend;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
⋮----
final class MyAccountView {
⋮----
public function get_template_args( array $pending, array $active, array $page ): array {
⋮----
'pending_rows'      => $this->get_rows( $pending, $current_page ),
'active_rows'       => $this->get_rows( $active, $current_page ),
⋮----
'previous_page_url' => $current_page > 1 ? MyAccountEndpoint::get_endpoint_url( $current_page - 1 ) : '',
'next_page_url'     => $current_page < $total_pages ? MyAccountEndpoint::get_endpoint_url( $current_page + 1 ) : '',
'shop_url'          => \wc_get_page_permalink( 'shop' ),
⋮----
private function get_rows( array $notifications, int $current_page ): array {
⋮----
$id           = (int) $notification->get_id();
$product_name = MyAccountEndpoint::get_display_product_name( $notification );
$variation    = (string) $notification->get_product_formatted_variation_list( true );
$date_created = $notification->get_date_created();
$can_resend   = MyAccountEndpoint::can_resend( $notification );
$can_cancel   = MyAccountEndpoint::is_cancellable( $notification );
⋮----
'status'       => (string) $notification->get_status(),
⋮----
'product_url'  => (string) $notification->get_product_permalink(),
⋮----
'date_iso'     => $date_created ? $date_created->date( 'c' ) : '',
'date_display' => $date_created ? \wc_format_datetime( $date_created ) : '',
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Frontend/NotificationManagementService.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Frontend;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Emails\EmailManager;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
⋮----
class NotificationManagementService {
⋮----
private EmailManager $email_manager;
⋮----
final public function init( EmailManager $email_manager ): void {
⋮----
public function get_resend_verification_email_url( Notification $notification ): string {
⋮----
self::RESEND_QUERY_ARG => $notification->get_id(),
⋮----
$notification->get_product_permalink()
⋮----
return wp_nonce_url( $url, self::RESEND_NONCE_ACTION . '_' . $notification->get_id() );
⋮----
public function maybe_process_resend_request(): void {
⋮----
// Scope the nonce per-notification so one valid resend URL cannot be replayed
// across the notification id query arg to trigger emails for other customers.
⋮----
$notification = Factory::get_notification( $notification_id );
⋮----
$owner_id = (int) $notification->get_user_id();
⋮----
... (28 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Frontend/ProductPageIntegration.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Frontend;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Config;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EligibilityService;
use Automattic\WooCommerce\Internal\StockNotifications\Frontend\MyAccountEndpoint;
use Automattic\WooCommerce\Internal\StockNotifications\Frontend\SignupService;
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use WC_Product;
⋮----
class ProductPageIntegration {
⋮----
private array $rendered = array();
⋮----
private EligibilityService $eligibility_service;
⋮----
private SignupService $signup_service;
⋮----
final public function init( EligibilityService $eligibility_service, SignupService $signup_service ): void {
⋮----
public function __construct() {
⋮----
public function maybe_render_form() {
⋮----
if ( ! Config::allows_signups() ) {
⋮----
if ( $this->is_rendering_inside_add_to_cart_with_options() ) {
⋮----
if ( isset( $this->rendered[ $product->get_id() ] ) ) {
⋮----
$this->rendered[ $product->get_id() ] = true;
... (44 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Frontend/SignupRateLimiter.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Frontend;
⋮----
use WC_Geolocation;
use WC_Rate_Limiter;
⋮----
class SignupRateLimiter {
⋮----
public function is_rate_limited( string $user_email ): bool {
foreach ( array_keys( $this->get_rate_limits( $user_email ) ) as $rate_limit_id ) {
if ( ! WC_Rate_Limiter::retried_too_soon( $rate_limit_id ) ) {
⋮----
public function apply( string $user_email ): bool {
⋮----
foreach ( $this->get_rate_limits( $user_email ) as $rate_limit_id => $delay ) {
if ( ! WC_Rate_Limiter::set_rate_limit( $rate_limit_id, $delay ) ) {
⋮----
WC_Rate_Limiter::set_rate_limit( $applied_rate_limit_id, -1 );
⋮----
private function get_rate_limits( string $user_email ): array {
$options     = $this->get_options();
⋮----
$ip_address = $this->get_ip_address( $options['proxy_support'] );
⋮----
private function get_ip_address( bool $proxy_support ): string {
⋮----
return WC_Geolocation::get_ip_address();
⋮----
$ip_address = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ?? '' ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- format-validated below via rest_is_ip_address().
⋮----
/**
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Frontend/SignupResult.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Frontend;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
⋮----
class SignupResult {
⋮----
private string $code;
⋮----
private ?Notification $notification;
⋮----
public function __construct( string $code, ?Notification $notification = null ) {
⋮----
public function get_code(): string {
⋮----
public function get_notification(): ?Notification {
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Frontend/SignupService.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Frontend;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Config;
use Automattic\WooCommerce\Internal\StockNotifications\Emails\EmailManager;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
use Automattic\WooCommerce\Internal\StockNotifications\Frontend\MyAccountEndpoint;
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\NotificationQuery;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EligibilityService;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EmailNormalizer;
⋮----
class SignupService {
⋮----
private EligibilityService $eligibility_service;
⋮----
private NotificationManagementService $notification_management_service;
⋮----
private EmailManager $email_manager;
⋮----
private SignupRateLimiter $rate_limiter;
⋮----
private $logger;
⋮----
final public function init(
⋮----
$this->logger                          = \wc_get_logger();
⋮----
public function signup( int $product_id, int $user_id, string $user_email, array $posted_attributes = array() ) {
⋮----
... (115 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Privacy/PrivacyEraser.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Privacy;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationCancellationSource;
use Automattic\WooCommerce\Internal\StockNotifications\Factory;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\NotificationQuery;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EmailNormalizer;
⋮----
class PrivacyEraser extends \WC_Abstract_Privacy {
⋮----
public function __construct() {
parent::__construct();
⋮----
public function register_erasers_exporters() {
$this->add_eraser(
⋮----
public static function erase_notification_data( string $email_address ): array {
⋮----
$email_address = EmailNormalizer::normalize( $email_address );
⋮----
$notifications = NotificationQuery::get_notifications(
⋮----
$notification = Factory::get_notification( $notification_id );
⋮----
$notification->set_user_email( $anonymous_email );
$notification->set_user_id( 0 );
$notification->set_status( NotificationStatus::CANCELLED );
$notification->set_cancellation_source( NotificationCancellationSource::USER );
$notification->set_date_cancelled( time() );
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Utilities/EligibilityService.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Utilities;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
use Automattic\WooCommerce\Internal\StockNotifications\Config;
use Automattic\WooCommerce\Internal\StockNotifications\NotificationQuery;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\StockManagementHelper;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\ProductStatus;
use WC_Product;
⋮----
class EligibilityService {
⋮----
private StockManagementHelper $stock_management_helper;
⋮----
final public function init( StockManagementHelper $stock_management_helper ): void {
⋮----
public function is_product_eligible( ?WC_Product $product ): bool {
⋮----
if ( ! $product->is_type( Config::get_supported_product_types() ) ) {
⋮----
if ( in_array( $product->get_status(), array( ProductStatus::TRASH, ProductStatus::AUTO_DRAFT, ProductStatus::PENDING, ProductStatus::FUTURE ), true ) ) {
⋮----
public function product_allows_signups( WC_Product $product ): bool {
if ( $product->is_type( ProductType::VARIATION ) ) {
$parent_product = wc_get_product( $product->get_parent_id() );
⋮----
return $this->product_allows_signups( $parent_product );
⋮----
return 'no' !== $product->get_meta( Config::get_product_signups_meta_key() );
⋮----
... (26 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Utilities/EmailNormalizer.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Utilities;
⋮----
final class EmailNormalizer {
⋮----
public static function normalize( string $email ): string {
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Utilities/StockManagementHelper.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Utilities;
⋮----
use Automattic\WooCommerce\Enums\ProductType;
use WC_Product;
⋮----
class StockManagementHelper {
⋮----
private array $managed_variations = array();
⋮----
public function get_managed_variations( WC_Product $product ): array {
if ( ! $product->is_type( ProductType::VARIABLE ) ) {
⋮----
$product_id = $product->get_id();
⋮----
$children = $product->get_children();
⋮----
$managed_children = $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT post_id FROM $wpdb->postmeta WHERE meta_key = '_manage_stock' AND meta_value != 'yes' AND post_id IN {$query_in}", $children ) );
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Utilities/UtmHelper.php">
namespace Automattic\WooCommerce\Internal\StockNotifications\Utilities;
⋮----
class UtmHelper {
⋮----
public static function add_email_utm_params( string $url, string $medium = self::UTM_MEDIUM_EMAIL ): string {
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Config.php">
namespace Automattic\WooCommerce\Internal\StockNotifications;
⋮----
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\ProductStatus;
⋮----
class Config {
⋮----
private static $supported_product_types;
⋮----
private static $supported_product_statuses;
⋮----
private static $eligible_stock_statuses;
⋮----
private static $verification_expiration_time_threshold;
⋮----
public static function get_supported_product_types(): array {
⋮----
public static function get_supported_product_statuses(): array {
⋮----
public static function get_eligible_stock_statuses(): array {
⋮----
public static function get_product_signups_meta_key(): string {
⋮----
public static function allows_signups(): bool {
⋮----
public static function requires_double_opt_in(): bool {
⋮----
public static function requires_account(): bool {
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/DataRetentionController.php">
namespace Automattic\WooCommerce\Internal\StockNotifications;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
⋮----
class DataRetentionController {
⋮----
public function __construct() {
⋮----
public function on_woo_install_or_update(): void {
$this->schedule_or_unschedule_daily_task( null, Config::get_unverified_deletion_days_threshold() );
⋮----
public function schedule_or_unschedule_daily_task( $unused, $new_option_value ): void {
⋮----
$this->clear_daily_task();
⋮----
public function clear_daily_task() {
⋮----
public function do_wc_customer_stock_notifications_daily() {
$time_threshold = Config::get_unverified_deletion_days_threshold();
⋮----
$overdue_notifications = NotificationQuery::get_notifications(
⋮----
$notification = Factory::get_notification( $notification_id );
⋮----
$notification->delete();
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Factory.php">
namespace Automattic\WooCommerce\Internal\StockNotifications;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Notification;
⋮----
class Factory {
⋮----
public static function get_notification( int $notification_id ) {
⋮----
\wc_caught_exception( $e, __FUNCTION__, array( $notification_id ) );
⋮----
public static function create_dummy_notification(): Notification {
⋮----
$product = new \WC_Product();
$product->set_name( __( 'Dummy Product', 'woocommerce' ) );
$product->set_price( 25 );
$product->set_image_id( get_option( 'woocommerce_placeholder_image', 0 ) );
⋮----
$notification->set_product_id( $product->get_id() );
$notification->set_user_email( 'preview@example.com' );
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/Notification.php">
namespace Automattic\WooCommerce\Internal\StockNotifications;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationCancellationSource;
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EmailNormalizer;
⋮----
class Notification extends \WC_Data {
⋮----
protected $object_type = 'stock_notification';
⋮----
public $product;
⋮----
protected $data = array(
⋮----
public function __construct( $read = 0 ) {
parent::__construct( $read );
⋮----
$this->set_id( $read );
⋮----
$this->set_id( $read->get_id() );
⋮----
$this->set_id( absint( $read->ID ) );
⋮----
$this->set_props( $read );
$this->set_object_read( true );
⋮----
$this->data_store = \WC_Data_Store::load( 'stock_notification' );
if ( $this->get_id() > 0 ) {
$this->data_store->read( $this );
⋮----
... (164 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/NotificationQuery.php">
namespace Automattic\WooCommerce\Internal\StockNotifications;
⋮----
class NotificationQuery {
⋮----
public static function get_notifications( array $args ): array {
$result = self::run_query( $args );
⋮----
public static function count_notifications( array $args ): int {
⋮----
return (int) self::run_query( $args );
⋮----
private static function run_query( array $args ) {
return \WC_Data_Store::load( 'stock_notification' )->query( $args );
⋮----
public static function product_has_active_notifications( array $product_ids ): bool {
return \WC_Data_Store::load( 'stock_notification' )->product_has_active_notifications( $product_ids );
⋮----
public static function notification_exists_by_email( int $product_id, string $email ): bool {
return \WC_Data_Store::load( 'stock_notification' )->notification_exists_by_email( $product_id, $email );
⋮----
public static function notification_exists_by_user_id( int $product_id, int $user_id ): bool {
return \WC_Data_Store::load( 'stock_notification' )->notification_exists_by_user_id( $product_id, $user_id );
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/StockNotifications.php">
namespace Automattic\WooCommerce\Internal\StockNotifications;
⋮----
use Automattic\WooCommerce\Internal\DataStores\StockNotifications\StockNotificationsDataStore;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Automattic\WooCommerce\Internal\StockNotifications\Emails\EmailActionController;
use Automattic\WooCommerce\Internal\StockNotifications\StockSyncController;
use Automattic\WooCommerce\Internal\StockNotifications\Privacy\PrivacyEraser;
use Automattic\WooCommerce\Internal\StockNotifications\Emails\EmailManager;
use Automattic\WooCommerce\Internal\StockNotifications\AsyncTasks\NotificationsProcessor;
use Automattic\WooCommerce\Internal\StockNotifications\Admin\AdminManager;
use Automattic\WooCommerce\Internal\StockNotifications\Admin\SettingsController;
use Automattic\WooCommerce\Internal\StockNotifications\Frontend\MyAccountEndpoint;
use Automattic\WooCommerce\Internal\StockNotifications\Frontend\ProductPageIntegration;
use Automattic\WooCommerce\Internal\StockNotifications\Frontend\FormHandlerService;
use Automattic\WooCommerce\Internal\StockNotifications\Frontend\NotificationManagementService;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class StockNotifications implements RegisterHooksInterface {
⋮----
public function register(): void {
⋮----
public function on_install_or_update() {
if ( ! FeaturesUtil::feature_is_enabled( self::FEATURE_NAME ) ) {
⋮----
wc_get_container()->get( DataRetentionController::class )->on_woo_install_or_update();
⋮----
public function on_feature_enabled_changed( $feature_id, $enabled = false ): void {
⋮----
$data_retention_controller = wc_get_container()->get( DataRetentionController::class );
... (27 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/StockNotifications/StockSyncController.php">
namespace Automattic\WooCommerce\Internal\StockNotifications;
⋮----
use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EligibilityService;
use Automattic\WooCommerce\Internal\StockNotifications\AsyncTasks\JobManager;
use WC_Product;
⋮----
class StockSyncController {
⋮----
private array $queue = array();
⋮----
private EligibilityService $eligibility_service;
⋮----
private JobManager $job_manager;
⋮----
protected $logger;
⋮----
final public function init(
⋮----
$this->logger              = \wc_get_logger();
⋮----
public function __construct() {
⋮----
public function handle_product_stock_status_change( $product_id, $stock_status, $product = null ) {
⋮----
if ( ! $this->eligibility_service->is_stock_status_eligible( $stock_status ) ) {
⋮----
$product = \wc_get_product( $product_id );
⋮----
if ( ! $this->eligibility_service->is_product_eligible( $product ) ) {
⋮----
... (19 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Tax/TaxRateDataStore.php">
namespace Automattic\WooCommerce\Internal\Tax;
⋮----
class TaxRateDataStore {
⋮----
private array $rate_objects_cache = array();
⋮----
public function get_rate_objects_for_ids( array $ids ): array {
⋮----
$rows = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id IN ( $list )" );
</file>

<file path="plugins/woocommerce/src/Internal/Traits/AccessiblePrivateMethods.php">
namespace Automattic\WooCommerce\Internal\Traits;
⋮----
trait AccessiblePrivateMethods {
⋮----
private $_accessible_private_methods = array();
⋮----
private static $_accessible_static_private_methods = array();
⋮----
protected static function add_action( string $hook_name, $callback, int $priority = 10, int $accepted_args = 1 ): void {
self::process_callback_before_hooking( $callback );
⋮----
protected static function add_filter( string $hook_name, $callback, int $priority = 10, int $accepted_args = 1 ): void {
⋮----
protected static function process_callback_before_hooking( $callback ): void {
⋮----
static::mark_static_method_as_accessible( $callback[1] );
⋮----
$first_item->mark_method_as_accessible( $callback[1] );
⋮----
protected function mark_method_as_accessible( string $method_name ): bool {
⋮----
protected static function mark_static_method_as_accessible( string $method_name ): bool {
⋮----
public function __call( $name, $arguments ) {
⋮----
return parent::__call( $name, $arguments );
⋮----
throw new \Error( 'Call to private method ' . get_class( $this ) . '::' . $name );
⋮----
throw new \Error( 'Call to undefined method ' . get_class( $this ) . '::' . $name );
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Traits/OrderAttributionMeta.php">
namespace Automattic\WooCommerce\Internal\Traits;
⋮----
use Automattic\WooCommerce\Vendor\Detection\MobileDetect;
use Exception;
use WC_Meta_Data;
use WC_Order;
use WP_Post;
⋮----
trait OrderAttributionMeta {
⋮----
private $default_fields = array(
⋮----
private $fields = array();
⋮----
private $field_names = array();
⋮----
private $field_prefix = '';
⋮----
/**
	 * Get the device type based on the other meta fields.
	 *
	 * @param array $values The meta values.
	 *
	 * @return string The device type.
	 */
protected function get_device_type( array $values ): string {
⋮----
if ( $detector->isMobile() ) {
⋮----
} elseif ( $detector->isTablet() ) {
... (48 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Traits/RestApiCache.php">
namespace Automattic\WooCommerce\Internal\Traits;
⋮----
use Automattic\WooCommerce\Internal\Caches\VersionStringGenerator;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\CallbackUtil;
use WP_REST_Request;
use WP_REST_Response;
⋮----
trait RestApiCache {
⋮----
private static string $cache_group = 'woocommerce_rest_api_cache';
⋮----
private static array $always_excluded_headers = array(
⋮----
private static string $warning_cache_group = 'woocommerce_rest_api_cache_warnings';
⋮----
private static int $file_warning_suppression_ttl = HOUR_IN_SECONDS;
⋮----
private ?VersionStringGenerator $version_string_generator = null;
⋮----
private $is_handling_cached_endpoint = false;
⋮----
private bool $rest_api_caching_feature_enabled = false;
⋮----
protected function initialize_rest_api_cache(): void {
⋮----
$features_controller = wc_get_container()->get( FeaturesController::class );
⋮----
$this->rest_api_caching_feature_enabled = $features_controller->feature_is_enabled( 'rest_api_caching' );
... (306 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Traits/ScriptDebug.php">
namespace Automattic\WooCommerce\Internal\Traits;
⋮----
use Automattic\Jetpack\Constants;
⋮----
trait ScriptDebug {
⋮----
protected function get_script_suffix(): string {
return $this->is_script_debug_enabled() ? '' : '.min';
⋮----
protected function is_script_debug_enabled(): bool {
return Constants::is_true( 'SCRIPT_DEBUG' );
</file>

<file path="plugins/woocommerce/src/Internal/TransientFiles/README.md">
# Transient Files Engine

## Index

* [Summary](#summary)
* [Contents of the engine](#contents-of-the-engine)
* [The code API](#the-code-api)
* [Hooks](#hooks)
* [The HTTP file serving endpoint](#the-http-file-serving-endpoint)


## Summary

The WooCommerce transient files engine allows for the creation of transient files. We define a _transient file_ as a physical file (in the server filesystem) that:

* Has a random name.
* Can have any arbitrary content.
* Lives in a dedicated subdirectory inside the WordPress `uploads` folder (customizable via [hook](#hooks)).
* Has an expiration date.
* Its contents can be retrieved via an [unauthenticated HTTP endpoint](#the-http-file-serving-endpoint).

As of now, the only way to create a transient file is by directly passing its contents to the [`create_transient_file`](#create_transient_file) method in a parameter. Additional mechanisms (e.g. passing the path of an already existing file) might be added in the future (pull requests welcome, as usual!)

Expiration dates don't include the time of the day. A file is considered to have expired after 23:59:59 of its expiration date.

A mechanism is in place too to periodically delete expired files using Action Scheduler.


## Contents of the engine

... (90 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/TransientFiles/TransientFilesEngine.php">
namespace Automattic\WooCommerce\Internal\TransientFiles;
⋮----
use \DateTime;
use \Exception;
use \InvalidArgumentException;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Automattic\WooCommerce\Utilities\TimeUtil;
⋮----
class TransientFilesEngine implements RegisterHooksInterface {
⋮----
private $legacy_proxy;
⋮----
public function register() {
⋮----
final public function init( LegacyProxy $legacy_proxy ) {
⋮----
public function get_transient_files_directory(): string {
$upload_dir_info                   = $this->legacy_proxy->call_function( 'wp_upload_dir' );
⋮----
$resolved_transient_files_directory = $this->resolve_directory_if_it_exists( $transient_files_directory );
⋮----
if ( ! $this->legacy_proxy->call_function( 'wp_mkdir_p', $transient_files_directory ) ) {
⋮----
$wp_filesystem = FilesystemUtil::get_wp_filesystem_direct();
$wp_filesystem->put_contents( $transient_files_directory . '/.htaccess', 'deny from all' );
$wp_filesystem->put_contents( $transient_files_directory . '/index.html', '' );
⋮----
// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Not rendered as output, and consistent with the other throws in this method.
... (103 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/ArrayUtil.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
class ArrayUtil {
⋮----
public static function array_is_list( array $arr ): bool {
⋮----
public static function merge_by_key( array $arr1, array $arr2, string $key ): array {
⋮----
public static function filter_null_values_recursive( array $arr ): array {
$is_list  = self::array_is_list( $arr );
⋮----
$filtered[ $key ] = self::filter_null_values_recursive( $value );
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/BlocksUtil.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
class BlocksUtil {
⋮----
public static function flatten_blocks( $blocks ) {
⋮----
$inner_blocks = self::flatten_blocks( $block['innerBlocks'] );
⋮----
public static function get_blocks_from_widget_area( $block_name ) {
⋮----
public static function get_block_from_template_part( $block_name, $template_part_slug ) {
⋮----
$flatten_blocks = self::flatten_blocks( $blocks );
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/COTMigrationUtil.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Automattic\WooCommerce\Internal\DataStores\Orders\{ DataSynchronizer, OrdersTableDataStore };
use WC_Order;
use WP_Post;
⋮----
class COTMigrationUtil {
⋮----
private $table_controller;
⋮----
private $data_synchronizer;
⋮----
final public function init( CustomOrdersTableController $table_controller, DataSynchronizer $data_synchronizer ) {
⋮----
public function get_order_admin_screen() : string {
⋮----
throw new \Exception( 'This function should only be called in admin.' );
⋮----
return $this->custom_orders_table_usage_is_enabled() && function_exists( 'wc_get_page_screen_id' )
⋮----
private function custom_orders_table_usage_is_enabled() : bool {
return $this->table_controller->custom_orders_table_usage_is_enabled();
⋮----
public function is_custom_order_tables_in_sync() : bool {
if ( ! $this->data_synchronizer->data_sync_is_enabled() ) {
⋮----
return ! $this->data_synchronizer->has_orders_pending_sync();
⋮----
public function custom_orders_table_data_sync_is_enabled(): bool {
... (29 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/DatabaseUtil.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
use DateTime;
use DateTimeZone;
use Vtiful\Kernel\Format;
⋮----
class DatabaseUtil {
⋮----
public function dbdelta( string $queries = '', bool $execute = true ): array {
⋮----
public function get_missing_tables( string $creation_queries ): array {
⋮----
$suppress_errors = $wpdb->suppress_errors( true );
$dbdelta_output  = $this->dbdelta( $creation_queries, false );
$wpdb->suppress_errors( $suppress_errors );
$parsed_output = $this->parse_dbdelta_output( $dbdelta_output );
⋮----
public function parse_dbdelta_output( array $dbdelta_output ): array {
⋮----
public function drop_database_table( string $table_name, bool $add_prefix = false ) {
⋮----
return $wpdb->query( "DROP TABLE IF EXISTS `{$table_name}`" );
⋮----
public function drop_table_index( string $table_name, string $index_name ): bool {
⋮----
if ( empty( $this->get_index_columns( $table_name, $index_name ) ) ) {
⋮----
$wpdb->query( "ALTER TABLE $table_name DROP INDEX $index_name" );
⋮----
public function create_primary_key( string $table_name, array $columns ) {
... (74 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/FilesystemUtil.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Proxies\LegacyProxy;
use Exception;
use WP_Filesystem_Base;
use WP_Filesystem_Direct;
⋮----
class FilesystemUtil {
⋮----
private static ?WP_Filesystem_Base $cached_direct_filesystem = null;
⋮----
public static function get_wp_filesystem(): WP_Filesystem_Base {
⋮----
$initialized = ( $wp_filesystem instanceof WP_Filesystem_Base ) || self::initialize_wp_filesystem();
⋮----
if ( ! $initialized || ! self::is_usable_ftp_filesystem( $wp_filesystem ) ) {
⋮----
public static function get_wp_filesystem_direct(): WP_Filesystem_Base {
⋮----
return self::get_wp_filesystem();
⋮----
public static function get_wp_filesystem_method_or_direct() {
$proxy = wc_get_container()->get( LegacyProxy::class );
if ( ! self::constant_exists( 'FS_METHOD' ) && false === $proxy->call_function( 'get_option', 'ftp_credentials' ) && ! self::constant_exists( 'FTP_HOST' ) ) {
⋮----
$method = $proxy->call_function( 'get_filesystem_method' );
⋮----
public static function get_content_directory_relative_path(): string {
$abspath        = (string) Constants::get_constant( 'ABSPATH' );
... (63 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/HtmlSanitizer.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
class HtmlSanitizer {
⋮----
public function styled_post_content( string $html ): string {
⋮----
public function sanitize( string $html, array $sanitizer_rules = self::LOW_HTML_BALANCED_TAGS_NO_LINKS ): string {
⋮----
$html = $this->apply_string_callbacks( $sanitizer_rules['pre_processors'], $html );
⋮----
private function apply_string_callbacks( array $callbacks, string $string ): string {
⋮----
$string = (string) $callback( $string );
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/LegacyRestApiStub.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Automattic\WooCommerce\Utilities\RestApiUtil;
⋮----
class LegacyRestApiStub implements RegisterHooksInterface {
⋮----
private RestApiUtil $rest_api_util;
⋮----
public function register() {
⋮----
final public function init( RestApiUtil $rest_api_util ) {
⋮----
public static function add_rewrite_rules_for_legacy_rest_api_stub() {
⋮----
public static function add_query_vars_for_legacy_rest_api_stub( $vars ) {
⋮----
public static function parse_legacy_rest_api_request() {
⋮----
self::maybe_process_wc_api_query_var();
⋮----
private static function maybe_process_wc_api_query_var() {
⋮----
WC()->payment_gateways();
⋮----
public function get_endpoint_data( $endpoint, $params = array() ) {
⋮----
return $this->rest_api_util->get_endpoint_data( $endpoint, $params );
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/OrderItemMetaUtil.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
use WC_Order_Item;
⋮----
final class OrderItemMetaUtil {
⋮----
public static function get_hidden_keys(): array {
⋮----
public static function get_reserved_keys( WC_Order_Item $item ): array {
⋮----
$internal_meta_keys = (array) $item->get_data_store()->get_internal_meta_keys();
⋮----
return array_values( array_unique( array_merge( self::get_hidden_keys(), $internal_meta_keys ) ) );
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/PluginInstaller.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Automattic\WooCommerce\Utilities\{ PluginUtil, StringUtil };
⋮----
class PluginInstaller implements RegisterHooksInterface {
⋮----
private bool $installing_plugin = false;
⋮----
public function register() {
⋮----
public function install_plugin( string $plugin_url, array $metadata = array() ): array {
⋮----
return $this->install_plugin_core( $plugin_url, $metadata );
⋮----
private function install_plugin_core( string $plugin_url, array $metadata ): array {
if ( ! StringUtil::starts_with( $plugin_url, 'https://downloads.wordpress.org/', false ) ) {
throw new \InvalidArgumentException( "Only installs from the WordPress.org plugins directory (plugin URL starting with 'https://downloads.wordpress.org/') are allowed." );
⋮----
$calling_file = StringUtil::normalize_local_path_slashes( debug_backtrace()[1]['file'] ?? '' ); // [1], not [0], because the immediate caller is the install_plugin method.
if ( ! StringUtil::starts_with( $calling_file, StringUtil::normalize_local_path_slashes( WC_ABSPATH . 'includes/' ) ) && ! StringUtil::starts_with( $calling_file, StringUtil::normalize_local_path_slashes( WC_ABSPATH . 'src/' ) ) ) {
throw new \InvalidArgumentException( "If the value of 'installed_by' is 'WooCommerce', the caller of the method must be a WooCommerce core class or function." );
⋮----
$skin = new \Automatic_Upgrader_Skin();
⋮----
$upgrader = new \Plugin_Upgrader( $skin );
⋮----
$install_ok = $upgrader->install( $plugin_url );
⋮----
$result = array( 'messages' => $skin->get_upgrade_messages() );
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/PostcodeValidation.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
final class PostcodeValidation {
⋮----
private static ?array $rules = null;
⋮----
public static function get_rules(): array {
⋮----
public static function validate( string $postcode, string $country ): ?bool {
$rules = self::get_rules();
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/PriceSeparators.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
class PriceSeparators {
⋮----
public static function get_decimal(): string {
⋮----
public static function get_thousand(): string {
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/ProductUtil.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
use Automattic\WooCommerce\Caches\ProductCountCache;
⋮----
class ProductUtil {
⋮----
public function delete_product_transients_for_products( array $product_ids ): void {
⋮----
$this->delete_product_specific_transients_for_products( $product_ids_to_clear );
⋮----
\WC_Cache_Helper::get_transient_version( 'product', true );
\WC_Cache_Helper::get_transient_version( 'product_query', true );
⋮----
public function delete_product_specific_transients( $product_or_id ) {
$this->delete_product_specific_transients_for_products( array( $product_or_id ) );
⋮----
public function delete_product_specific_transients_for_products( array $products_or_ids ) {
⋮----
$product_id = $product->get_id();
⋮----
$parent_id = $product->get_parent_id();
⋮----
public function prime_image_caches( array $products ): void {
⋮----
$featured  = array_map( static fn( $product ) => $product->get_image_id(), $products );
$gallery   = array_map( static fn( $product ) => $product->get_gallery_image_ids(), $products );
⋮----
public function append_product_sorting_table_join( $join ): string {
⋮----
// A non-empty wpdb prefix prevents a table-name match. Empty prefixes retain the old guard's limitation.
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/Types.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
use InvalidArgumentException;
⋮----
class Types {
⋮----
public static function ensure_instance_of( $thing, string $desired_type, ?callable $on_failure = null ) {
⋮----
$logger->error(
⋮----
return $on_failure( $thing, $desired_type );
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/URL.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
class URL {
⋮----
private $components = array(
⋮----
private $is_absolute;
⋮----
private $is_non_root_directory;
⋮----
private $path_parts = array();
⋮----
private $url;
⋮----
public function __construct( string $url ) {
⋮----
$this->preprocess();
$this->process_path();
⋮----
private function preprocess() {
⋮----
// Windows: capture the drive letter if provided.
⋮----
// Restore the host to null in this situation.
⋮----
private function process_path() {
⋮----
/**
	 * Returns the processed URL as a string.
	 *
... (50 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/URLException.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
use Exception;
⋮----
class URLException extends Exception {}
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/Users.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
use Automattic\WooCommerce\Proxies\LegacyProxy;
use WP_Error, WP_User;
⋮----
class Users {
⋮----
public static function is_site_administrator( int $user_id = 0 ): bool {
⋮----
return is_multisite() ? $user->has_cap( 'manage_sites' ) : $user->has_cap( 'manage_options' );
⋮----
public static function get_user_in_current_site( $user_id, ?int $requesting_user_id = null ) {
⋮----
$legacy_proxy       = wc_get_container()->get( LegacyProxy::class );
⋮----
if ( ! $user instanceof WP_User || ! $user->exists() ) {
⋮----
$legacy_proxy->call_function( 'is_multisite' )
&& ! $legacy_proxy->call_function( 'is_user_member_of_blog', $user->ID )
&& ! $legacy_proxy->call_function( 'user_can', $requesting_user_id, 'manage_network_users' )
⋮----
public static function should_user_verify_order_email( $order_id, $supplied_email = null, $context = 'view' ) {
⋮----
$billing_email = $order->get_billing_email();
$customer_id   = $order->get_customer_id();
⋮----
$date_created              = $order->get_date_created();
⋮----
&& time() - $date_created->getTimestamp() <= $verification_grace_period
⋮----
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/Utilities/WebhookUtil.php">
namespace Automattic\WooCommerce\Internal\Utilities;
⋮----
class WebhookUtil {
⋮----
public function __construct() {
⋮----
public function reassign_webhooks_to_new_user_id( int $old_user_id, ?int $new_user_id ): void {
$webhook_ids = $this->get_webhook_ids_for_user( $old_user_id );
⋮----
$webhook = new \WC_Webhook( $webhook_id );
$webhook->set_user_id( $new_user_id ?? 0 );
$webhook->save();
⋮----
public function maybe_render_user_with_webhooks_warning( \WP_User $current_user, array $userids ): void {
⋮----
$webhook_ids = $this->get_webhook_ids_for_user( $user_id );
⋮----
/* translators: 1 = user id, 2 = user login, 3 = webhooks count */
⋮----
'User #%1$s %2$s has created %3$d WooCommerce webhooks.',
⋮----
if ( $wpdb->get_var( "SELECT ID FROM {$wpdb->posts} WHERE post_author IN( " . implode( ',', $userids ) . ' ) LIMIT 1' ) ) {
⋮----
} elseif ( $wpdb->get_var( "SELECT link_id FROM {$wpdb->links} WHERE link_owner IN( " . implode( ',', $userids ) . ' ) LIMIT 1' ) ) {
⋮----
private function get_webhook_ids_for_user( int $user_id ): array {
$data_store = \WC_Data_Store::load( 'webhook' );
return $data_store->search_webhooks(
</file>

<file path="plugins/woocommerce/src/Internal/VariationGallery/ClassicVariationGalleryAdmin.php">
namespace Automattic\WooCommerce\Internal\VariationGallery;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use WC_Product_Variation;
use WP_Post;
⋮----
class ClassicVariationGalleryAdmin implements RegisterHooksInterface {
⋮----
public function register() {
⋮----
public function enqueue_assets(): void {
if ( ! $this->is_product_edit_screen() ) {
⋮----
$suffix = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min';
⋮----
\WC()->plugin_url() . '/assets/js/admin/variation-gallery' . $suffix . '.js',
⋮----
Constants::get_constant( 'WC_VERSION' ),
⋮----
\WC()->plugin_url() . '/assets/css/variation-gallery-admin.css',
⋮----
Constants::get_constant( 'WC_VERSION' )
⋮----
public function render_variation_gallery_field( int $loop, array $variation_data, WP_Post $variation ): void {
⋮----
$image_ids = $this->get_display_image_ids( $variation_object );
⋮----
<?php echo esc_html( $this->get_count_text( $count ) ); ?>
⋮----
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/VariationGallery/LegacyVariationGalleryCompatibility.php">
namespace Automattic\WooCommerce\Internal\VariationGallery;
⋮----
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use WC_Product_Variation;
⋮----
class LegacyVariationGalleryCompatibility implements RegisterHooksInterface {
⋮----
public static function get_core_managed_meta_key(): string {
⋮----
public static function mark_core_managed( WC_Product_Variation $variation ): void {
if ( ! metadata_exists( 'post', $variation->get_id(), self::LEGACY_META_KEY ) ) {
⋮----
$variation->update_meta_data( self::LEGACY_FALLBACK_DISABLED_META_KEY, 'yes' );
⋮----
public static function mark_variation_id_core_managed( int $variation_id ): void {
⋮----
public static function is_variation_id_core_managed( int $variation_id ): bool {
⋮----
public function register() {
⋮----
public function maybe_read_legacy_gallery_image_ids( $gallery_image_ids, WC_Product_Variation $variation ): array {
⋮----
if ( self::is_variation_id_core_managed( $variation->get_id() ) ) {
⋮----
$legacy_gallery_image_ids = get_post_meta( $variation->get_id(), self::LEGACY_META_KEY, true );
</file>

<file path="plugins/woocommerce/src/Internal/VariationGallery/Migration.php">
namespace Automattic\WooCommerce\Internal\VariationGallery;
⋮----
class Migration {
⋮----
public static function run(): bool {
⋮----
$fallback_disabled    = LegacyVariationGalleryCompatibility::get_core_managed_meta_key();
⋮----
$query = $wpdb->prepare(
⋮----
return array_map( 'intval', $wpdb->get_col( $query ) );
⋮----
$variation_ids = $select_variation_ids( self::BATCH_SIZE );
⋮----
LegacyVariationGalleryCompatibility::mark_variation_id_core_managed( $variation_id );
⋮----
$has_more = ! empty( $select_variation_ids( 1 ) );
⋮----
Telemetry::record_event( Telemetry::EVENT_MIGRATION_COMPLETED );
</file>

<file path="plugins/woocommerce/src/Internal/VariationGallery/Package.php">
namespace Automattic\WooCommerce\Internal\VariationGallery;
⋮----
class Package {
⋮----
public static function is_in_canary_cohort(): bool {
⋮----
return self::is_enabled();
⋮----
public static function is_enabled() {
⋮----
public static function prepare(): void {
⋮----
final public static function init(): void {
⋮----
$container->get( ClassicVariationGalleryAdmin::class )->register();
$container->get( LegacyVariationGalleryCompatibility::class )->register();
⋮----
public static function maybe_schedule_migration(): void {
⋮----
if ( self::has_pending_or_running_migration( $args ) ) {
⋮----
WC()->queue()->add(
⋮----
private static function has_pending_or_running_migration( array $args ): bool {
if ( null !== WC()->queue()->get_next( self::UPDATE_CALLBACK_HOOK, $args, self::UPDATE_CALLBACK_GROUP ) ) {
⋮----
$running_actions = WC()->queue()->search(
</file>

<file path="plugins/woocommerce/src/Internal/VariationGallery/Telemetry.php">
namespace Automattic\WooCommerce\Internal\VariationGallery;
⋮----
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
⋮----
class Telemetry implements RegisterHooksInterface {
⋮----
public function register() {
⋮----
public function add_snapshot_to_tracker_data( array $data ): array {
$data['variation_gallery'] = self::collect_snapshot();
⋮----
public static function collect_snapshot(): array {
⋮----
$legacy_plugin_active = self::is_legacy_plugin_active();
⋮----
$migrated_variation_count = (int) $wpdb->get_var(
$wpdb->prepare(
⋮----
LegacyVariationGalleryCompatibility::get_core_managed_meta_key()
⋮----
$variation_gallery_rows = $wpdb->get_col(
⋮----
$authored_without_legacy_count = (int) $wpdb->get_var(
⋮----
public static function record_event( string $event_name, array $properties = array() ): void {
⋮----
private static function is_legacy_plugin_active(): bool {
</file>

<file path="plugins/woocommerce/src/Internal/WCCom/ConnectionHelper.php">
namespace Automattic\WooCommerce\Internal\WCCom;
⋮----
final class ConnectionHelper {
⋮----
public static function is_connected() {
</file>

<file path="plugins/woocommerce/src/Internal/AssignDefaultCategory.php">
namespace Automattic\WooCommerce\Internal;
⋮----
class AssignDefaultCategory {
⋮----
final public function init() {
⋮----
public function schedule_action() {
WC()->queue()->schedule_single(
⋮----
public function maybe_assign_default_product_cat() {
⋮----
$affected_rows = $wpdb->query(
$wpdb->prepare(
</file>

<file path="plugins/woocommerce/src/Internal/Brands.php">
namespace Automattic\WooCommerce\Internal;
⋮----
class Brands {
⋮----
final public static function init() {
⋮----
if ( ! self::is_enabled() ) {
⋮----
public static function is_enabled() {
⋮----
public static function prepare() {
</file>

<file path="plugins/woocommerce/src/Internal/DownloadPermissionsAdjuster.php">
namespace Automattic\WooCommerce\Internal;
⋮----
use Automattic\WooCommerce\Proxies\LegacyProxy;
use WC_Product;
⋮----
class DownloadPermissionsAdjuster {
⋮----
private $downloads_data_store;
⋮----
final public function init() {
$this->downloads_data_store = wc_get_container()->get( LegacyProxy::class )->get_instance_of( \WC_Data_Store::class, 'customer-download' );
⋮----
public function maybe_schedule_adjust_download_permissions( \WC_Product $product ) {
$children_ids = $product->get_children();
⋮----
if ( $child && $child->is_downloadable() ) {
⋮----
if ( ! $product->is_downloadable() && ! $are_any_children_downloadable ) {
⋮----
$scheduled_action_args = array( $product->get_id() );
⋮----
WC()->call_function(
⋮----
WC()->call_function( 'time' ) + 1,
⋮----
public function adjust_download_permissions( int $product_id ) {
⋮----
$parent_downloads = $this->get_download_files_and_permissions( $product );
⋮----
wc_get_logger()->warning(
... (15 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/McStats.php">
namespace Automattic\WooCommerce\Internal;
⋮----
use Automattic\Jetpack\A8c_Mc_Stats;
⋮----
class McStats extends A8c_Mc_Stats {
⋮----
public function get_group_query_args( $group_name ) {
$stats = $this->get_current_stats();
⋮----
public function do_stats() {
if ( ! \WC_Site_Tracking::is_tracking_enabled() ) {
⋮----
parent::do_stats();
⋮----
public function do_server_side_stat( $url ) {
⋮----
return parent::do_server_side_stat( $url );
⋮----
public function do_server_side_stats() {
⋮----
parent::do_server_side_stats();
</file>

<file path="plugins/woocommerce/src/Internal/OrderCouponDataMigrator.php">
namespace Automattic\WooCommerce\Internal;
⋮----
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessingController;
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessorInterface;
use Automattic\WooCommerce\Utilities\StringUtil;
use \Exception;
⋮----
class OrderCouponDataMigrator implements BatchProcessorInterface, RegisterHooksInterface {
⋮----
public function register() {
⋮----
public function get_name(): string {
⋮----
public function get_description(): string {
⋮----
public function get_total_pending_count(): int {
⋮----
return $wpdb->get_var(
$wpdb->prepare(
⋮----
public function get_next_batch_to_process( int $size ): array {
⋮----
$meta_ids = $wpdb->get_col(
⋮----
public function process_batch( array $batch ): void {
⋮----
$meta_ids = StringUtil::to_sql_list( $batch );
⋮----
$meta_ids_and_values = $wpdb->get_results(
⋮----
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/README.md">
# The internal namespace

All the code in this directory (and hence in the `Automattic\WooCommerce\Internal` namespace) is internal WooCommerce infrastructure code and not intended to be used by extensions. The important thing that this implies is that **backwards compatibility of the public surface for classes in this namespace is not guaranteed in future releases of WooCommerce**.

Therefore **extensions developers should never use classes in this namespace directly in their code**. See [the README file for the src folder](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/README.md#the-internal-namespace) for more detailed guidance.

Note that this applies to all the code entities in this namespace, even those not having an `@internal` annotation.
</file>

<file path="plugins/woocommerce/src/Internal/RegisterHooksInterface.php">
namespace Automattic\WooCommerce\Internal;
⋮----
interface RegisterHooksInterface {
⋮----
public function register();
</file>

<file path="plugins/woocommerce/src/Internal/RestApiControllerBase.php">
namespace Automattic\WooCommerce\Internal;
⋮----
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Automattic\WooCommerce\Utilities\StringUtil;
use WP_HTTP_Response;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use InvalidArgumentException;
use Exception;
⋮----
abstract class RestApiControllerBase implements RegisterHooksInterface {
⋮----
protected string $route_namespace = 'wc/v3';
⋮----
public function register() {
⋮----
public function handle_woocommerce_rest_api_get_rest_namespaces( array $namespaces ): array {
$namespaces['wc/v3'][ $this->get_rest_api_namespace() ] = static::class;
⋮----
abstract protected function get_rest_api_namespace(): string;
⋮----
abstract public function register_routes();
⋮----
protected function run( WP_REST_Request $request, string $method_name ) {
⋮----
$message = $ex->getMessage();
⋮----
wc_get_logger()->error( StringUtil::class_name_without_namespace( static::class ) . ": when executing method $method_name: {$ex->getMessage()}" );
return $this->internal_wp_error( $ex );
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/RestApiParameterUtil.php">
namespace Automattic\WooCommerce\Internal;
⋮----
class RestApiParameterUtil {
⋮----
public static function adjust_create_refund_request_parameters( \WP_REST_Request &$request ) {
⋮----
$request['line_items'] = self::adjust_line_items_for_create_refund_request( $request['line_items'] );
⋮----
$amount = self::calculate_refund_amount_from_line_items( $request );
⋮----
private static function calculate_refund_amount_from_line_items( $request ) {
⋮----
private static function adjust_line_items_for_create_refund_request( $line_items ) {
if ( ! is_array( $line_items ) || empty( $line_items ) || self::is_associative( $line_items ) ) {
⋮----
$item['refund_tax'] = self::adjust_taxes_for_create_refund_request_line_item( $item['refund_tax'] );
⋮----
private static function adjust_taxes_for_create_refund_request_line_item( $taxes_array ) {
if ( ! is_array( $taxes_array ) || empty( $taxes_array ) || self::is_associative( $taxes_array ) ) {
⋮----
private static function is_associative( array $the_array ) {
</file>

<file path="plugins/woocommerce/src/Internal/RestockRefundedItemsAdjuster.php">
namespace Automattic\WooCommerce\Internal;
⋮----
use Automattic\WooCommerce\Enums\OrderItemType;
use Automattic\WooCommerce\Proxies\LegacyProxy;
⋮----
class RestockRefundedItemsAdjuster {
⋮----
private $order_factory;
⋮----
final public function init() {
$this->order_factory = wc_get_container()->get( LegacyProxy::class )->get_instance_of( \WC_Order_Factory::class );
⋮----
public function initialize_restock_refunded_items( $order_id, $items ) {
⋮----
$order_version = $order->get_version();
⋮----
if ( 0 === count( $order->get_refunds() ) ) {
⋮----
$item = $this->order_factory::get_order_item( absint( $item_id ) );
⋮----
if ( OrderItemType::LINE_ITEM !== $item->get_type() ) {
⋮----
if ( '' !== $item->get_meta( '_restock_refunded_items', true ) ) {
⋮----
$refunded_item_quantity = abs( $order->get_qty_refunded_for_item( $item->get_id() ) );
$item->add_meta_data( '_restock_refunded_items', $refunded_item_quantity, false );
$item->save();
</file>

<file path="plugins/woocommerce/src/Internal/ScheduledSalePriceReconciler.php">
namespace Automattic\WooCommerce\Internal;
⋮----
use WC_Product;
⋮----
class ScheduledSalePriceReconciler implements RegisterHooksInterface {
⋮----
public function register(): void {
⋮----
public function reconcile_price( $price, $product ) {
⋮----
// Fast path: products with no sale price (the vast majority, plus variable/grouped
// parents whose own sale price is empty) can never drift out of sync.
$sale_price = $product->get_sale_price( 'edit' );
⋮----
// Only scheduled sales can drift: an unscheduled sale's price is fixed at save time.
$date_from = $product->get_date_on_sale_from( 'edit' );
$date_to   = $product->get_date_on_sale_to( 'edit' );
⋮----
$regular_price = $product->get_regular_price( 'edit' );
⋮----
// Respect third-party prices: if another callback already changed the price away from
// the stored value, leave it alone. This is deliberate even for ambient transforms
// such as currency conversion: by this priority the price is already transformed, and
// returning a raw sale/regular price would bypass the transform, which cannot be
// re-applied from here. Those stores keep their pre-existing behavior during the gap.
// The 'edit' context returns the raw stored price without re-applying this filter, so
⋮----
$stored_price = $product->get_price( 'edit' );
⋮----
$within_window = ! ( ( $date_from && $date_from->getTimestamp() > $now ) || ( $date_to && $date_to->getTimestamp() < $now ) );
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/src/Internal/TermCount.php">
namespace Automattic\WooCommerce\Internal;
⋮----
use Automattic\WooCommerce\Enums\ProductStockStatus;
⋮----
class TermCount {
⋮----
final public function init(): void {
⋮----
public function handle_set_object_terms( $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ): void {
⋮----
$new_tt_ids      = $this->normalize_ids( $tt_ids );
$old_tt_ids      = $this->normalize_ids( $old_tt_ids );
$counting_tt_ids = $this->get_count_affecting_visibility_term_taxonomy_ids();
⋮----
public function handle_deleted_term_relationships( $object_id, $tt_ids, $taxonomy ): void {
⋮----
$this->normalize_ids( $tt_ids ),
$this->get_count_affecting_visibility_term_taxonomy_ids()
⋮----
private function get_count_affecting_visibility_term_taxonomy_ids(): array {
⋮----
return $this->normalize_ids( $counting_tt_ids );
⋮----
private function normalize_ids( array $ids ): array {
</file>

<file path="plugins/woocommerce/src/LayoutTemplates/LayoutTemplateRegistry.php">
namespace Automattic\WooCommerce\LayoutTemplates;
⋮----
final class LayoutTemplateRegistry {
⋮----
private static $instance = null;
⋮----
private static $removal_warning_logged = false;
⋮----
public function __construct() {
self::maybe_log_removal_warning();
⋮----
public static function get_instance(): LayoutTemplateRegistry {
⋮----
public function unregister_all() {
⋮----
public function is_registered( $layout_template_id ): bool {
⋮----
public function register( $layout_template_id, $layout_template_area, $layout_template_class_name ) {
⋮----
public function instantiate_layout_templates( array $query_params = array() ): array {
⋮----
private static function maybe_log_removal_warning(): void {
⋮----
wc_get_logger()->warning(
</file>

<file path="plugins/woocommerce/src/Proxies/ActionsProxy.php">
namespace Automattic\WooCommerce\Proxies;
⋮----
class ActionsProxy {
⋮----
public function did_action( $tag ) {
⋮----
public function apply_filters( $tag, $value, ...$parameters ) {
</file>

<file path="plugins/woocommerce/src/Proxies/LegacyProxy.php">
namespace Automattic\WooCommerce\Proxies;
⋮----
use Automattic\WooCommerce\Internal\DependencyManagement\Definition;
use Automattic\WooCommerce\Utilities\StringUtil;
⋮----
class LegacyProxy {
⋮----
public function get_instance_of( string $class_name, ...$args ) {
if ( StringUtil::starts_with( $class_name, 'Automattic\\WooCommerce\\' ) ) {
throw new \Exception(
⋮----
// If a class has a dedicated method to obtain a instance, use it.
⋮----
return $class_name::instance( ...$args );
⋮----
return $class_name::load( ...$args );
⋮----
return new $class_name( ...$args );
⋮----
private function get_instance_of_wc_queue_interface() {
return \WC_Queue::instance();
⋮----
public function call_function( $function_name, ...$parameters ) {
⋮----
public function call_static( $class_name, $method_name, ...$parameters ) {
⋮----
public function get_global( string $global_name ) {
⋮----
public function exit( $status = '' ) {
</file>

<file path="plugins/woocommerce/src/StoreApi/docs/rate-limiting.md">
The docs for this file have been moved [here](https://github.com/woocommerce/woocommerce/blob/trunk/docs/apis/store-api/rate-limiting.md)
</file>

<file path="plugins/woocommerce/src/StoreApi/Exceptions/InvalidCartException.php">
namespace Automattic\WooCommerce\StoreApi\Exceptions;
⋮----
use WP_Error;
⋮----
class InvalidCartException extends \Exception {
⋮----
public $error_code;
⋮----
public $additional_data = [];
⋮----
public $error;
⋮----
public function __construct( $error_code, WP_Error $error, $additional_data = [] ) {
⋮----
parent::__construct( '', 409 );
⋮----
public function getErrorCode() {
⋮----
public function getError() {
⋮----
public function getAdditionalData() {
</file>

<file path="plugins/woocommerce/src/StoreApi/Exceptions/InvalidStockLevelsInCartException.php">
namespace Automattic\WooCommerce\StoreApi\Exceptions;
⋮----
use WP_Error;
⋮----
class InvalidStockLevelsInCartException extends \Exception {
⋮----
public $error_code;
⋮----
public $additional_data = [];
⋮----
public $error;
⋮----
public function __construct( $error_code, $error, $additional_data = [] ) {
⋮----
parent::__construct( '', 409 );
⋮----
public function getErrorCode() {
⋮----
public function getError() {
⋮----
public function getAdditionalData() {
</file>

<file path="plugins/woocommerce/src/StoreApi/Exceptions/NotPurchasableException.php">
namespace Automattic\WooCommerce\StoreApi\Exceptions;
⋮----
class NotPurchasableException extends StockAvailabilityException {}
</file>

<file path="plugins/woocommerce/src/StoreApi/Exceptions/OutOfStockException.php">
namespace Automattic\WooCommerce\StoreApi\Exceptions;
⋮----
class OutOfStockException extends StockAvailabilityException {}
</file>

<file path="plugins/woocommerce/src/StoreApi/Exceptions/PartialOutOfStockException.php">
namespace Automattic\WooCommerce\StoreApi\Exceptions;
⋮----
class PartialOutOfStockException extends StockAvailabilityException {}
</file>

<file path="plugins/woocommerce/src/StoreApi/Exceptions/RouteException.php">
namespace Automattic\WooCommerce\StoreApi\Exceptions;
⋮----
class RouteException extends \Exception {
⋮----
public $error_code;
⋮----
public $additional_data = [];
⋮----
public function __construct( $error_code, $message, $http_status_code = 400, $additional_data = [] ) {
⋮----
parent::__construct( $message, $http_status_code );
⋮----
public function getErrorCode() {
⋮----
public function getAdditionalData() {
</file>

<file path="plugins/woocommerce/src/StoreApi/Exceptions/StockAvailabilityException.php">
namespace Automattic\WooCommerce\StoreApi\Exceptions;
⋮----
class StockAvailabilityException extends \Exception {
⋮----
public $error_code;
⋮----
public $product_name;
⋮----
public $additional_data = [];
⋮----
public function __construct( $error_code, $product_name, $additional_data = [] ) {
⋮----
parent::__construct();
⋮----
public function getErrorCode() {
⋮----
public function getAdditionalData() {
⋮----
public function getProductName() {
</file>

<file path="plugins/woocommerce/src/StoreApi/Exceptions/TooManyInCartException.php">
namespace Automattic\WooCommerce\StoreApi\Exceptions;
⋮----
class TooManyInCartException extends StockAvailabilityException {}
</file>

<file path="plugins/woocommerce/src/StoreApi/Formatters/CurrencyFormatter.php">
namespace Automattic\WooCommerce\StoreApi\Formatters;
⋮----
use Automattic\WooCommerce\Enums\CurrencyPosition;
use Automattic\WooCommerce\Internal\Utilities\PriceSeparators;
⋮----
class CurrencyFormatter implements FormatterInterface {
⋮----
public function format( $value, array $options = [] ) {
⋮----
'currency_decimal_separator'  => PriceSeparators::get_decimal(),
'currency_thousand_separator' => PriceSeparators::get_thousand(),
</file>

<file path="plugins/woocommerce/src/StoreApi/Formatters/DefaultFormatter.php">
namespace Automattic\WooCommerce\StoreApi\Formatters;
⋮----
class DefaultFormatter implements FormatterInterface {
⋮----
public function format( $value, array $options = [] ) {
</file>

<file path="plugins/woocommerce/src/StoreApi/Formatters/FormatterInterface.php">
namespace Automattic\WooCommerce\StoreApi\Formatters;
⋮----
interface FormatterInterface {
⋮----
public function format( $value, array $options = [] );
</file>

<file path="plugins/woocommerce/src/StoreApi/Formatters/HtmlFormatter.php">
namespace Automattic\WooCommerce\StoreApi\Formatters;
⋮----
class HtmlFormatter implements FormatterInterface {
⋮----
public function format( $value, array $options = [] ) {
</file>

<file path="plugins/woocommerce/src/StoreApi/Formatters/MoneyFormatter.php">
namespace Automattic\WooCommerce\StoreApi\Formatters;
⋮----
class MoneyFormatter implements FormatterInterface {
⋮----
public function format( $value, array $options = [] ) {
</file>

<file path="plugins/woocommerce/src/StoreApi/Payments/PaymentContext.php">
namespace Automattic\WooCommerce\StoreApi\Payments;
⋮----
class PaymentContext {
⋮----
protected $payment_method = '';
⋮----
/**
	 * Order object for the order being paid.
	 *
	 * @var \WC_Order
	 */
protected $order;
⋮----
/**
	 * Holds data to send to the payment gateway to support payment.
	 *
	 * @var array Key value pairs.
	 */
protected $payment_data = [];
⋮----
/**
	 * Magic getter for protected properties.
	 *
	 * @param string $name Property name.
	 */
public function __get( $name ) {
⋮----
public function set_payment_method( $payment_method ) {
⋮----
public function get_payment_method_instance() {
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Payments/PaymentResult.php">
namespace Automattic\WooCommerce\StoreApi\Payments;
⋮----
class PaymentResult {
⋮----
protected $valid_statuses = [ 'success', 'failure', 'pending', 'error' ];
⋮----
protected $status = '';
⋮----
/**
	 * Array of details about the payment.
	 *
	 * @var string
	 */
protected $payment_details = [];
⋮----
/**
	 * Redirect URL for checkout.
	 *
	 * @var string
	 */
protected $redirect_url = '';
⋮----
/**
	 * Constructor.
	 *
	 * @param string $status Sets the payment status for the result.
	 */
public function __construct( $status = '' ) {
⋮----
$this->set_status( $status );
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/AI/Middleware.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1\AI;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class Middleware {}
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/AI/Products.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1\AI;
⋮----
class Products {}
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/AbstractCartRoute.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Schemas\V1\AbstractSchema;
use Automattic\WooCommerce\StoreApi\Schemas\V1\CartItemSchema;
use Automattic\WooCommerce\StoreApi\Schemas\V1\CartSchema;
use Automattic\WooCommerce\StoreApi\SessionHandler;
use Automattic\WooCommerce\StoreApi\Utilities\CartController;
use Automattic\WooCommerce\StoreApi\Utilities\DraftOrderTrait;
use Automattic\WooCommerce\StoreApi\Utilities\OrderController;
use Automattic\WooCommerce\StoreApi\Utilities\CartTokenUtils;
⋮----
abstract class AbstractCartRoute extends AbstractRoute {
⋮----
protected $schema;
⋮----
protected $cart_schema;
⋮----
protected $cart_item_schema;
⋮----
protected $cart_controller;
⋮----
protected $order_controller;
⋮----
protected $additional_fields_controller;
⋮----
protected $has_cart_token = null;
... (90 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/AbstractRoute.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Routes\RouteInterface;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\Exceptions\InvalidCartException;
use Automattic\WooCommerce\StoreApi\Schemas\V1\AbstractSchema;
use WP_Error;
⋮----
abstract class AbstractRoute implements RouteInterface {
⋮----
protected $schema;
⋮----
protected $namespace = 'wc/store/v1';
⋮----
protected $schema_controller;
⋮----
/**
	 * The routes schema version.
	 *
	 * @var integer
	 */
⋮----
/**
	 * Constructor.
	 *
	 * @param SchemaController $schema_controller Schema Controller instance.
	 * @param AbstractSchema   $schema Schema class for this route.
	 */
public function __construct( SchemaController $schema_controller, AbstractSchema $schema ) {
... (94 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/AbstractTermsRoute.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Utilities\Pagination;
use WP_Term_Query;
⋮----
abstract class AbstractTermsRoute extends AbstractRoute {
⋮----
public function get_collection_params() {
⋮----
$params['context']            = $this->get_context_param();
⋮----
protected function get_terms_response( $taxonomy, $request ) {
⋮----
$objects    = $term_query->query( $prepared_args );
⋮----
$data     = $this->prepare_item_for_response( $object, $request );
$return[] = $this->prepare_response_for_collection( $data );
⋮----
$term_count = $this->get_term_count( $taxonomy, $prepared_args );
$response   = ( new Pagination() )->add_headers( $response, $request, $term_count, ceil( $term_count / $per_page ) );
⋮----
protected function get_term_count( $taxonomy, $args ) {
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/Batch.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Routes\RouteInterface;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Batch extends AbstractRoute implements RouteInterface {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
public function get_response( WP_REST_Request $request ) {
⋮----
$response = rest_get_server()->serve_batch_request_v1( $request );
⋮----
$response = $this->get_route_error_response( $error->getErrorCode(), $error->getMessage(), $error->getCode(), $error->getAdditionalData() );
⋮----
$response = $this->get_route_error_response( 'woocommerce_rest_unknown_server_error', $error->getMessage(), 500 );
⋮----
$response = $this->error_to_response( $response );
⋮----
$response->header( 'Nonce', $nonce );
$response->header( 'Nonce-Timestamp', time() );
$response->header( 'User-ID', get_current_user_id() );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/Cart.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
class Cart extends AbstractCartRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
return rest_ensure_response( $this->schema->get_item_response( $this->cart_controller->get_cart_for_response() ) );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/CartAddItem.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class CartAddItem extends AbstractCartRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
protected function get_route_post_response( \WP_REST_Request $request ) {
⋮----
$item_id   = $this->cart_controller->add_to_cart( $add_to_cart_data );
$cart      = $this->cart_controller->get_cart_instance();
$cart_item = $cart->get_cart_item( $item_id );
⋮----
$response = rest_ensure_response( $this->schema->get_item_response( $this->cart_controller->get_cart_for_response() ) );
$response->set_status( 201 );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/CartApplyCoupon.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class CartApplyCoupon extends AbstractCartRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
protected function get_route_post_response( \WP_REST_Request $request ) {
⋮----
$this->cart_controller->apply_coupon( $coupon_code );
⋮----
throw new RouteException( $e->getErrorCode(), $e->getMessage(), $e->getCode() );
⋮----
return rest_ensure_response( $this->schema->get_item_response( $this->cart_controller->get_cart_for_response() ) );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/CartCoupons.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class CartCoupons extends AbstractCartRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
⋮----
'args'                => $this->schema->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE ),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
$cart_coupons = $this->cart_controller->get_cart_coupons();
⋮----
$response = rest_ensure_response( $this->schema->get_item_response( $coupon_code ) );
$response->add_links( $this->prepare_links( $coupon_code, $request ) );
⋮----
$response = $this->prepare_response_for_collection( $response );
⋮----
protected function get_route_post_response( \WP_REST_Request $request ) {
⋮----
$this->cart_controller->apply_coupon( $request['code'] );
⋮----
throw new RouteException( $e->getErrorCode(), $e->getMessage(), $e->getCode() );
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/CartCouponsByCode.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class CartCouponsByCode extends AbstractCartRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
if ( ! $this->cart_controller->has_coupon( $request['code'] ) ) {
⋮----
return $this->prepare_item_for_response( $request['code'], $request );
⋮----
protected function get_route_delete_response( \WP_REST_Request $request ) {
⋮----
$cart = $this->cart_controller->get_cart_instance();
$cart->remove_coupon( $request['code'] );
⋮----
return new \WP_REST_Response( null, 204 );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/CartExtensions.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class CartExtensions extends AbstractCartRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
protected function get_route_post_response( \WP_REST_Request $request ) {
⋮----
return $this->schema->get_item_response( $request );
⋮----
throw new RouteException( $e->getErrorCode(), $e->getMessage(), $e->getCode() );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/CartItems.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class CartItems extends AbstractCartRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
⋮----
'args'                => $this->schema->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE ),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
$cart_items = $this->cart_controller->get_cart_items();
⋮----
$data    = $this->prepare_item_for_response( $cart_item, $request );
$items[] = $this->prepare_response_for_collection( $data );
⋮----
protected function get_route_post_response( \WP_REST_Request $request ) {
⋮----
$result = $this->cart_controller->add_to_cart(
⋮----
$response = rest_ensure_response( $this->prepare_item_for_response( $this->cart_controller->get_cart_item( $result ), $request ) );
$response->set_status( 201 );
⋮----
... (7 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/CartItemsByKey.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class CartItemsByKey extends AbstractCartRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
⋮----
'args'                => $this->schema->get_endpoint_args_for_item_schema( \WP_REST_Server::EDITABLE ),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
$cart_item = $this->cart_controller->get_cart_item( $request['key'] );
⋮----
$data     = $this->prepare_item_for_response( $cart_item, $request );
⋮----
protected function get_route_update_response( \WP_REST_Request $request ) {
$cart = $this->cart_controller->get_cart_instance();
⋮----
$this->cart_controller->set_cart_item_quantity( $request['key'], $request['quantity'] );
⋮----
return rest_ensure_response( $this->prepare_item_for_response( $this->cart_controller->get_cart_item( $request['key'] ), $request ) );
⋮----
protected function get_route_delete_response( \WP_REST_Request $request ) {
... (9 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/CartRemoveCoupon.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class CartRemoveCoupon extends AbstractCartRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
protected function get_route_post_response( \WP_REST_Request $request ) {
⋮----
$cart        = $this->cart_controller->get_cart_instance();
⋮----
$coupon      = new \WC_Coupon( $coupon_code );
$discounts   = new \WC_Discounts( $cart );
⋮----
if ( ! wc_is_same_coupon( $coupon->get_code(), $coupon_code ) || is_wp_error( $discounts->is_coupon_valid( $coupon ) ) ) {
⋮----
if ( ! $this->cart_controller->has_coupon( $coupon_code ) ) {
⋮----
$cart = $this->cart_controller->get_cart_instance();
$cart->remove_coupon( $coupon_code );
⋮----
return rest_ensure_response( $this->schema->get_item_response( $cart ) );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/CartRemoveItem.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Utilities\DraftOrderTrait;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class CartRemoveItem extends AbstractCartRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
protected function get_route_post_response( \WP_REST_Request $request ) {
$cart      = $this->cart_controller->get_cart_instance();
$cart_item = $this->cart_controller->get_cart_item( $request['key'] );
⋮----
$removed = $cart->remove_cart_item( $request['key'] );
⋮----
$this->maybe_release_stock();
⋮----
return rest_ensure_response( $this->schema->get_item_response( $cart ) );
⋮----
protected function maybe_release_stock() {
$draft_order_id = $this->get_draft_order_id();
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/CartSelectShippingRate.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class CartSelectShippingRate extends AbstractCartRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
protected function get_route_post_response( \WP_REST_Request $request ) {
⋮----
$cart       = $this->cart_controller->get_cart_instance();
⋮----
$this->cart_controller->select_shipping_rate( $package_id, $rate_id );
⋮----
foreach ( $this->cart_controller->get_shipping_packages() as $package ) {
$this->cart_controller->select_shipping_rate( $package['package_id'], $rate_id );
⋮----
throw new RouteException( $e->getErrorCode(), $e->getMessage(), $e->getCode() );
⋮----
$cart->calculate_totals();
⋮----
return rest_ensure_response( $this->cart_schema->get_item_response( $cart ) );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/CartUpdateCustomer.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Utilities\DraftOrderTrait;
⋮----
class CartUpdateCustomer extends AbstractCartRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'properties'        => $this->schema->billing_address_schema->get_properties(),
⋮----
'properties'        => $this->schema->shipping_address_schema->get_properties(),
⋮----
protected function validate_address_params( $request, $billing, $shipping ) {
⋮----
$billing_validation_check = $this->schema->billing_address_schema->validate_callback( $billing, $request, 'billing_address' );
⋮----
$invalid_params['billing_address']  = implode( ' ', $billing_validation_check->get_error_messages() );
$invalid_details['billing_address'] = \rest_convert_error_to_response( $billing_validation_check )->get_data();
⋮----
$shipping_validation_check = $this->schema->shipping_address_schema->validate_callback( $shipping, $request, 'shipping_address' );
⋮----
$invalid_params['shipping_address']  = implode( ' ', $shipping_validation_check->get_error_messages() );
$invalid_details['shipping_address'] = \rest_convert_error_to_response( $shipping_validation_check )->get_data();
⋮----
return new \WP_Error(
... (57 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/CartUpdateItem.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
class CartUpdateItem extends AbstractCartRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
protected function get_route_post_response( \WP_REST_Request $request ) {
$cart = $this->cart_controller->get_cart_instance();
⋮----
$cart_item    = $cart->get_cart_item( $request['key'] );
⋮----
$this->cart_controller->set_cart_item_quantity( $request['key'], $new_quantity );
⋮----
return rest_ensure_response( $this->schema->get_item_response( $cart ) );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/Checkout.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Payments\PaymentResult;
use Automattic\WooCommerce\StoreApi\Exceptions\InvalidCartException;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\Utilities\DraftOrderTrait;
use Automattic\WooCommerce\Checkout\Helpers\ReserveStockException;
use Automattic\WooCommerce\StoreApi\Utilities\CheckoutTrait;
⋮----
class Checkout extends AbstractCartRoute {
⋮----
private $order = null;
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
protected function requires_nonce( \WP_REST_Request $request ) {
return ! $this->has_cart_token( $request );
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
⋮----
$this->schema->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE )
⋮----
$this->schema->get_endpoint_args_for_item_schema( \WP_REST_Server::EDITABLE )
⋮----
public function get_response( \WP_REST_Request $request ) {
... (224 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/CheckoutOrder.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Payments\PaymentResult;
use Automattic\WooCommerce\StoreApi\Exceptions\InvalidStockLevelsInCartException;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\Utilities\OrderAuthorizationTrait;
use Automattic\WooCommerce\StoreApi\Utilities\CheckoutTrait;
⋮----
class CheckoutOrder extends AbstractCartRoute {
⋮----
private $order = null;
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
$this->schema->get_endpoint_args_for_item_schema( \WP_REST_Server::CREATABLE )
⋮----
protected function get_route_post_response( \WP_REST_Request $request ) {
⋮----
if ( ! $order instanceof \WC_Order || ! $order->needs_payment() ) {
return new \WP_Error(
⋮----
$this->update_billing_address( $request );
$this->update_order_from_request( $request );
⋮----
$this->process_customer( $request );
... (32 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/Order.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Schemas\V1\AbstractSchema;
use Automattic\WooCommerce\StoreApi\Utilities\OrderController;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\Utilities\OrderAuthorizationTrait;
⋮----
class Order extends AbstractRoute {
⋮----
protected $order_controller;
⋮----
public function __construct( SchemaController $schema_controller, AbstractSchema $schema ) {
parent::__construct( $schema_controller, $schema );
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param( [ 'default' => 'view' ] ),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
⋮----
return rest_ensure_response( $this->schema->get_item_response( wc_get_order( $order_id ) ) );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/Patterns.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\Blocks\BlockPatterns;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Patterns\PTKClient;
use Automattic\WooCommerce\Blocks\Patterns\PTKPatternsStore;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Exception;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
⋮----
class Patterns extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
protected function get_route_response( WP_REST_Request $request ) {
$ptk_client = Package::container()->get( PTKClient::class );
⋮----
$response = $ptk_client->fetch_patterns(
⋮----
wp_kses( $response->get_error_message(), array() ),
wp_kses( $response->get_error_code(), array() )
⋮----
protected function get_route_post_response( WP_REST_Request $request ) {
... (8 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ProductAttributes.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
class ProductAttributes extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
⋮----
$data     = $this->prepare_item_for_response( $object, $request );
$return[] = $this->prepare_response_for_collection( $data );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ProductAttributesById.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class ProductAttributesById extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param(
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
⋮----
$data     = $this->prepare_item_for_response( $object, $request );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ProductAttributeTerms.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\Internal\ProductAttributes\VisualAttributeTermMeta;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\Schemas\V1\ProductAttributeTermSchema;
⋮----
class ProductAttributeTerms extends AbstractTermsRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
public function get_collection_params() {
$params                          = parent::get_collection_params();
⋮----
public function prepare_item_for_response( $item, \WP_REST_Request $request ) {
$response = parent::prepare_item_for_response( $item, $request );
⋮----
! VisualAttributeTermMeta::is_visual_attribute_taxonomy( $item->taxonomy )
⋮----
$data = $response->get_data();
⋮----
$data[ ProductAttributeTermSchema::VISUAL_PROPERTY_NAME ] = VisualAttributeTermMeta::get_term_visual(
⋮----
$response->set_data( $data );
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ProductBrands.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
class ProductBrands extends AbstractTermsRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
return $this->get_terms_response( 'product_brand', $request );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ProductBrandsById.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class ProductBrandsById extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param(
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
⋮----
$data = $this->prepare_item_for_response( $object, $request );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ProductCategories.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
class ProductCategories extends AbstractTermsRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
return $this->get_terms_response( 'product_cat', $request );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ProductCategoriesById.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class ProductCategoriesById extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param(
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
⋮----
$data = $this->prepare_item_for_response( $object, $request );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ProductCollectionData.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Utilities\ProductQueryFilters;
⋮----
class ProductCollectionData extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
⋮----
$filter_request->set_param( 'min_price', null );
$filter_request->set_param( 'max_price', null );
⋮----
$price_results     = $filters->get_filtered_price( $filter_request );
⋮----
$counts         = $filters->get_stock_status_counts( $filter_request );
⋮----
$filter_attributes = $filter_request->get_param( 'attributes' );
⋮----
$filter_request->set_param( 'attributes', $filter_attributes );
$counts = $filters->get_attribute_counts( $filter_request, [ $taxonomy ] );
⋮----
$counts = $filters->get_attribute_counts( $request, $taxonomy__and_queries );
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ProductReviews.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use WP_Comment_Query;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\StoreApi\Utilities\Pagination;
⋮----
class ProductReviews extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
⋮----
$prepared_args['orderby'] = $this->normalize_query_param( $request['orderby'] );
⋮----
$unlocked_product_ids = $this->get_unlocked_password_protected_product_ids( $prepared_args['post__in'] ?? array() );
⋮----
return $this->exclude_password_protected_product_reviews( $clauses, $unlocked_product_ids );
⋮----
$query_result = $query->query( $prepared_args );
⋮----
$total_reviews = $query->query( $prepared_args );
⋮----
$data               = $this->prepare_item_for_response( $review, $request );
... (21 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/Products.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\CatalogVisibility;
use Automattic\WooCommerce\StoreApi\Utilities\Pagination;
use Automattic\WooCommerce\StoreApi\Utilities\ProductQuery;
use Automattic\WooCommerce\StoreApi\Utilities\ProductLinksTrait;
⋮----
class Products extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
$response      = new \WP_REST_Response();
⋮----
if ( \WP_REST_Server::READABLE === $request->get_method() ) {
$query_results    = $product_query->get_objects( $request );
⋮----
$data               = $this->prepare_item_for_response( $object, $request );
$response_objects[] = $this->prepare_response_for_collection( $data );
⋮----
$response->set_data( $response_objects );
⋮----
... (11 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ProductsById.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\Utilities\ProductLinksTrait;
⋮----
class ProductsById extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param(
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
⋮----
if ( ! $object || 0 === $object->get_id() || ! $object->is_publicly_viewable() ) {
⋮----
return $this->prepare_item_for_response( $object, $request );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ProductsBySlug.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\Utilities\ProductLinksTrait;
⋮----
class ProductsBySlug extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param(
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
⋮----
$object = $this->get_product_by_slug( $slug );
⋮----
$object = $this->get_product_variation_by_slug( $slug );
⋮----
if ( ! $object || 0 === $object->get_id() || ! $object->is_publicly_viewable() ) {
⋮----
return $this->prepare_item_for_response( $object, $request );
⋮----
public function get_product_by_slug( $slug ) {
⋮----
private function get_product_variation_by_slug( $slug ) {
⋮----
... (3 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ProductTags.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
class ProductTags extends AbstractTermsRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'args'                => $this->get_collection_params(),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
return $this->get_terms_response( 'product_tag', $request );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ShopperListItems.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\Internal\ShopperLists\ShopperList;
use Automattic\WooCommerce\Internal\ShopperLists\ShopperListItem;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class ShopperListItems extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
$list = ShopperList::get_by_slug( (string) $request['slug'] );
⋮----
$items = array_values( $list->get_items() );
$this->prime_product_caches_for_items( $items );
⋮----
$response[] = $this->prepare_response_for_collection( $this->prepare_item_for_response( $item, $request ) );
⋮----
protected function get_route_post_response( \WP_REST_Request $request ) {
⋮----
[ $lookup_id, $variation, $quantity ] = $this->resolve_item_payload( $request );
⋮----
$item = ShopperListItem::from_product( $lookup_id, $variation, $quantity );
... (24 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ShopperListItemsByKey.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\Internal\ShopperLists\ShopperList;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class ShopperListItemsByKey extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
protected function get_route_delete_response( \WP_REST_Request $request ) {
$list = ShopperList::get_by_slug( (string) $request['slug'] );
⋮----
if ( ! $list->remove_item( (string) $request['key'] ) ) {
⋮----
$list->save();
⋮----
return new \WP_REST_Response( null, 204 );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ShopperLists.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\Internal\ShopperLists\ShopperList;
⋮----
class ShopperLists extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
⋮----
foreach ( ShopperList::get_all_for_user() as $list ) {
$response[] = $this->prepare_response_for_collection( $this->prepare_item_for_response( $list, $request ) );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ShopperListsBySlug.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
use Automattic\WooCommerce\Internal\ShopperLists\ShopperList;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class ShopperListsBySlug extends AbstractRoute {
⋮----
public function get_path() {
return self::get_path_regex();
⋮----
public static function get_path_regex() {
⋮----
public function get_args() {
⋮----
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
⋮----
protected function get_route_response( \WP_REST_Request $request ) {
$list = ShopperList::get_by_slug( (string) $request['slug'] );
⋮----
return rest_ensure_response( $this->prepare_item_for_response( $list, $request ) );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/V1/ShopperListsNonceCheck.php">
namespace Automattic\WooCommerce\StoreApi\Routes\V1;
⋮----
trait ShopperListsNonceCheck {
⋮----
private static $store_api_nonce_action = 'wc_store_api';
⋮----
public function get_response( \WP_REST_Request $request ) {
if ( $this->is_write_request( $request ) ) {
$nonce_check = $this->check_store_api_nonce( $request );
⋮----
return $this->add_nonce_response_headers( $this->error_to_response( $nonce_check ) );
⋮----
$response = parent::get_response( $request );
⋮----
return $this->add_nonce_response_headers( rest_ensure_response( $response ) );
⋮----
private function is_write_request( \WP_REST_Request $request ): bool {
return in_array( $request->get_method(), array( 'POST', 'PUT', 'PATCH', 'DELETE' ), true );
⋮----
private function check_store_api_nonce( \WP_REST_Request $request ) {
⋮----
$nonce = $request->get_header( 'Nonce' );
⋮----
return $this->get_route_error_response(
⋮----
private function add_nonce_response_headers( \WP_REST_Response $response ): \WP_REST_Response {
$response->header( 'Nonce', wp_create_nonce( self::$store_api_nonce_action ) );
$response->header( 'Nonce-Timestamp', (string) time() );
$response->header( 'Cache-Control', 'no-store' );
</file>

<file path="plugins/woocommerce/src/StoreApi/Routes/RouteInterface.php">
namespace Automattic\WooCommerce\StoreApi\Routes;
⋮----
interface RouteInterface {
⋮----
public function get_path();
⋮----
public function get_args();
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/AI/ProductsSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1\AI;
⋮----
use Automattic\WooCommerce\StoreApi\Schemas\V1\AbstractSchema;
⋮----
class ProductsSchema {}
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/AbstractAddressSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Utilities\SanitizationUtils;
use Automattic\WooCommerce\StoreApi\Utilities\ValidationUtils;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Utilities\TimeUtil;
⋮----
abstract class AbstractAddressSchema extends AbstractSchema {
⋮----
protected $additional_fields_controller;
⋮----
public function __construct( ExtendSchema $extend, SchemaController $controller ) {
parent::__construct( $extend, $controller );
$this->additional_fields_controller = Package::container()->get( CheckoutFields::class );
⋮----
public function get_properties() {
⋮----
$this->get_additional_address_fields_schema(),
⋮----
public function sanitize_callback( $address, $request, $param ) {
⋮----
$schema            = $this->get_properties();
⋮----
$carry[ $key ] = $validation_util->format_state( sanitize_text_field( $address[ $key ] ), $address['country'] );
⋮----
if ( $this->additional_fields_controller->is_field( $key ) ) {
$carry[ $key ] = $this->additional_fields_controller->sanitize_field( $key, $carry[ $key ] );
... (45 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/AbstractSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
use Automattic\WooCommerce\Blocks\Package;
⋮----
abstract class AbstractSchema {
⋮----
protected $title = 'Schema';
⋮----
protected $extend;
⋮----
protected $controller;
⋮----
public function __construct( ExtendSchema $extend, SchemaController $controller ) {
⋮----
public function get_item_schema() {
⋮----
'properties' => $this->get_properties(),
⋮----
public function get_item_response( $item ) {
⋮----
abstract public function get_properties();
⋮----
protected function remove_arg_options( $properties ) {
⋮----
$property['properties'] = $this->remove_arg_options( $property['properties'] );
⋮----
$property['items']['properties'] = $this->remove_arg_options( $property['items']['properties'] );
... (56 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/BatchSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
class BatchSchema extends AbstractSchema {
⋮----
protected $title = 'batch';
⋮----
public function get_properties() {
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/BillingAddressSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\Utilities\ValidationUtils;
⋮----
class BillingAddressSchema extends AbstractAddressSchema {
⋮----
protected $title = 'billing_address';
⋮----
public function get_properties() {
$properties = parent::get_properties();
⋮----
public function sanitize_callback( $address, $request, $param ) {
$address = parent::sanitize_callback( $address, $request, $param );
⋮----
public function validate_callback( $address, $request, $param ) {
$errors  = parent::validate_callback( $address, $request, $param );
⋮----
$errors  = is_wp_error( $errors ) ? $errors : new \WP_Error();
⋮----
$errors->add(
⋮----
return $errors->has_errors( $errors ) ? $errors : true;
⋮----
public function get_item_response( $address ) {
⋮----
$billing_country = $address->get_billing_country();
$billing_state   = $address->get_billing_state();
⋮----
if ( ! $validation_util->validate_state( $billing_state, $billing_country ) ) {
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/CartCouponSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Utilities\CartController;
⋮----
class CartCouponSchema extends AbstractSchema {
⋮----
protected $title = 'cart_coupon';
⋮----
public function get_properties() {
⋮----
$this->get_store_currency_properties(),
⋮----
public function coupon_exists( $coupon_code ) {
$coupon = new \WC_Coupon( $coupon_code );
return (bool) $coupon->get_id() || $coupon->get_virtual();
⋮----
public function get_item_response( $coupon_code ) {
⋮----
$cart       = $controller->get_cart_instance();
$coupon     = new \WC_Coupon( $coupon_code );
⋮----
'code'          => $coupon->get_code(),
'discount_type' => $coupon->get_discount_type(),
'totals'        => (object) $this->prepare_currency_response(
⋮----
'total_discount'     => $this->prepare_money_response( $cart->get_coupon_discount_amount( $coupon_code ), wc_get_price_decimals() ),
'total_discount_tax' => $this->prepare_money_response( $cart->get_coupon_discount_tax_amount( $coupon_code ), wc_get_price_decimals(), PHP_ROUND_HALF_DOWN ),
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/CartExtensionsSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
use Automattic\WooCommerce\StoreApi\Utilities\CartController;
⋮----
class CartExtensionsSchema extends AbstractSchema {
⋮----
protected $title = 'cart-extensions';
⋮----
public $cart_schema;
⋮----
public function __construct( ExtendSchema $extend, SchemaController $controller ) {
parent::__construct( $extend, $controller );
$this->cart_schema = $this->controller->get( CartSchema::IDENTIFIER );
⋮----
public function get_properties() {
⋮----
public function get_item_response( $request = null ) {
⋮----
$callback = $this->extend->get_update_callback( $request['namespace'] );
⋮----
esc_html( $e->getMessage() ),
⋮----
$callback( $request['data'] );
⋮----
$cart       = $controller->calculate_totals();
$response   = $this->cart_schema->get_item_response( $cart );
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/CartFeeSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
class CartFeeSchema extends AbstractSchema {
⋮----
protected $title = 'cart_fee';
⋮----
public function get_properties() {
⋮----
$this->get_store_currency_properties(),
⋮----
public function get_item_response( $fee ) {
⋮----
'name'   => $this->prepare_html_response( $fee->name ),
'totals' => (object) $this->prepare_currency_response(
⋮----
'total'     => $this->prepare_money_response( $fee->total, wc_get_price_decimals() ),
'total_tax' => $this->prepare_money_response( $fee->tax, wc_get_price_decimals(), PHP_ROUND_HALF_DOWN ),
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/CartItemSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Utilities\ProductItemTrait;
use Automattic\WooCommerce\StoreApi\Utilities\QuantityLimits;
⋮----
class CartItemSchema extends ItemSchema {
⋮----
protected $title = 'cart_item';
⋮----
public function get_item_response( $cart_item ) {
⋮----
$product_permalink = apply_filters( 'woocommerce_cart_item_permalink', $product->get_permalink(), $cart_item, $cart_item['key'] );
⋮----
'id'                   => $product->get_id(),
'type'                 => $product->get_type(),
⋮----
'quantity_limits'      => (object) ( new QuantityLimits() )->get_cart_item_quantity_limits( $cart_item ),
'name'                 => $this->prepare_html_response( $product->get_title() ),
'short_description'    => $this->prepare_html_response( wc_format_content( wp_kses_post( $product->get_short_description() ) ) ),
'description'          => $this->prepare_html_response( wc_format_content( wp_kses_post( $product->get_description() ) ) ),
'sku'                  => $this->prepare_html_response( $product->get_sku() ),
'low_stock_remaining'  => $this->get_low_stock_remaining( $product ),
'backorders_allowed'   => (bool) $product->backorders_allowed(),
'show_backorder_badge' => (bool) $product->backorders_require_notification() && $product->is_on_backorder( $cart_item['quantity'] ),
'sold_individually'    => $product->is_sold_individually(),
⋮----
'images'               => $this->get_cart_images( $product, $cart_item, $cart_item['key'] ),
'variation'            => $this->format_variation_data( $cart_item['variation'], $product ),
'item_data'            => $this->get_item_data( $cart_item ),
'prices'               => (object) $this->prepare_product_price_response( $product, get_option( 'woocommerce_tax_display_cart' ) ),
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/CartSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\Enums\WeightUnit;
use Automattic\WooCommerce\Internal\Tax\TaxRateDataStore;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
use Automattic\WooCommerce\StoreApi\Utilities\CartController;
⋮----
class CartSchema extends AbstractSchema {
⋮----
protected $title = 'cart';
⋮----
public $item_schema;
⋮----
public $coupon_schema;
⋮----
public $cross_sells_item_schema;
⋮----
public $fee_schema;
⋮----
public $shipping_rate_schema;
⋮----
public $shipping_address_schema;
⋮----
public $billing_address_schema;
⋮----
public $error_schema;
⋮----
public function __construct( ExtendSchema $extend, SchemaController $controller ) {
... (93 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/CartShippingRateSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use WC_Shipping_Rate as ShippingRate;
⋮----
class CartShippingRateSchema extends AbstractSchema {
⋮----
protected $title = 'cart-shipping-rate';
⋮----
public function get_properties() {
⋮----
'properties' => $this->get_rate_properties(),
⋮----
protected function get_rate_properties() {
⋮----
$this->get_store_currency_properties()
⋮----
public function get_item_response( $package ) {
⋮----
'destination'    => $this->prepare_package_destination_response( $package ),
'items'          => $this->prepare_package_items_response( $package ),
'shipping_rates' => $this->prepare_package_shipping_rates_response( $package ),
⋮----
protected function prepare_package_destination_response( $package ) {
⋮----
return (object) $this->prepare_html_response(
⋮----
protected function prepare_package_items_response( $package ) {
⋮----
'name'     => $values['data']->get_name(),
⋮----
... (33 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/CheckoutOrderSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Payments\PaymentResult;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
⋮----
class CheckoutOrderSchema extends CheckoutSchema {
⋮----
protected $title = 'checkout-order';
⋮----
public function get_properties() {
$parent_properties = parent::get_properties();
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/CheckoutSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Payments\PaymentResult;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\StoreApi\Utilities\SanitizationUtils;
use Automattic\WooCommerce\StoreApi\Schemas\V1\CartSchema;
use Automattic\WooCommerce\StoreApi\Utilities\PaymentUtils;
⋮----
class CheckoutSchema extends AbstractSchema {
⋮----
protected $title = 'checkout';
⋮----
protected $billing_address_schema;
⋮----
protected $shipping_address_schema;
⋮----
protected $image_attachment_schema;
⋮----
protected $cart_schema;
⋮----
protected $additional_fields_controller;
⋮----
public function __construct( ExtendSchema $extend, SchemaController $controller ) {
parent::__construct( $extend, $controller );
$this->billing_address_schema       = $this->controller->get( BillingAddressSchema::IDENTIFIER );
$this->shipping_address_schema      = $this->controller->get( ShippingAddressSchema::IDENTIFIER );
$this->image_attachment_schema      = $this->controller->get( ImageAttachmentSchema::IDENTIFIER );
... (108 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/ErrorSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
class ErrorSchema extends AbstractSchema {
⋮----
protected $title = 'error';
⋮----
public function get_properties() {
⋮----
public function get_item_response( $error ) {
⋮----
'code'    => $this->prepare_html_response( $error->get_error_code() ),
'message' => $this->prepare_html_response( $error->get_error_message() ),
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/ImageAttachmentSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
class ImageAttachmentSchema extends AbstractSchema {
⋮----
protected $title = 'image';
⋮----
public function get_properties() {
⋮----
public function get_item_response( $attachment_id ) {
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/ItemSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
abstract class ItemSchema extends ProductSchema {
⋮----
public function get_properties() {
⋮----
'properties' => $this->image_attachment_schema->get_properties(),
⋮----
$this->get_store_currency_properties(),
⋮----
self::EXTENDING_KEY    => $this->get_extended_schema( static::IDENTIFIER ),
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/OrderCouponSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
class OrderCouponSchema extends AbstractSchema {
⋮----
protected $title = 'order_coupon';
⋮----
public function get_properties() {
⋮----
$this->get_store_currency_properties(),
⋮----
public function get_item_response( $coupon ) {
$coupon_object = new \WC_Coupon( $coupon->get_code() );
⋮----
'code'          => $coupon->get_code(),
'discount_type' => $coupon_object ? $coupon_object->get_discount_type() : '',
'totals'        => (object) $this->prepare_currency_response(
⋮----
'total_discount'     => $this->prepare_money_response( $coupon->get_discount(), wc_get_price_decimals() ),
'total_discount_tax' => $this->prepare_money_response( $coupon->get_discount_tax(), wc_get_price_decimals(), PHP_ROUND_HALF_DOWN ),
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/OrderFeeSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
class OrderFeeSchema extends AbstractSchema {
⋮----
protected $title = 'order_fee';
⋮----
public function get_properties() {
⋮----
$this->get_store_currency_properties(),
⋮----
public function get_item_response( $fee ) {
⋮----
'key'    => $fee->get_id(),
'name'   => $this->prepare_html_response( $fee->get_name() ),
'totals' => (object) $this->prepare_currency_response(
⋮----
'total'     => $this->prepare_money_response( $fee->get_total(), wc_get_price_decimals() ),
'total_tax' => $this->prepare_money_response( $fee->get_total_tax(), wc_get_price_decimals(), PHP_ROUND_HALF_DOWN ),
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/OrderItemSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Utilities\ProductItemTrait;
⋮----
class OrderItemSchema extends ItemSchema {
⋮----
protected $title = 'order_item';
⋮----
private $cached_parent_attributes = null;
⋮----
public function get_properties() {
$properties = parent::get_properties();
⋮----
private function get_item_data( $order_item ) {
⋮----
$meta_rows = $order_item->get_meta_data();
⋮----
$formatted_meta_data = $order_item->get_all_formatted_meta_data();
⋮----
$meta = $meta->jsonSerialize();
⋮----
public function get_item_response( $order_item ) {
⋮----
$order   = $order_item->get_order();
$product = $order_item->get_product();
⋮----
$product_properties['short_description']  = $product->get_short_description();
$product_properties['description']        = $product->get_description();
$product_properties['sku']                = $product->get_sku();
$product_properties['permalink']          = $product->get_permalink();
... (48 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/OrderSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\Enums\OrderItemType;
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
use Automattic\WooCommerce\StoreApi\Utilities\OrderController;
⋮----
class OrderSchema extends AbstractSchema {
⋮----
protected $title = 'order';
⋮----
public $item_schema;
⋮----
protected $order_controller;
⋮----
public $coupon_schema;
⋮----
public $cross_sells_item_schema;
⋮----
public $fee_schema;
⋮----
public $shipping_rate_schema;
⋮----
public $shipping_address_schema;
⋮----
public $billing_address_schema;
⋮----
public $error_schema;
⋮----
public function __construct( ExtendSchema $extend, SchemaController $controller ) {
... (73 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/PatternsSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
class PatternsSchema extends AbstractSchema {
⋮----
protected $title = 'patterns';
⋮----
public function get_properties() {
⋮----
public function get_item_response( $item ) {
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/ProductAttributeSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
class ProductAttributeSchema extends AbstractSchema {
⋮----
protected $title = 'product_attribute';
⋮----
public function get_properties() {
⋮----
public function get_item_response( $attribute ) {
⋮----
'name'         => $this->prepare_html_response( $attribute->name ),
⋮----
'count'        => (int) \wp_count_terms( $attribute->slug ),
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/ProductAttributeTermSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\Internal\ProductAttributes\VisualAttributeTermMeta;
⋮----
class ProductAttributeTermSchema extends TermSchema {
⋮----
protected $title = 'product-attribute-term';
⋮----
public function get_properties() {
$schema = parent::get_properties();
⋮----
$schema[ self::VISUAL_PROPERTY_NAME ] = $this->get_visual_property_schema();
⋮----
private function get_visual_property_schema(): array {
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/ProductBrandSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
⋮----
class ProductBrandSchema extends TermSchema {
⋮----
protected $title = 'product-brand';
⋮----
protected $image_attachment_schema;
⋮----
public function __construct( ExtendSchema $extend, SchemaController $controller ) {
parent::__construct( $extend, $controller );
$this->image_attachment_schema = $this->controller->get( ImageAttachmentSchema::IDENTIFIER );
⋮----
public function get_properties() {
$schema                 = parent::get_properties();
⋮----
'properties'  => $this->image_attachment_schema->get_properties(),
⋮----
public function get_item_response( $term ) {
$response = parent::get_item_response( $term );
⋮----
$response['image']        = $this->image_attachment_schema->get_item_response( get_term_meta( $term->term_id, 'thumbnail_id', true ) );
$response['review_count'] = $this->get_brand_review_count( $term );
⋮----
protected function get_brand_review_count( $term ) {
⋮----
$review_count = $wpdb->get_var( $products_of_brand_sql );
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/ProductCategorySchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
⋮----
class ProductCategorySchema extends TermSchema {
⋮----
protected $title = 'product-category';
⋮----
protected $image_attachment_schema;
⋮----
public function __construct( ExtendSchema $extend, SchemaController $controller ) {
parent::__construct( $extend, $controller );
$this->image_attachment_schema = $this->controller->get( ImageAttachmentSchema::IDENTIFIER );
⋮----
public function get_properties() {
$schema                 = parent::get_properties();
⋮----
'properties'  => $this->image_attachment_schema->get_properties(),
⋮----
public function get_item_response( $term ) {
$response = parent::get_item_response( $term );
⋮----
$response['image']        = $this->image_attachment_schema->get_item_response( get_term_meta( $term->term_id, 'thumbnail_id', true ) );
$response['review_count'] = $this->get_category_review_count( $term );
⋮----
protected function get_category_review_count( $term ) {
⋮----
$review_count = $wpdb->get_var( $products_of_category_sql );
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/ProductCollectionDataSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
class ProductCollectionDataSchema extends AbstractSchema {
⋮----
protected $title = 'product-collection-data';
⋮----
public function get_properties() {
⋮----
$this->get_store_currency_properties(),
⋮----
public function get_item_response( $data ) {
⋮----
'price_range'         => ! is_null( $data['min_price'] ) && ! is_null( $data['max_price'] ) ? (object) $this->prepare_currency_response(
⋮----
'min_price' => $this->prepare_money_response( $data['min_price'], wc_get_price_decimals() ),
'max_price' => $this->prepare_money_response( $data['max_price'], wc_get_price_decimals() ),
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/ProductReviewSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
use Automattic\WooCommerce\StoreApi\SchemaController;
⋮----
class ProductReviewSchema extends AbstractSchema {
⋮----
protected $title = 'product_review';
⋮----
protected $image_attachment_schema;
⋮----
public function __construct( ExtendSchema $extend, SchemaController $controller ) {
parent::__construct( $extend, $controller );
$this->image_attachment_schema = $this->controller->get( ImageAttachmentSchema::IDENTIFIER );
⋮----
public function get_properties() {
⋮----
'properties'  => $this->image_attachment_schema->get_properties(),
⋮----
public function get_item_response( $review ) {
⋮----
'product_image'          => $this->image_attachment_schema->get_item_response( get_post_thumbnail_id( (int) $review->comment_post_ID ) ),
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/ProductSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
use Automattic\WooCommerce\StoreApi\Utilities\QuantityLimits;
use Automattic\WooCommerce\Blocks\Utils\ProductAvailabilityUtils;
use Automattic\WooCommerce\Blocks\Utils\ProductDescriptionUtils;
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\Enums\StockDisplayFormat;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
⋮----
class ProductSchema extends AbstractSchema {
⋮----
protected $title = 'product';
⋮----
protected $image_attachment_schema;
⋮----
public function __construct( ExtendSchema $extend, SchemaController $controller ) {
parent::__construct( $extend, $controller );
$this->image_attachment_schema = $this->controller->get( ImageAttachmentSchema::IDENTIFIER );
⋮----
public function get_properties() {
⋮----
$this->get_store_currency_properties(),
⋮----
'properties' => $this->image_attachment_schema->get_properties(),
⋮----
self::EXTENDING_KEY     => $this->get_extended_schema( self::IDENTIFIER ),
⋮----
... (165 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/ShippingAddressSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\Utilities\ValidationUtils;
⋮----
class ShippingAddressSchema extends AbstractAddressSchema {
⋮----
protected $title = 'shipping_address';
⋮----
public function get_item_response( $address ) {
⋮----
$shipping_country = $address->get_shipping_country();
$shipping_state   = $address->get_shipping_state();
⋮----
if ( ! $validation_util->validate_state( $shipping_state, $shipping_country ) ) {
⋮----
$additional_address_fields = $this->additional_fields_controller->get_all_fields_from_object( $address, 'shipping' );
⋮----
'first_name' => $address->get_shipping_first_name(),
'last_name'  => $address->get_shipping_last_name(),
'company'    => $address->get_shipping_company(),
'address_1'  => $address->get_shipping_address_1(),
'address_2'  => $address->get_shipping_address_2(),
'city'       => $address->get_shipping_city(),
⋮----
'postcode'   => $address->get_shipping_postcode(),
⋮----
'phone'      => $address->get_shipping_phone(),
⋮----
foreach ( $this->additional_fields_controller->get_address_fields_keys() as $field ) {
... (5 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/ShopperListItemSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\Internal\ShopperLists\ShopperListItem;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Utilities\ProductItemTrait;
⋮----
class ShopperListItemSchema extends AbstractSchema {
⋮----
protected $title = 'shopper_list_item';
⋮----
protected $image_attachment_schema;
⋮----
public function __construct( ExtendSchema $extend, SchemaController $controller ) {
parent::__construct( $extend, $controller );
$schema = $this->controller->get( ImageAttachmentSchema::IDENTIFIER );
⋮----
throw new \RuntimeException( 'ImageAttachmentSchema is not registered in SchemaController.' );
⋮----
public function get_properties() {
⋮----
'properties' => $this->image_attachment_schema->get_properties(),
⋮----
$this->get_store_currency_properties(),
⋮----
public function get_item_response( $item ) {
$variation_id = $item->get_variation_id();
$product_id   = $variation_id > 0 ? $variation_id : $item->get_product_id();
$product      = $item->get_product();
$is_live      = $item->is_live();
... (46 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/ShopperListSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
use Automattic\WooCommerce\Internal\ShopperLists\ShopperList;
use Automattic\WooCommerce\Internal\ShopperLists\ShopperListItem;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
use Automattic\WooCommerce\StoreApi\SchemaController;
⋮----
class ShopperListSchema extends AbstractSchema {
⋮----
protected $title = 'shopper_list';
⋮----
protected $item_schema;
⋮----
public function __construct( ExtendSchema $extend, SchemaController $controller ) {
parent::__construct( $extend, $controller );
$schema = $this->controller->get( ShopperListItemSchema::IDENTIFIER );
⋮----
throw new \RuntimeException( 'ShopperListItemSchema is not registered in SchemaController.' );
⋮----
public function get_properties() {
⋮----
'properties' => $this->force_schema_readonly( $this->item_schema->get_properties() ),
⋮----
public function get_item_response( $shopper_list ) {
$items = array_values( $shopper_list->get_items() );
⋮----
$variation_id = $item->get_variation_id();
return $variation_id > 0 ? $variation_id : $item->get_product_id();
⋮----
'slug'             => $shopper_list->get_slug(),
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/V1/TermSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas\V1;
⋮----
class TermSchema extends AbstractSchema {
⋮----
protected $title = 'term';
⋮----
public function get_properties() {
⋮----
public function get_item_response( $term ) {
⋮----
'name'        => $this->prepare_html_response( $term->name ),
⋮----
'description' => $this->prepare_html_response( $term->description ),
</file>

<file path="plugins/woocommerce/src/StoreApi/Schemas/ExtendSchema.php">
namespace Automattic\WooCommerce\StoreApi\Schemas;
⋮----
use Automattic\WooCommerce\StoreApi\Schemas\V1\CartItemSchema;
use Automattic\WooCommerce\StoreApi\Schemas\V1\CartSchema;
use Automattic\WooCommerce\StoreApi\Schemas\V1\CheckoutSchema;
use Automattic\WooCommerce\StoreApi\Schemas\V1\ProductSchema;
use Automattic\WooCommerce\StoreApi\Formatters;
⋮----
final class ExtendSchema {
⋮----
private $endpoints = [
⋮----
private $formatters;
⋮----
private $extend_data = [];
⋮----
private $callback_methods = [];
⋮----
private $payment_requirements = [];
⋮----
public function __construct( Formatters $formatters ) {
⋮----
public function register_endpoint_data( $args ) {
⋮----
$this->throw_exception( 'You must provide a plugin namespace when extending a Store REST endpoint.' );
⋮----
$this->throw_exception(
⋮----
$this->throw_exception( '$schema_callback must be a callable function.' );
⋮----
... (39 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/ArrayUtils.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
class ArrayUtils {
⋮----
public static function natural_language_join( $array, $enclose_items_with_quotes = false ) {
⋮----
public static function string_contains_array( $needle, $haystack ) {
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/CartController.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
use Automattic\WooCommerce\Checkout\Helpers\ReserveStock;
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\StoreApi\Exceptions\InvalidCartException;
use Automattic\WooCommerce\StoreApi\Exceptions\NotPurchasableException;
use Automattic\WooCommerce\StoreApi\Exceptions\OutOfStockException;
use Automattic\WooCommerce\StoreApi\Exceptions\PartialOutOfStockException;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\Exceptions\TooManyInCartException;
use Automattic\WooCommerce\StoreApi\Utilities\ArrayUtils;
use Automattic\WooCommerce\StoreApi\Utilities\DraftOrderTrait;
use Automattic\WooCommerce\StoreApi\Utilities\NoticeHandler;
use Automattic\WooCommerce\StoreApi\Utilities\QuantityLimits;
use WP_Error;
⋮----
class CartController {
⋮----
public function load_cart() {
⋮----
$cart               = $this->get_cart_instance();
⋮----
$cart->get_cart();
⋮----
public function normalize_cart() {
⋮----
$cart_items      = $this->get_cart_items();
⋮----
$normalized_qty = $quantity_limits->normalize_cart_item_quantity( $cart_item['quantity'], $cart_item );
... (308 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/CartTokenUtils.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
use Automattic\WooCommerce\StoreApi\Authentication;
use Automattic\WooCommerce\StoreApi\Utilities\JsonWebToken;
⋮----
class CartTokenUtils {
⋮----
public static function get_cart_token( string $customer_id ): string {
return JsonWebToken::create(
⋮----
'exp'     => self::get_cart_token_expiration(),
⋮----
self::get_cart_token_secret()
⋮----
public static function get_request_cart_token(): string {
⋮----
/**
	 * Validate the cart token.
	 *
	 * @param string $cart_token The cart token.
	 * @return bool
	 */
public static function validate_cart_token( string $cart_token ): bool {
return JsonWebToken::validate( $cart_token, self::get_cart_token_secret() );
⋮----
/**
	 * Get the cart token payload.
	 *
	 * Returns an empty payload unless the signature validates.
	 *
... (30 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/CheckoutTrait.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\StoreApi\Payments\PaymentContext;
use Automattic\WooCommerce\StoreApi\Payments\PaymentResult;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFieldsSchema\DocumentObject;
use WC_Customer;
⋮----
trait CheckoutTrait {
⋮----
public function prepare_item_for_response( $item, \WP_REST_Request $request ) {
$response     = parent::prepare_item_for_response( $item, $request );
⋮----
$response->set_status( $status_codes[ $item->payment_result->status ] ?? 200 );
⋮----
private function get_order_or_throw(): \WC_Order {
⋮----
private function process_without_payment( \WP_REST_Request $request, PaymentResult $payment_result ) {
$order = $this->get_order_or_throw();
⋮----
$order->payment_complete();
⋮----
$payment_result->set_status( 'success' );
$payment_result->set_redirect_url( $order->get_checkout_order_received_url() );
⋮----
private function process_payment( \WP_REST_Request $request, PaymentResult $payment_result ) {
⋮----
$session->set( 'order_awaiting_payment', $order->get_id() );
⋮----
... (103 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/DraftOrderTrait.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
trait DraftOrderTrait {
⋮----
protected function get_draft_order_id() {
⋮----
wc()->initialize_session();
⋮----
return wc()->session->get( 'store_api_draft_order', 0 );
⋮----
protected function set_draft_order_id( $order_id ) {
⋮----
wc()->session->set( 'store_api_draft_order', $order_id );
⋮----
protected function get_draft_order() {
$draft_order_id = $this->get_draft_order_id();
⋮----
return $this->is_valid_draft_order( $draft_order ) ? $draft_order : null;
⋮----
protected function is_valid_draft_order( $order_object ) {
⋮----
if ( $order_object->has_status( 'checkout-draft' ) ) {
⋮----
if ( $order_object->needs_payment() && $order_object->has_cart_hash( wc()->cart->get_cart_hash() ) ) {
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/JsonWebToken.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
final class JsonWebToken {
⋮----
private static $type = 'JWT';
⋮----
private static $algorithm = 'HS256';
⋮----
public static function create( array $payload, string $secret ) {
$header    = self::to_base_64_url( self::generate_header() );
$payload   = self::to_base_64_url( self::generate_payload( $payload ) );
$signature = self::to_base_64_url( self::generate_signature( $header . '.' . $payload, $secret ) );
⋮----
public static function validate( string $token, string $secret ) {
if ( ! self::shallow_validate( $token ) ) {
⋮----
$parts = self::get_parts( $token );
⋮----
$encoded_regenerated_signature = self::to_base_64_url(
self::generate_signature( $parts->header_encoded . '.' . $parts->payload_encoded, $secret )
⋮----
public static function shallow_validate( string $token ) {
⋮----
public static function get_parts( string $token ) {
⋮----
'header'            => json_decode( self::from_base_64_url( $parts[0] ) ),
⋮----
'payload'           => json_decode( self::from_base_64_url( $parts[1] ) ),
⋮----
'signature'         => self::from_base_64_url( $parts[2] ),
... (29 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/LocalPickupUtils.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
class LocalPickupUtils {
⋮----
public static function get_local_pickup_settings( $context = 'view' ) {
⋮----
// Return settings as is if we're editing them.
⋮----
public static function is_local_pickup_enabled() {
⋮----
public static function get_local_pickup_method_ids() {
⋮----
WC()->shipping()->get_shipping_methods(),
⋮----
if ( $method->supports( 'local-pickup' ) ) {
⋮----
public static function is_local_pickup_method( $method_id ) {
return in_array( $method_id, self::get_local_pickup_method_ids(), true );
⋮----
public static function get_local_pickup_method_locations() {
⋮----
$shipping_methods = WC()->shipping()->get_shipping_methods();
⋮----
$base_country = WC()->countries->get_base_country();
$base_state   = WC()->countries->get_base_state();
⋮----
if ( ! $method->supports( 'local-pickup' ) ) {
⋮----
'name'      => $method->get_method_title(),
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/NoticeHandler.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use WP_Error;
⋮----
class NoticeHandler {
⋮----
public static function convert_notices_to_exceptions( $error_code = 'unknown_server_error' ) {
⋮----
public static function convert_notices_to_wp_errors( $error_code = 'unknown_server_error' ) {
⋮----
$errors->add( $error_code, wp_strip_all_tags( $error_notice['notice'] ) );
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/OrderAuthorizationTrait.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
trait OrderAuthorizationTrait {
⋮----
public function is_authorized( \WP_REST_Request $request ) {
⋮----
$order_key     = sanitize_text_field( wp_unslash( $request->get_param( 'key' ) ) );
$billing_email = sanitize_text_field( wp_unslash( $request->get_param( 'billing_email' ) ) );
⋮----
$order_customer_id = $order->get_customer_id();
⋮----
$this->order_controller->validate_order_key( $order_id, $order_key );
$this->validate_billing_email_matches_order( $order_id, $billing_email );
⋮----
return new \WP_Error(
$error->getErrorCode(),
$error->getMessage(),
array( 'status' => $error->getCode() )
⋮----
public function validate_billing_email_matches_order( $order_id, $billing_email ) {
⋮----
$order_billing_email = $order->get_billing_email();
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/OrderController.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Internal\Customers\SearchService as CustomerSearchService;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Automattic\WooCommerce\Utilities\ArrayUtil;
use Automattic\WooCommerce\Enums\OrderItemType;
use Automattic\WooCommerce\Utilities\DiscountsUtil;
use Automattic\WooCommerce\Utilities\ShippingUtil;
use Exception;
⋮----
class OrderController {
⋮----
private CheckoutFields $additional_fields_controller;
⋮----
public function __construct() {
$this->additional_fields_controller = Package::container()->get( CheckoutFields::class );
⋮----
public function create_order_from_cart() {
if ( wc()->cart->is_empty() ) {
⋮----
$order = new \WC_Order();
$order->set_status( 'checkout-draft' );
$order->set_created_via( 'store-api' );
$this->update_order_from_cart( $order );
⋮----
public function update_order_from_cart( \WC_Order $order, $update_totals = true ) {
⋮----
wc()->cart->calculate_totals();
... (333 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/Pagination.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
class Pagination {
⋮----
public function add_headers( $response, $request, $total_items, $total_pages ) {
$response->header( 'X-WP-Total', $total_items );
$response->header( 'X-WP-TotalPages', $total_pages );
⋮----
$current_page = $this->get_current_page( $request );
$link_base    = $this->get_link_base( $request );
⋮----
$this->add_page_link( $response, 'prev', $previous_page, $link_base );
⋮----
$this->add_page_link( $response, 'next', ( $current_page + 1 ), $link_base );
⋮----
protected function get_current_page( $request ) {
return (int) $request->get_param( 'page' );
⋮----
protected function get_link_base( $request ) {
return esc_url( add_query_arg( $request->get_query_params(), rest_url( $request->get_route() ) ) );
⋮----
protected function add_page_link( &$response, $name, $page, $link_base ) {
$response->link_header( $name, add_query_arg( 'page', $page, $link_base ) );
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/PaymentUtils.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
class PaymentUtils {
⋮----
public static function include_token_id_with_payment_methods( $list_item, $token ) {
$list_item['tokenId'] = $token->get_id();
⋮----
public static function get_enabled_payment_gateways() {
$payment_gateways = WC()->payment_gateways->payment_gateways();
⋮----
public static function get_saved_payment_methods() {
⋮----
$enabled_payment_gateways = self::get_enabled_payment_gateways();
⋮----
public static function get_default_payment_method() {
$saved_payment_methods = self::get_saved_payment_methods();
⋮----
$chosen_payment_method = WC()->session->get( 'chosen_payment_method' );
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/ProductItemTrait.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
trait ProductItemTrait {
⋮----
protected function prepare_product_price_response( \WC_Product $product, $tax_display_mode = '' ) {
$tax_display_mode   = $this->get_tax_display_mode( $tax_display_mode );
$price_function     = $this->get_price_function_from_tax_display_mode( $tax_display_mode );
$prices             = parent::prepare_product_price_response( $product, $tax_display_mode );
⋮----
// Add raw prices (prices with greater precision).
⋮----
'price'         => $this->prepare_money_response( $price_function( $product ), $rounding_precision ),
'regular_price' => $this->prepare_money_response( $price_function( $product, array( 'price' => $product->get_regular_price() ) ), $rounding_precision ),
'sale_price'    => $this->prepare_money_response( $price_function( $product, array( 'price' => $product->get_sale_price() ) ), $rounding_precision ),
⋮----
protected function format_variation_data( $variation_data, $product ) {
⋮----
// If this is a term slug, get the term's nice name.
⋮----
'raw_attribute' => $this->prepare_html_response( $key ),
'attribute'     => $this->prepare_html_response( $label ),
'value'         => $this->prepare_html_response( $value ),
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/ProductLinksTrait.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
trait ProductLinksTrait {
⋮----
protected function prepare_links( $item, $request ): array {
⋮----
'href' => rest_url( $this->get_namespace() . '/products/' . $item->get_id() ),
⋮----
'href' => rest_url( $this->get_namespace() . '/products' ),
⋮----
if ( $item->get_parent_id() ) {
⋮----
'href' => rest_url( $this->get_namespace() . '/products/' . $item->get_parent_id() ),
⋮----
$upsell_ids = $item->get_upsell_ids();
⋮----
rest_url( $this->get_namespace() . '/products' )
⋮----
$cross_sell_ids = $item->get_cross_sell_ids();
⋮----
'related'  => $item->get_id(),
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/ProductQuery.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
use Automattic\WooCommerce\Enums\ProductStatus;
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Enums\CatalogVisibility;
use Automattic\WooCommerce\Enums\TaxDisplayMode;
use Automattic\WooCommerce\Internal\ProductFilters\Interfaces\QueryClausesGenerator;
use Automattic\WooCommerce\Internal\Utilities\ProductUtil;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use WC_Tax;
⋮----
class ProductQuery implements QueryClausesGenerator {
⋮----
public function prepare_objects_query( $request ) {
⋮----
$operator    = $request->get_param( $key . '_operator' ) && isset( $operator_mapping[ $request->get_param( $key . '_operator' ) ] ) ? $operator_mapping[ $request->get_param( $key . '_operator' ) ] : 'IN';
⋮----
$relation    = $request->get_param( 'attribute_relation' ) && isset( $operator_mapping[ $request->get_param( 'attribute_relation' ) ] ) ? $operator_mapping[ $request->get_param( 'attribute_relation' ) ] : 'IN';
⋮----
$args['meta_query'] = $this->convert_tax_query_to_meta_query( array_merge( $tax_query, $args['tax_query'] ) );
⋮----
$args['meta_query'] = $this->convert_tax_query_to_meta_query( $tax_query );
⋮----
$catalog_visibility = $request->get_param( 'catalog_visibility' );
$rating             = $request->get_param( 'rating' );
⋮----
$orderby = $request->get_param( 'orderby' );
$order   = $request->get_param( 'order' );
⋮----
$ordering_args   = wc()->query->get_catalog_ordering_args( $orderby, $order );
... (110 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/ProductQueryFilters.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
use Automattic\WooCommerce\Enums\ProductStockStatus;
use Automattic\WooCommerce\StoreApi\Utilities\ProductQuery;
⋮----
class ProductQueryFilters {
⋮----
public function get_filtered_price( $request ) {
⋮----
$query_args                   = $product_query->prepare_objects_query( $request );
⋮----
$query                        = new \WP_Query();
$result                       = $query->query( $query_args );
⋮----
return $wpdb->get_row( $price_filter_sql );
⋮----
public function get_stock_status_counts( $request ) {
⋮----
$query_args = $product_query->prepare_objects_query( $request );
⋮----
$stock_status_count_sql = $this->generate_stock_status_count_query( $status, $product_query_sql, $stock_status_options );
⋮----
$result = $wpdb->get_row( $stock_status_count_sql );
⋮----
private function generate_stock_status_count_query( $status, $product_query_sql, $stock_status_options ) {
⋮----
public function get_attribute_counts( $request, $attributes = [] ) {
⋮----
$request->set_param( 'page', null );
$request->set_param( 'per_page', null );
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/QuantityLimits.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
use Automattic\WooCommerce\Checkout\Helpers\ReserveStock;
use Automattic\WooCommerce\StoreApi\Utilities\DraftOrderTrait;
use Automattic\WooCommerce\Utilities\NumberUtil;
⋮----
final class QuantityLimits {
⋮----
public function get_cart_item_quantity_limits( $cart_item ) {
⋮----
$this->get_add_to_cart_limits( $product, $cart_item ),
⋮----
'editable' => $this->filter_boolean_value( ! $product->is_sold_individually(), 'editable', $product, $cart_item ),
⋮----
public function get_add_to_cart_limits( \WC_Product $product, $cart_item = null ) {
⋮----
$minimum     = $this->filter_numeric_value( $args['min_value'], 'minimum', $product, $cart_item );
$maximum     = $this->filter_numeric_value(
$this->adjust_product_quantity_limit( $args['max_value'], $product, $cart_item ),
⋮----
$multiple_of = $this->filter_numeric_value( $args['step'], 'multiple_of', $product, $cart_item );
⋮----
$minimum = max( $multiple_of, $this->limit_to_multiple( $minimum, $multiple_of, 'ceil' ) );
$maximum = max( $minimum, $this->limit_to_multiple( $maximum, $multiple_of, 'floor' ) );
⋮----
public function normalize_cart_item_quantity( $quantity, array $cart_item ) {
⋮----
$quantity = NumberUtil::normalize( $quantity );
⋮----
$limits       = $this->get_cart_item_quantity_limits( $cart_item );
... (46 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/RateLimits.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
use WC_Rate_Limiter;
use WC_Cache_Helper;
⋮----
class RateLimits extends WC_Rate_Limiter {
⋮----
protected static function get_cache_key( $action_id ): string {
return WC_Cache_Helper::get_cache_prefix( 'store_api_rate_limit' . $action_id );
⋮----
protected static function get_rate_limit_row( string $action_id ): object {
⋮----
$row = $wpdb->get_row(
$wpdb->prepare(
⋮----
$options = self::get_options();
⋮----
public static function get_rate_limit( string $action_id ): object {
$current_limit = self::get_cached( $action_id );
⋮----
$current_limit = self::get_rate_limit_row( $action_id );
self::set_cache( $action_id, $current_limit );
⋮----
public static function is_exceeded_retry_after( string $action_id ) {
$current_limit = self::get_rate_limit( $action_id );
⋮----
public static function update_rate_limit( string $action_id ): object {
⋮----
$options           = self::get_options();
⋮----
... (14 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/SanitizationUtils.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
class SanitizationUtils {
⋮----
public function wp_kses_array( array $array ) {
⋮----
$array[ $key ] = $this->wp_kses_array( $value );
</file>

<file path="plugins/woocommerce/src/StoreApi/Utilities/ValidationUtils.php">
namespace Automattic\WooCommerce\StoreApi\Utilities;
⋮----
class ValidationUtils {
⋮----
public function get_states_for_country( $country ) {
return $country ? array_filter( (array) \wc()->countries->get_states( $country ) ) : [];
⋮----
public function validate_state( $state, $country ) {
$states = $this->get_states_for_country( $country );
⋮----
if ( count( $states ) && ! in_array( \wc_strtoupper( $state ), array_map( '\wc_strtoupper', array_keys( $states ) ), true ) ) {
⋮----
public function format_state( $state, $country ) {
⋮----
$state        = \wc_strtoupper( $state );
</file>

<file path="plugins/woocommerce/src/StoreApi/Authentication.php">
namespace Automattic\WooCommerce\StoreApi;
⋮----
use Automattic\WooCommerce\StoreApi\Utilities\RateLimits;
use Automattic\WooCommerce\StoreApi\Utilities\CartTokenUtils;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
class Authentication {
⋮----
public function init() {
if ( ! $this->is_request_to_store_api() ) {
⋮----
public function allowed_cors_headers( $allowed_headers ) {
⋮----
public function maybe_use_store_api_session_handler( $handler ): string {
if ( ! WC()->is_store_api_request() && ! $this->has_store_api_route_as_get_parameter() ) {
⋮----
$cart_token = CartTokenUtils::get_request_cart_token();
if ( $cart_token && CartTokenUtils::validate_cart_token( $cart_token ) ) {
⋮----
public function exposed_cors_headers( $exposed_headers ) {
⋮----
public function send_cors_headers( $served, $result, $request, $server ) {
⋮----
$server->send_header( 'Access-Control-Allow-Methods', 'OPTIONS, GET, POST, PUT, PATCH, DELETE' );
$server->send_header( 'Access-Control-Allow-Credentials', 'true' );
$server->send_header( 'Vary', 'Origin', false );
⋮----
if ( $this->is_preflight() || CartTokenUtils::validate_cart_token( $this->get_cart_token( $request ) ) || is_allowed_http_origin( $origin ) ) {
$server->send_header( 'Access-Control-Allow-Origin', $origin );
⋮----
... (67 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/deprecated.php">

</file>

<file path="plugins/woocommerce/src/StoreApi/Formatters.php">
namespace Automattic\WooCommerce\StoreApi;
⋮----
use \Exception;
use Automattic\WooCommerce\StoreApi\Formatters\DefaultFormatter;
⋮----
class Formatters {
⋮----
private $formatters = [];
⋮----
public function __get( $name ) {
⋮----
public function register( $name, $class ) {
$this->formatters[ $name ] = new $class();
</file>

<file path="plugins/woocommerce/src/StoreApi/functions.php">
use Automattic\WooCommerce\StoreApi\StoreApi;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
⋮----
function woocommerce_store_api_register_endpoint_data( $args ) {
⋮----
$extend = StoreApi::container()->get( ExtendSchema::class );
$extend->register_endpoint_data( $args );
⋮----
return new \WP_Error( 'error', $error->getMessage() );
⋮----
function woocommerce_store_api_register_update_callback( $args ) {
⋮----
$extend->register_update_callback( $args );
⋮----
function woocommerce_store_api_register_payment_requirements( $args ) {
⋮----
$extend->register_payment_requirements( $args );
⋮----
function woocommerce_store_api_get_formatter( $name ) {
return StoreApi::container()->get( ExtendSchema::class )->get_formatter( $name );
</file>

<file path="plugins/woocommerce/src/StoreApi/Legacy.php">
namespace Automattic\WooCommerce\StoreApi;
⋮----
use Automattic\WooCommerce\StoreApi\Payments\PaymentContext;
use Automattic\WooCommerce\StoreApi\Payments\PaymentResult;
use Automattic\WooCommerce\StoreApi\Utilities\NoticeHandler;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
⋮----
class Legacy {
⋮----
public function init() {
⋮----
public function process_legacy_payment( PaymentContext $context, PaymentResult &$result ) {
⋮----
$payment_method_object = $context->get_payment_method_instance();
⋮----
$payment_method_object->validate_fields();
⋮----
NoticeHandler::convert_notices_to_exceptions( 'woocommerce_rest_payment_error' );
⋮----
$gateway_result = $payment_method_object->process_payment( $context->order->get_id() );
⋮----
$result->set_status( in_array( $result_status, $valid_status, true ) ? $result_status : 'failure' );
⋮----
$result->set_payment_details( array_merge( $result->payment_details, $gateway_result ) );
$result->set_redirect_url( $gateway_result['redirect'] ?? '' );
</file>

<file path="plugins/woocommerce/src/StoreApi/README.md">
# WooCommerce Store API

**The Store API provides public Rest API endpoints for the development of customer-facing cart, checkout, and product functionality. It follows many of the patterns used in the [WordPress REST API](https://developer.wordpress.org/rest-api/key-concepts/).**

In contrast to the WooCommerce REST API, the Store API is unauthenticated and does not provide access to sensitive store data or other customer information.

For full documentation of the Store API, visit the [Store API Developer Docs](https://developer.woocommerce.com/docs/apis/store-api)
</file>

<file path="plugins/woocommerce/src/StoreApi/RoutesController.php">
namespace Automattic\WooCommerce\StoreApi;
⋮----
use Automattic\WooCommerce\Internal\ShopperLists\ShopperListsController;
use Automattic\WooCommerce\StoreApi\Routes\V1\AbstractRoute;
⋮----
class RoutesController {
⋮----
protected $schema_controller;
⋮----
protected $routes = [];
⋮----
private static $api_namespace = 'wc/store';
⋮----
public function __construct( SchemaController $schema_controller ) {
⋮----
public function register_all_routes() {
$this->register_routes( 'v1', self::$api_namespace );
$this->register_routes( 'v1', self::$api_namespace . '/v1' );
$this->register_routes( 'private', 'wc/private' );
⋮----
if ( wc_get_container()->get( ShopperListsController::class )->is_enabled() ) {
$this->register_routes( 'shopper_lists', self::$api_namespace . '/v1' );
⋮----
public function get( $name, $version = 'v1' ) {
⋮----
throw new \Exception( "{$name} {$version} route does not exist" );
⋮----
return new $route(
⋮----
$this->schema_controller->get( $route::SCHEMA_TYPE, $route::SCHEMA_VERSION )
... (16 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/SchemaController.php">
namespace Automattic\WooCommerce\StoreApi;
⋮----
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
⋮----
class SchemaController {
⋮----
protected $schemas = [];
⋮----
private $extend;
⋮----
public function __construct( ExtendSchema $extend ) {
⋮----
public function get( $name, $version = 1 ) {
⋮----
throw new \Exception( "{$name} v{$version} schema does not exist" );
⋮----
return new $schema( $this->extend, $this );
</file>

<file path="plugins/woocommerce/src/StoreApi/SessionHandler.php">
namespace Automattic\WooCommerce\StoreApi;
⋮----
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\StoreApi\Utilities\CartTokenUtils;
use WC_Session;
⋮----
final class SessionHandler extends WC_Session {
⋮----
protected $token = '';
⋮----
/**
	 * Table name for session data.
	 *
	 * @var string Custom session table name
	 */
protected $table = '';
⋮----
/**
	 * Expiration timestamp.
	 *
	 * @var int
	 */
protected $session_expiration = 0;
⋮----
/**
	 * Constructor for the session class.
	 */
public function __construct() {
$this->token = CartTokenUtils::get_request_cart_token();
⋮----
... (63 lines truncated)
</file>

<file path="plugins/woocommerce/src/StoreApi/StoreApi.php">
namespace Automattic\WooCommerce\StoreApi;
⋮----
use Automattic\WooCommerce\Blocks\Registry\Container;
use Automattic\WooCommerce\StoreApi\Formatters;
use Automattic\WooCommerce\StoreApi\Authentication;
use Automattic\WooCommerce\StoreApi\Legacy;
use Automattic\WooCommerce\StoreApi\Formatters\CurrencyFormatter;
use Automattic\WooCommerce\StoreApi\Formatters\HtmlFormatter;
use Automattic\WooCommerce\StoreApi\Formatters\MoneyFormatter;
use Automattic\WooCommerce\StoreApi\RoutesController;
use Automattic\WooCommerce\StoreApi\SchemaController;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
⋮----
final class StoreApi {
⋮----
public function init() {
⋮----
$authentication = self::container()->get( Authentication::class );
⋮----
self::container()->get( Legacy::class )->init();
self::container()->get( RoutesController::class )->register_all_routes();
⋮----
self::container()->get( Authentication::class )->init();
⋮----
self::container()->get( RoutesController::class )->get_all_routes( 'v1' )
⋮----
public static function container( $reset = false ) {
⋮----
$container->register(
⋮----
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/src/Utilities/ArrayUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
class ArrayUtil {
⋮----
public static function get_nested_value( array $items, string $key, $default_value = null ) {
⋮----
public static function is_truthy( array $items, string $key ) {
⋮----
public static function get_value_or_default( array $items, string $key, $default_value = null ) {
⋮----
public static function to_ranges_string( array $items, string $item_separator = ', ', string $range_separator = '-', bool $sort = true ): string {
⋮----
/**
	 * Helper function to generate a callback which can be executed on an array to select a value from each item.
	 *
	 * @param string $selector_name Field/property/method name to select.
	 * @param int    $selector_type Selector type.
	 *
	 * @return \Closure Callback to select the value.
	 */
private static function get_selector_callback( string $selector_name, int $selector_type = self::SELECT_BY_AUTO ): \Closure {
⋮----
/**
	 * Select one single value from all the items in an array of either arrays or objects based on a selector.
	 * For arrays, the selector is a key name; for objects, the selector can be either a method name or a property name.
	 *
	 * @param array  $items Items to apply the selection to.
	 * @param string $selector_name Key, method or property name to use as a selector.
	 * @param int    $selector_type Selector type, one of the SELECT_BY_* constants.
	 * @return array The selected values.
... (59 lines truncated)
</file>

<file path="plugins/woocommerce/src/Utilities/CallbackUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
final class CallbackUtil {
⋮----
public static function get_callback_signature( $callback ): string {
⋮----
return self::get_closure_signature( $callback );
⋮----
return self::get_invokable_signature( $callback );
⋮----
public static function get_hook_callback_signatures( string $hook_name ): array {
⋮----
fn( $callback_data ) => self::get_callback_signature( $callback_data['function'] ),
⋮----
private static function get_closure_signature( \Closure $closure ): string {
$reflection = new \ReflectionFunction( $closure );
$file       = $reflection->getFileName();
$start      = $reflection->getStartLine();
$end        = $reflection->getEndLine();
⋮----
throw new \ReflectionException( 'Unable to get closure location information' );
⋮----
private static function get_invokable_signature( object $invokable ): string {
$method = new \ReflectionMethod( $invokable, '__invoke' );
$class  = $method->getDeclaringClass();
⋮----
if ( ! $class->isAnonymous() ) {
return $class->getName() . '::__invoke';
⋮----
md5( $class->getName() ),
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/src/Utilities/DiscountsUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
class DiscountsUtil {
⋮----
public static function is_coupon_emails_allowed( $check_emails, $restrictions ) {
</file>

<file path="plugins/woocommerce/src/Utilities/FeaturesUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
use Automattic\WooCommerce\Internal\Features\FeaturesController;
⋮----
class FeaturesUtil {
⋮----
public static function get_features( bool $include_experimental = false, bool $include_enabled_info = false ): array {
return wc_get_container()->get( FeaturesController::class )->get_features( $include_experimental, $include_enabled_info );
⋮----
public static function feature_is_enabled( string $feature_id ): bool {
$features_controller = wc_get_container()->get( FeaturesController::class );
$feature             = $features_controller->get_feature_definition( $feature_id );
⋮----
self::log_deprecated_feature_usage( $feature_id, $feature['deprecated_since'] );
⋮----
return $features_controller->feature_is_enabled( $feature_id );
⋮----
private static function log_deprecated_feature_usage( string $feature_id, string $deprecated_since ): void {
⋮----
public static function declare_compatibility( string $feature_id, string $plugin_file, bool $positive_compatibility = true ): bool {
return wc_get_container()->get( FeaturesController::class )->declare_compatibility(
⋮----
public static function get_compatible_features_for_plugin( string $plugin_name ): array {
return wc_get_container()->get( FeaturesController::class )->get_compatible_features_for_plugin( $plugin_name );
⋮----
public static function get_compatible_plugins_for_feature( string $feature_id ): array {
return wc_get_container()->get( FeaturesController::class )->get_compatible_plugins_for_feature( $feature_id );
⋮----
public static function allow_enabling_features_with_incompatible_plugins(): void {
wc_get_container()->get( FeaturesController::class )->allow_enabling_features_with_incompatible_plugins();
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/src/Utilities/I18nUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
final class I18nUtil {
⋮----
private static $units;
⋮----
public static function get_weight_unit_label( $weight_unit ) {
⋮----
self::$units = include WC()->plugin_path() . '/i18n/units.php';
⋮----
public static function get_dimensions_unit_label( $dimensions_unit ) {
</file>

<file path="plugins/woocommerce/src/Utilities/LoggingUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
use Automattic\WooCommerce\Internal\Admin\Logging\{ PageController, Settings };
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\{ File, FileController };
⋮----
final class LoggingUtil {
⋮----
public static function get_logs_tab_url(): string {
return wc_get_container()->get( PageController::class )->get_logs_tab_url();
⋮----
public static function logging_is_enabled(): bool {
return wc_get_container()->get( Settings::class )->logging_is_enabled();
⋮----
public static function get_default_handler(): string {
return wc_get_container()->get( Settings::class )->get_default_handler();
⋮----
public static function get_retention_period(): int {
return wc_get_container()->get( Settings::class )->get_retention_period();
⋮----
public static function get_level_threshold(): string {
return wc_get_container()->get( Settings::class )->get_level_threshold();
⋮----
public static function generate_log_file_id( string $source, ?int $rotation = null, int $created = 0 ): string {
return File::generate_file_id( $source, $rotation, $created );
⋮----
public static function generate_log_file_hash( string $file_id ): string {
return File::generate_hash( $file_id );
⋮----
public static function get_log_directory( bool $create_dir = true ): string {
return Settings::get_log_directory( $create_dir );
... (4 lines truncated)
</file>

<file path="plugins/woocommerce/src/Utilities/MetaDataUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
use WC_Data;
⋮----
class MetaDataUtil {
⋮----
public static function update( $meta_data, WC_Data $target, $default_id = '' ): void {
⋮----
foreach ( self::normalize( $meta_data, $default_id ) as $meta ) {
$target->update_meta_data( $meta['key'], $meta['value'], $meta['id'] );
⋮----
public static function normalize( array $meta_data, $default_id = '' ): array {
</file>

<file path="plugins/woocommerce/src/Utilities/NumberUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
final class NumberUtil {
⋮----
public static function normalize( $value, $fallback = 0 ) {
⋮----
public static function round( $val, int $precision = 0, int $mode = PHP_ROUND_HALF_UP ): float {
return round( self::normalize( $val ), $precision, $mode );
⋮----
public static function floor( $val ): float {
return floor( self::normalize( $val ) );
⋮----
public static function ceil( $val ): float {
return ceil( self::normalize( $val ) );
⋮----
public static function array_sum( array $arr ): float {
⋮----
public static function sanitize_cost_in_current_locale( $value ): string {
⋮----
// Count the number of decimal points.
⋮----
// If it's a standard decimal number (single decimal point and is_numeric), accept it directly. This could be in the case where the frontend has de-localised the value.
⋮----
throw new \InvalidArgumentException(
⋮----
/* translators: %s: Invalid value that was input by the user */
</file>

<file path="plugins/woocommerce/src/Utilities/OrderUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
use Automattic\WooCommerce\Caches\OrderCacheController;
use Automattic\WooCommerce\Caches\OrderCountCache;
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\Admin\Orders\PageController;
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Automattic\WooCommerce\Internal\Utilities\COTMigrationUtil;
use WC_Order;
use WP_Post;
⋮----
final class OrderUtil {
⋮----
public static function get_order_admin_screen(): string {
return wc_get_container()->get( COTMigrationUtil::class )->get_order_admin_screen();
⋮----
public static function custom_orders_table_usage_is_enabled(): bool {
return wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled();
⋮----
public static function custom_orders_table_datastore_cache_enabled(): bool {
return wc_get_container()->get( CustomOrdersTableController::class )->hpos_data_caching_is_enabled();
⋮----
public static function orders_cache_usage_is_enabled(): bool {
return wc_get_container()->get( OrderCacheController::class )->orders_cache_usage_is_enabled();
⋮----
public static function is_custom_order_tables_in_sync(): bool {
return wc_get_container()->get( COTMigrationUtil::class )->is_custom_order_tables_in_sync();
⋮----
public static function custom_orders_table_data_sync_is_enabled(): bool {
return wc_get_container()->get( COTMigrationUtil::class )->custom_orders_table_data_sync_is_enabled();
... (56 lines truncated)
</file>

<file path="plugins/woocommerce/src/Utilities/PluginUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
use Automattic\WooCommerce\Enums\FeaturePluginCompatibility;
use Automattic\WooCommerce\Internal\Features\FeaturesController;
use Automattic\WooCommerce\Internal\Utilities\PluginInstaller;
use Automattic\WooCommerce\Proxies\LegacyProxy;
⋮----
class PluginUtil {
⋮----
private $proxy;
⋮----
private $woocommerce_aware_plugins = null;
⋮----
private $woocommerce_aware_active_plugins = null;
⋮----
public function __construct() {
⋮----
final public function init( LegacyProxy $proxy ) {
⋮----
public function get_all_active_valid_plugins() {
⋮----
public function get_woocommerce_aware_plugins( bool $active_only = false ): array {
⋮----
$all_plugins = $this->proxy->call_function( 'get_plugins' );
⋮----
return $this->proxy->call_function( 'is_plugin_active', $plugin_name );
⋮----
public function get_plugin_name( string $plugin_id ): string {
$plugin_data = $this->proxy->call_function( 'get_plugin_data', WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . $plugin_id );
⋮----
... (46 lines truncated)
</file>

<file path="plugins/woocommerce/src/Utilities/RestApiUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
class RestApiUtil {
⋮----
public function get_endpoint_data( $endpoint, $params = array() ) {
$request = new \WP_REST_Request( 'GET', $endpoint );
⋮----
$request->set_query_params( $params );
⋮----
$json     = wp_json_encode( $server->response_to_data( $response, false ) );
⋮----
public function lazy_load_namespace( string $route_namespace, callable $callback ) {
⋮----
$this->attach_lazy_loaded_namespace( $route_namespace, $callback );
⋮----
public function attach_lazy_loaded_namespace( string $route_namespace, callable $callback, string $rest_route = '', string $callback_filter_id = '' ) {
⋮----
// Load all namespaces for root requests (/wp-json/) to maintain API discovery functionality.
⋮----
// Remove the current filter prior to the callback, to prevent recursive callback issues.
// This is crucial for APIs like wc-analytics that may callback to their own namespace when loading.
⋮----
$this->attach_lazy_loaded_namespace( $route_namespace, $callback, $request->get_route(), $callback_filter_id );
</file>

<file path="plugins/woocommerce/src/Utilities/ShippingUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
class ShippingUtil {
⋮----
public static function get_selected_shipping_rates_from_packages( $packages ) {
</file>

<file path="plugins/woocommerce/src/Utilities/StringUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
final class StringUtil {
⋮----
public static function starts_with( string $string, string $starts_with, bool $case_sensitive = true ): bool {
⋮----
public static function ends_with( string $string, string $ends_with, bool $case_sensitive = true ): bool {
⋮----
public static function contains( string $string, string $contained, bool $case_sensitive = true ): bool {
⋮----
public static function plugin_name_from_plugin_file( string $plugin_file_path ): string {
⋮----
public static function is_null_or_empty( ?string $value ) {
⋮----
/**
	 * Check if a string is null, is empty, or has only whitespace characters
	 * (space, tab, vertical tab, form feed, carriage return, new line)
	 *
	 * @param string|null $value The string to check.
	 * @return bool True if the string is null, is empty, or contains only whitespace characters.
	 */
public static function is_null_or_whitespace( ?string $value ) {
⋮----
/**
	 * Convert an array of values to a list suitable for a SQL "IN" statement
	 * (so comma separated and delimited by parenthesis).
	 * e.g.: [1,2,3] --> (1,2,3)
	 *
	 * @param array $values The values to convert.
	 * @return string A parenthesized and comma-separated string generated from the values.
... (17 lines truncated)
</file>

<file path="plugins/woocommerce/src/Utilities/TimeUtil.php">
namespace Automattic\WooCommerce\Utilities;
⋮----
use \DateTime;
use \DateTimeZone;
use \Exception;
⋮----
class TimeUtil {
⋮----
private static DateTimeZone $utc_date_time_zone;
⋮----
public function __construct() {
⋮----
public static function get_utc_date_time_zone(): DateTimeZone {
⋮----
public static function is_valid_date( string $date, string $format = 'Y-m-d H:i:s' ): bool {
$d = DateTime::createFromFormat( $format, $date );
return $d && $d->format( $format ) === $date;
</file>

<file path="plugins/woocommerce/src/Autoloader.php">
namespace Automattic\WooCommerce;
⋮----
use Composer\Autoload\ClassLoader;
⋮----
class Autoloader {
⋮----
private function __construct() {}
⋮----
public static function init() {
⋮----
self::missing_autoloader();
⋮----
public static function build_woocommerce_psr4_fallback(): ?ClassLoader {
⋮----
$loader->setPsr4( $namespace, $paths );
⋮----
// Foreign/ancient ClassLoader shape, or a torn Composer file — skip the
// fallback rather than fatal the bootstrap.
⋮----
/**
	 * Register the WooCommerce-scoped PSR-4 fallback as an appended (lowest-priority)
	 * SPL autoloader, so it is consulted only after every other autoloader — including
	 * the primary Jetpack autoloader — has missed.
	 *
	 * The handler resolves each miss with a throwaway loader (see {@see self::find_scoped_file()})
	 * rather than a single long-lived `ClassLoader`. Composer's `ClassLoader` records a
	 * per-instance negative cache (`missingClasses`) on a PSR-4 miss and short-circuits
	 * subsequent lookups for that class; a shared instance would therefore cache a miss for a
	 * class probed *before* an in-place upgrade swaps the files, then keep refusing that same
	 * class *after* the new file is on disk — for the remainder of the request. A fresh loader
... (51 lines truncated)
</file>

<file path="plugins/woocommerce/src/Container.php">
namespace Automattic\WooCommerce;
⋮----
use Automattic\WooCommerce\Internal\DependencyManagement\ContainerException;
use Automattic\WooCommerce\Internal\DependencyManagement\RuntimeContainer;
⋮----
final class Container {
⋮----
private $container;
⋮----
public function __construct() {
⋮----
public function get( string $id ) {
return $this->container->get( $id );
⋮----
public function has( string $id ): bool {
return $this->container->has( $id );
</file>

<file path="plugins/woocommerce/src/Deprecated.php">
use Automattic\WooCommerce\Admin\Features\Navigation\RemovedDeprecated;
</file>

<file path="plugins/woocommerce/src/Packages.php">
namespace Automattic\WooCommerce;
⋮----
use Automattic\Jetpack\Constants;
⋮----
class Packages {
⋮----
private function __construct() {}
⋮----
protected static $packages = array(
⋮----
protected static $base_packages = array(
⋮----
protected static $merged_packages = array(
⋮----
public static function init() {
⋮----
public static function on_init() {
self::deactivate_merged_packages();
self::initialize_packages();
⋮----
public static function package_exists( $package ) {
⋮----
public static function should_load_class( $class_name ) {
⋮----
protected static function get_enabled_packages() {
⋮----
// Opt out from the feature.
⋮----
public static function is_package_enabled( $package ) {
return array_key_exists( $package, self::get_enabled_packages() );
... (29 lines truncated)
</file>

<file path="plugins/woocommerce/src/README.md">
# WooCommerce `src` files

## Table of contents

* [A note on @internal annotations](#a-note-on-internal-annotations)
* [Installing Composer](#installing-composer)
    * [Updating the autoloader class maps](#updating-the-autoloader-class-maps)
* [Installing packages](#installing-packages)
* [The container](#the-container)
    * [Retrieving classes](#retrieving-classes)
        * [From other classes in the `src` directory](#1-other-classes-in-the-src-directory)
        * [From code in the `includes` directory](#2-code-in-the-includes-directory)
        * [A note on legacy classes](#a-note-on-legacy-classes)
    * [Historical note](#historical-note)
* [The `Internal` namespace](#the-internal-namespace)
* [Interacting with legacy code](#interacting-with-legacy-code)
    * [The `LegacyProxy` class](#the-legacyproxy-class)
    * [Using the legacy proxy](#using-the-legacy-proxy)
    * [Using the mockable proxy in tests](#using-the-mockable-proxy-in-tests)
    * [But how does `get_instance_of` work?](#but-how-does-get_instance_of-work)
    * [Creating specialized proxies](#creating-specialized-proxies)
* [Defining new actions and filters](#defining-new-actions-and-filters)
* [Writing unit tests](#writing-unit-tests)
    * [Mocking dependencies](#mocking-dependencies)
    * [Additional tools for writing unit tests](#additional-tools-for-writing-unit-tests)

This directory is home to new WooCommerce class files under the `Automattic\WooCommerce` namespace using [PSR-4](https://www.php-fig.org/psr/psr-4/) file naming. This is to take full advantage of autoloading.

Ideally, all the new code for WooCommerce should consist of classes following the PSR-4 naming and living in this directory, and the code in [the `includes` directory](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/includes/README.md) should receive the minimum amount of changes required for bug fixing. This will not always be possible but that should be the rule of thumb.

... (301 lines truncated)
</file>

<file path="plugins/woocommerce/templates/auth/footer.php">

</file>

<file path="plugins/woocommerce/templates/auth/form-grant-access.php">

</file>

<file path="plugins/woocommerce/templates/auth/form-login.php">

</file>

<file path="plugins/woocommerce/templates/auth/header.php">
<link rel="stylesheet" href="<?php echo esc_url( str_replace( array( 'http:', 'https:' ), '', WC()->plugin_url() ) . '/assets/css/auth.css' ); ?>" type="text/css" />
⋮----
<img src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/woo-logo.svg' ); ?>" alt="
</file>

<file path="plugins/woocommerce/templates/block-notices/error.php">
<div class="wc-block-components-notice-banner is-error" role="alert" <?php echo $multiple ? '' : wc_get_notice_data_attr( $notices[0] ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
</file>

<file path="plugins/woocommerce/templates/block-notices/notice.php">

</file>

<file path="plugins/woocommerce/templates/block-notices/success.php">

</file>

<file path="plugins/woocommerce/templates/brands/shortcodes/brands-a-z.php">

</file>

<file path="plugins/woocommerce/templates/brands/shortcodes/single-brand.php">

</file>

<file path="plugins/woocommerce/templates/brands/widgets/brand-description.php">

</file>

<file path="plugins/woocommerce/templates/brands/widgets/brand-thumbnails-description.php">
/**
		 * Filter the brand's thumbnail size.
		 *
		 * @since 9.4.0
		 * @param string $size Defaults to 'shop_catalog'
		 */
</file>

<file path="plugins/woocommerce/templates/brands/widgets/brand-thumbnails.php">

</file>

<file path="plugins/woocommerce/templates/brands/brand-description.php">

</file>

<file path="plugins/woocommerce/templates/brands/taxonomy-product_brand.php">

</file>

<file path="plugins/woocommerce/templates/cart/cart-empty.php">

</file>

<file path="plugins/woocommerce/templates/cart/cart-item-data.php">

</file>

<file path="plugins/woocommerce/templates/cart/cart-shipping.php">
$formatted_destination    = isset( $formatted_destination ) ? $formatted_destination : WC()->countries->get_formatted_address( $package['destination'], ', ' );
⋮----
printf( '<input type="radio" name="shipping_method[%1$d]" data-index="%1$d" id="shipping_method_%1$d_%2$s" value="%3$s" class="shipping_method" %4$s />', $index, esc_attr( sanitize_title( $method->id ) ), esc_attr( $method->id ), checked( $method->id, $chosen_method, false ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- %1$d normalizes the package index; the remaining values are escaped or safe attribute markup.
⋮----
printf( '<input type="hidden" name="shipping_method[%1$d]" data-index="%1$d" id="shipping_method_%1$d_%2$s" value="%3$s" class="shipping_method" />', $index, esc_attr( sanitize_title( $method->id ) ), esc_attr( $method->id ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- %1$d normalizes the package index; the remaining attribute values are escaped.
⋮----
printf( '<label for="shipping_method_%1$d_%2$s">%3$s</label>', $index, esc_attr( sanitize_title( $method->id ) ), wc_cart_totals_shipping_method_label( $method ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- %1$d normalizes the package index; the shipping method label is intentionally filterable HTML.
</file>

<file path="plugins/woocommerce/templates/cart/cart-totals.php">
<div class="cart_totals <?php echo ( WC()->customer->has_calculated_shipping() ) ? 'calculated_shipping' : ''; ?>">
⋮----
<?php foreach ( WC()->cart->get_coupons() as $code => $coupon ) : ?>
⋮----
<?php if ( WC()->cart->needs_shipping() && WC()->cart->show_shipping() ) : ?>
⋮----
<?php elseif ( WC()->cart->needs_shipping() && 'yes' === get_option( 'woocommerce_enable_shipping_calc' ) ) : ?>
⋮----
<?php foreach ( WC()->cart->get_fees() as $fee ) : ?>
⋮----
if ( wc_tax_enabled() && ! WC()->cart->display_prices_including_tax() ) {
$taxable_address = WC()->customer->get_taxable_address();
⋮----
if ( WC()->customer->is_customer_outside_base() && ! WC()->customer->has_calculated_shipping() ) {
/* translators: %s location. */
$estimated_text = sprintf( ' <small>' . esc_html__( '(estimated for %s)', 'woocommerce' ) . '</small>', WC()->countries->estimated_for_prefix( $taxable_address[0] ) . WC()->countries->countries[ $taxable_address[0] ] );
⋮----
foreach ( WC()->cart->get_tax_totals() as $code => $tax ) {
⋮----
<th><?php echo esc_html( WC()->countries->tax_or_vat() ) . $estimated_text; ?></th>
<td data-title="<?php echo esc_attr( WC()->countries->tax_or_vat() ); ?>"><?php wc_cart_totals_taxes_total_html(); ?></td>
</file>

<file path="plugins/woocommerce/templates/cart/cart.php">
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
⋮----
if ( $_product instanceof WC_Product && $_product->exists() && $cart_item['quantity'] > 0 && $visible ) {
$cart_item_name = WC()->cart->get_item_product_name( $cart_item, $_product );
⋮----
$product_permalink = apply_filters( 'woocommerce_cart_item_permalink', $_product->is_visible() ? $_product->get_permalink( $cart_item ) : '', $cart_item, $cart_item_key );
⋮----
esc_attr( $_product->get_sku() )
⋮----
$thumbnail = apply_filters( 'woocommerce_cart_item_thumbnail', $_product->get_image(), $cart_item, $cart_item_key );
⋮----
if ( $_product->backorders_require_notification() && $_product->is_on_backorder( $cart_item['quantity'] ) ) {
⋮----
echo apply_filters( 'woocommerce_cart_item_price', WC()->cart->get_product_price( $_product ), $cart_item, $cart_item_key );
⋮----
if ( $_product->is_sold_individually() ) {
⋮----
$max_quantity = $_product->get_max_purchase_quantity();
⋮----
echo apply_filters( 'woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key );
</file>

<file path="plugins/woocommerce/templates/cart/cross-sells.php">
$post_object = get_post( $cross_sell->get_id() );
</file>

<file path="plugins/woocommerce/templates/cart/mini-cart.php">
<?php if ( WC()->cart && ! WC()->cart->is_empty() ) : ?>
⋮----
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
⋮----
if ( $_product instanceof WC_Product && $_product->exists() && $cart_item['quantity'] > 0 && $visible ) {
$cart_item_name = WC()->cart->get_item_product_name( $cart_item, $_product );
⋮----
$thumbnail         = apply_filters( 'woocommerce_cart_item_thumbnail', $_product->get_image(), $cart_item, $cart_item_key );
$product_price     = apply_filters( 'woocommerce_cart_item_price', WC()->cart->get_product_price( $_product ), $cart_item, $cart_item_key );
$product_permalink = apply_filters( 'woocommerce_cart_item_permalink', $_product->is_visible() ? $_product->get_permalink( $cart_item ) : '', $cart_item, $cart_item_key );
⋮----
echo apply_filters( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
⋮----
/* translators: %s is the product name */
⋮----
esc_attr( $_product->get_sku() ),
</file>

<file path="plugins/woocommerce/templates/cart/proceed-to-checkout-button.php">

</file>

<file path="plugins/woocommerce/templates/cart/shipping-calculator.php">
foreach ( WC()->countries->get_shipping_countries() as $key => $value ) {
echo '<option value="' . esc_attr( $key ) . '"' . selected( WC()->customer->get_shipping_country(), esc_attr( $key ), false ) . '>' . esc_html( $value ) . '</option>';
⋮----
$current_cc = WC()->customer->get_shipping_country();
$current_r  = WC()->customer->get_shipping_state();
$states     = WC()->countries->get_states( $current_cc );
⋮----
<input type="text" class="input-text" value="<?php echo esc_attr( WC()->customer->get_shipping_city() ); ?>" name="calc_shipping_city" id="calc_shipping_city" />
⋮----
<input type="text" class="input-text" value="<?php echo esc_attr( WC()->customer->get_shipping_postcode() ); ?>" name="calc_shipping_postcode" id="calc_shipping_postcode" />
</file>

<file path="plugins/woocommerce/templates/checkout/cart-errors.php">

</file>

<file path="plugins/woocommerce/templates/checkout/form-billing.php">
<?php if ( wc_ship_to_billing_address_only() && WC()->cart->needs_shipping() ) : ?>
⋮----
$fields = $checkout->get_checkout_fields( 'billing' );
⋮----
woocommerce_form_field( $key, $field, $checkout->get_value( $key ) );
⋮----
<?php if ( ! is_user_logged_in() && $checkout->is_registration_enabled() ) : ?>
⋮----
<?php if ( ! $checkout->is_registration_required() ) : ?>
⋮----
<input class="woocommerce-form__input woocommerce-form__input-checkbox input-checkbox" id="createaccount" <?php checked( ( true === $checkout->get_value( 'createaccount' ) || ( true === apply_filters( 'woocommerce_create_account_default_checked', false ) ) ), true ); ?> type="checkbox" name="createaccount" value="1" /> <span><?php esc_html_e( 'Create an account?', 'woocommerce' ); ?></span>
⋮----
<?php if ( $checkout->get_checkout_fields( 'account' ) ) : ?>
⋮----
<?php foreach ( $checkout->get_checkout_fields( 'account' ) as $key => $field ) : ?>
<?php woocommerce_form_field( $key, $field, $checkout->get_value( $key ) ); ?>
</file>

<file path="plugins/woocommerce/templates/checkout/form-checkout.php">
if ( ! $checkout->is_registration_enabled() && $checkout->is_registration_required() && ! is_user_logged_in() ) {
⋮----
<?php if ( $checkout->get_checkout_fields() ) : ?>
</file>

<file path="plugins/woocommerce/templates/checkout/form-coupon.php">

</file>

<file path="plugins/woocommerce/templates/checkout/form-login.php">
$registration_at_checkout   = WC_Checkout::instance()->is_registration_enabled();
</file>

<file path="plugins/woocommerce/templates/checkout/form-pay.php">
$totals = $order->get_order_item_totals();
⋮----
<?php if ( count( $order->get_items() ) > 0 ) : ?>
<?php foreach ( $order->get_items() as $item_id => $item ) : ?>
⋮----
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false ) );
⋮----
<td class="product-quantity"><?php echo apply_filters( 'woocommerce_order_item_quantity_html', ' <strong class="product-quantity">' . sprintf( '&times;&nbsp;%s', esc_html( $item->get_quantity() ) ) . '</strong>', $item ); ?></td><?php ?>
<td class="product-subtotal"><?php echo $order->get_formatted_line_subtotal( $item ); ?></td><?php ?>
⋮----
<?php if ( $order->needs_payment() ) : ?>
⋮----
<?php echo apply_filters( 'woocommerce_pay_order_button_html', '<button type="submit" class="button alt' . esc_attr( wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '' ) . '" id="place_order" value="' . esc_attr( $order_button_text ) . '" data-value="' . esc_attr( $order_button_text ) . '">' . esc_html( $order_button_text ) . '</button>' ); // @codingStandardsIgnoreLine ?>
</file>

<file path="plugins/woocommerce/templates/checkout/form-shipping.php">
<?php if ( true === WC()->cart->needs_shipping_address() ) : ?>
⋮----
$fields = $checkout->get_checkout_fields( 'shipping' );
⋮----
woocommerce_form_field( $key, $field, $checkout->get_value( $key ) );
⋮----
<?php $order_fields = $checkout->get_checkout_fields( 'order' ); ?>
⋮----
<?php woocommerce_form_field( $key, $field, $checkout->get_value( $key ) ); ?>
</file>

<file path="plugins/woocommerce/templates/checkout/form-verify-email.php">

</file>

<file path="plugins/woocommerce/templates/checkout/order-receipt.php">
<strong><?php echo esc_html( $order->get_order_number() ); ?></strong>
⋮----
<strong><?php echo esc_html( wc_format_datetime( $order->get_date_created() ) ); ?></strong>
⋮----
<strong><?php echo wp_kses_post( $order->get_formatted_order_total() ); ?></strong>
⋮----
<?php if ( $order->get_payment_method_title() ) : ?>
⋮----
<strong><?php echo wp_kses_post( $order->get_payment_method_title() ); ?></strong>
⋮----
<?php do_action( 'woocommerce_receipt_' . $order->get_payment_method(), $order->get_id() ); ?>
</file>

<file path="plugins/woocommerce/templates/checkout/order-received.php">

</file>

<file path="plugins/woocommerce/templates/checkout/payment-method.php">
<?php echo $gateway->get_title();  ?> <?php echo $gateway->get_icon();  ?>
⋮----
<?php if ( $gateway->has_fields() || $gateway->get_description() ) : ?>
⋮----
<?php $gateway->payment_fields(); ?>
</file>

<file path="plugins/woocommerce/templates/checkout/payment.php">
<?php if ( WC()->cart && WC()->cart->needs_payment() ) : ?>
⋮----
wc_print_notice( apply_filters( 'woocommerce_no_available_payment_methods_message', WC()->customer->get_billing_country() ? esc_html__( 'Sorry, it seems that there are no available payment methods. Please contact us if you require assistance or wish to make alternate arrangements.', 'woocommerce' ) : esc_html__( 'Please fill in your details above to see available payment methods.', 'woocommerce' ) ), 'notice' );
⋮----
<?php echo apply_filters( 'woocommerce_order_button_html', '<button type="submit" class="button alt' . esc_attr( wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '' ) . '" name="woocommerce_checkout_place_order" id="place_order" value="' . esc_attr( $order_button_text ) . '" data-value="' . esc_attr( $order_button_text ) . '">' . esc_html( $order_button_text ) . '</button>' ); // @codingStandardsIgnoreLine ?>
</file>

<file path="plugins/woocommerce/templates/checkout/review-order.php">
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
⋮----
if ( $_product instanceof WC_Product && $_product->exists() && $cart_item['quantity'] > 0 && $visible ) {
⋮----
$cart_item_name = WC()->cart->get_item_product_name( $cart_item, $_product );
⋮----
<?php echo apply_filters( 'woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key ); ?>
⋮----
<?php foreach ( WC()->cart->get_coupons() as $code => $coupon ) : ?>
⋮----
<?php if ( WC()->cart->needs_shipping() && WC()->cart->show_shipping() ) : ?>
⋮----
<?php foreach ( WC()->cart->get_fees() as $fee ) : ?>
⋮----
<?php if ( wc_tax_enabled() && ! WC()->cart->display_prices_including_tax() ) : ?>
⋮----
<?php foreach ( WC()->cart->get_tax_totals() as $code => $tax ) : ?>
⋮----
<th><?php echo esc_html( WC()->countries->tax_or_vat() ); ?></th>
</file>

<file path="plugins/woocommerce/templates/checkout/terms.php">

</file>

<file path="plugins/woocommerce/templates/checkout/thankyou.php">
do_action( 'woocommerce_before_thankyou', $order->get_id() );
⋮----
<?php if ( $order->has_status( 'failed' ) ) : ?>
⋮----
<a href="<?php echo esc_url( $order->get_checkout_payment_url() ); ?>" class="button pay"><?php esc_html_e( 'Pay', 'woocommerce' ); ?></a>
⋮----
<strong><?php echo $order->get_order_number(); ?></strong>
⋮----
<strong><?php echo wc_format_datetime( $order->get_date_created() ); ?></strong>
⋮----
<?php if ( is_user_logged_in() && $order->get_user_id() === get_current_user_id() && $order->get_billing_email() ) : ?>
⋮----
<strong><?php echo $order->get_billing_email(); ?></strong>
⋮----
<strong><?php echo $order->get_formatted_order_total(); ?></strong>
⋮----
<?php if ( $order->get_payment_method_title() ) : ?>
⋮----
<strong><?php echo wp_kses_post( $order->get_payment_method_title() ); ?></strong>
⋮----
<?php do_action( 'woocommerce_thankyou_' . $order->get_payment_method(), $order->get_id() ); ?>
<?php do_action( 'woocommerce_thankyou', $order->get_id() ); ?>
</file>

<file path="plugins/woocommerce/templates/emails/block/admin-cancelled-order.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/admin-failed-order.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/admin-new-order.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/admin-payment-gateway-enabled.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-cancelled-order.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-completed-order.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-failed-order.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-fulfillment-created.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-fulfillment-deleted.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-fulfillment-updated.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-invoice.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-new-account.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-note.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-on-hold-order.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-partially-refunded-order.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-pos-completed-order.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-pos-refunded-order.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-processing-order.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-refunded-order.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-reset-password.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/customer-review-request.php">

</file>

<file path="plugins/woocommerce/templates/emails/block/customer-verify-email.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/default-block-content.php">
use Automattic\WooCommerce\Internal\EmailEditor\BlockEmailRenderer;
</file>

<file path="plugins/woocommerce/templates/emails/block/general-block-content-for-fulfillment-emails.php">

</file>

<file path="plugins/woocommerce/templates/emails/block/general-block-email.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Internal\Settings\PointOfSaleDefaultSettings;
⋮----
<?php if ( $order->needs_payment() ) { ?>
⋮----
if ( $order->has_status( OrderStatus::FAILED ) ) {
⋮----
'<a href="' . esc_url( $order->get_checkout_payment_url() ) . '">' . esc_html__( 'Pay for this order', 'woocommerce' ) . '</a>'
⋮----
printf( esc_html__( 'Here are the details of your order placed on %s:', 'woocommerce' ), esc_html( wc_format_datetime( $order->get_date_created() ) ) );
⋮----
if ( ! empty( get_option( 'woocommerce_pos_store_email', PointOfSaleDefaultSettings::get_default_store_email() ) )
⋮----
|| ! empty( get_option( 'woocommerce_pos_store_address', PointOfSaleDefaultSettings::get_default_store_address() ) ) ) :
⋮----
<?php if ( ! empty( get_option( 'woocommerce_pos_store_name', PointOfSaleDefaultSettings::get_default_store_name() ) ) ) : ?>
⋮----
<h3 class="wp-block-heading"><?php echo esc_html( get_option( 'woocommerce_pos_store_name', PointOfSaleDefaultSettings::get_default_store_name() ) ); ?></h3>
⋮----
<?php if ( ! empty( get_option( 'woocommerce_pos_store_email', PointOfSaleDefaultSettings::get_default_store_email() ) ) ) : ?>
⋮----
<p><?php echo esc_html( get_option( 'woocommerce_pos_store_email', PointOfSaleDefaultSettings::get_default_store_email() ) ); ?></p>
⋮----
<?php if ( ! empty( get_option( 'woocommerce_pos_store_address', PointOfSaleDefaultSettings::get_default_store_address() ) ) ) : ?>
⋮----
<p><?php echo esc_html( get_option( 'woocommerce_pos_store_address', PointOfSaleDefaultSettings::get_default_store_address() ) ); ?></p>
</file>

<file path="plugins/woocommerce/templates/emails/plain/admin-cancelled-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
echo sprintf( esc_html( $text ), esc_html( $order->get_order_number() ), esc_html( $order->get_formatted_billing_full_name() ) ) . "\n\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/admin-failed-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
echo sprintf( esc_html( $text ), esc_html( $order->get_order_number() ), esc_html( $order->get_formatted_billing_full_name() ) ) . "\n\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/admin-new-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
echo sprintf( esc_html( $text ), esc_html( $order->get_formatted_billing_full_name() ) ) . "\n\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/admin-order-withdrawal-requested.php">
absint( $matched_order->get_id() )
⋮----
if ( '' !== $matched_order->get_edit_order_url() ) {
echo esc_url( $matched_order->get_edit_order_url() ) . "\n";
⋮----
/**
 * Filter the email footer text.
 *
 * @param string $footer_text The footer text.
 * @since 2.3.0
 */
</file>

<file path="plugins/woocommerce/templates/emails/plain/admin-payment-gateway-enabled.php">

</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-cancelled-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
echo sprintf( esc_html( $text ), esc_html( $order->get_order_number() ) ) . "\n\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-completed-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
echo sprintf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) ) . "\n\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-failed-order.php">
echo sprintf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) ) . "\n\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-fulfillment-created.php">

</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-fulfillment-deleted.php">

</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-fulfillment-updated.php">

</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-invoice.php">
use Automattic\WooCommerce\Enums\OrderStatus;
⋮----
echo sprintf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) ) . "\n\n";
⋮----
if ( $order->needs_payment() ) {
if ( $order->has_status( OrderStatus::FAILED ) ) {
⋮----
esc_url( $order->get_checkout_payment_url() )
⋮----
echo sprintf( esc_html__( 'Here are the details of your order placed on %s:', 'woocommerce' ), esc_html( wc_format_datetime( $order->get_date_created() ) ) ) . "\n\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-new-account.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-note.php">
echo sprintf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) ) . "\n\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-on-hold-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
echo sprintf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) ) . "\n\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-order-withdrawal-requested.php">

</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-pos-completed-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
if ( ! empty( $order->get_billing_first_name() ) ) {
⋮----
echo sprintf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) ) . "\n\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-pos-refunded-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
if ( ! empty( $order->get_billing_first_name() ) ) {
⋮----
echo sprintf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) ) . "\n\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-processing-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
echo sprintf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) ) . "\n\n";
⋮----
echo sprintf( esc_html__( 'Just to let you know &mdash; we\'ve received your order #%s, and it is now being processed:', 'woocommerce' ), esc_html( $order->get_order_number() ) ) . "\n\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-refunded-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
echo sprintf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) ) . "\n\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-reset-password.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-review-request.php">
if ( ! empty( $order->get_billing_first_name() ) ) {
⋮----
echo sprintf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) ) . "\n\n";
⋮----
$date_created = $order->get_date_created();
⋮----
esc_html( $order->get_order_number() ),
⋮----
/**
 * Show user-defined additional content - this is set in each email's settings.
 */
</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-stock-notification-verified.php">

</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-stock-notification-verify.php">

</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-stock-notification.php">

</file>

<file path="plugins/woocommerce/templates/emails/plain/customer-verify-email.php">

</file>

<file path="plugins/woocommerce/templates/emails/plain/email-addresses.php">
echo preg_replace( '#<br\s*/?>#i', "\n", $order->get_formatted_billing_address() ) . "\n";
⋮----
if ( $order->get_billing_phone() ) {
echo $order->get_billing_phone() . "\n";
⋮----
if ( $order->get_billing_email() ) {
echo $order->get_billing_email() . "\n";
⋮----
if ( ! wc_ship_to_billing_address_only() && $order->needs_shipping_address() ) {
$shipping = $order->get_formatted_shipping_address();
⋮----
if ( $order->get_shipping_phone() ) {
echo $order->get_shipping_phone() . "\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/email-customer-details.php">

</file>

<file path="plugins/woocommerce/templates/emails/plain/email-downloads.php">

</file>

<file path="plugins/woocommerce/templates/emails/plain/email-fulfillment-details.php">
if ( null === $fulfillment->get_date_deleted() ) {
$tracking_number   = $fulfillment->get_meta( '_tracking_number', true );
$tracking_url      = $fulfillment->get_meta( '_tracking_url' );
$shipment_provider = $fulfillment->get_meta( '_shipment_provider' );
⋮----
$after  = '(' . esc_url( $order->get_edit_order_url() ) . ')';
⋮----
/* translators: %s: Order ID. */
</file>

<file path="plugins/woocommerce/templates/emails/plain/email-fulfillment-items.php">
$product       = $item->item->get_product();
⋮----
$sku           = $product->get_sku();
$purchase_note = $product->get_purchase_note();
⋮----
/**
		 * Email Order Item Name hook.
		 *
		 * @since 2.1.0
		 * @since 2.4.0 Added $is_visible parameter.
		 * @param string        $product_name Product name.
		 * @param WC_Order_Item $item Order item object.
		 * @param bool          $is_visible Is item visible.
		 */
$product_name = apply_filters( 'woocommerce_order_item_name', $item->item->get_name(), $item->item, false );
⋮----
echo esc_html( str_pad( wp_kses( $order->get_formatted_line_subtotal( $item->item ), array() ), 20, ' ', STR_PAD_LEFT ) ) . "\n";
⋮----
// SKU.
</file>

<file path="plugins/woocommerce/templates/emails/plain/email-order-details.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
echo wp_kses_post( sprintf( esc_html__( 'Order #%1$s (%2$s)', 'woocommerce' ), $order->get_order_number(), wc_format_datetime( $order->get_date_created() ) ) ) . "\n";
⋮----
echo wp_kses_post( wc_strtoupper( sprintf( esc_html__( '[Order #%1$s] (%2$s)', 'woocommerce' ), $order->get_order_number(), wc_format_datetime( $order->get_date_created() ) ) ) ) . "\n";
⋮----
$item_totals = $order->get_order_item_totals();
⋮----
if ( (bool) apply_filters( 'woocommerce_email_order_shipping_show_free_label', $order->has_shipping_method( 'free_shipping' ), $order ) ) {
⋮----
if ( $order->get_customer_note() ) {
⋮----
echo "\n" . esc_html__( 'Note:', 'woocommerce' ) . "\n" . wp_kses( wc_wptexturize_order_note( $order->get_customer_note() ), array() ) . "\n";
⋮----
echo esc_html__( 'Note:', 'woocommerce' ) . "\t " . wp_kses( wc_wptexturize_order_note( $order->get_customer_note() ), array() ) . "\n";
⋮----
echo "\n" . sprintf( esc_html__( 'View order: %s', 'woocommerce' ), esc_url( $order->get_edit_order_url() ) ) . "\n";
</file>

<file path="plugins/woocommerce/templates/emails/plain/email-order-items.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
$product       = $item->get_product();
⋮----
$sku           = $product->get_sku();
$purchase_note = $product->get_purchase_note();
⋮----
/**
			 * Email Order Item Name hook.
			 *
			 * @since 2.1.0
			 * @since 2.4.0 Added $is_visible parameter.
			 * @param string        $product_name Product name.
			 * @param WC_Order_Item $item Order item object.
			 * @param bool          $is_visible Is item visible.
			 */
$product_name = apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false );
⋮----
$quantity = apply_filters( 'woocommerce_email_order_item_quantity', $item->get_quantity(), $item );
⋮----
echo esc_html( str_pad( wp_kses( $order->get_formatted_line_subtotal( $item ), array() ), 20, ' ', STR_PAD_LEFT ) ) . "\n";
⋮----
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false ) );
⋮----
echo ' = ' . $order->get_formatted_line_subtotal( $item ) . "\n";
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
⋮----
// allow other plugins to add additional product information here.
... (1 lines truncated)
</file>

<file path="plugins/woocommerce/templates/emails/admin-cancelled-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
/* translators: %1$s: Order number. %2$s: Customer full name */
⋮----
$text = __( 'We’re getting in touch to let you know that order #%1$s from %2$s has been cancelled.', 'woocommerce' );
⋮----
<p><?php printf( esc_html( $text ), esc_html( $order->get_order_number() ), esc_html( $order->get_formatted_billing_full_name() ) ); ?></p>
⋮----
/*
 * @hooked WC_Emails::order_details() Shows the order details table.
 * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
 * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
 * @since 2.5.0
 */
⋮----
/*
 * @hooked WC_Emails::email_footer() Output the email footer
 */
</file>

<file path="plugins/woocommerce/templates/emails/admin-failed-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
/* translators: %1$s: Order number. %2$s: Customer full name. */
⋮----
$text = __( 'Unfortunately, the payment for order #%1$s from %2$s has failed. The order was as follows:', 'woocommerce' );
⋮----
<p><?php printf( esc_html( $text ), esc_html( $order->get_order_number() ), esc_html( $order->get_formatted_billing_full_name() ) ); ?></p>
⋮----
/*
 * @hooked WC_Emails::order_details() Shows the order details table.
 * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
 * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
 * @since 2.5.0
 */
⋮----
/*
 * @hooked WC_Emails::email_footer() Output the email footer
*/
</file>

<file path="plugins/woocommerce/templates/emails/admin-new-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
/* translators: %s: Customer billing full name */
⋮----
<p><?php printf( esc_html( $text ), esc_html( $order->get_formatted_billing_full_name() ) ); ?></p>
⋮----
/*
 * @hooked WC_Emails::order_details() Shows the order details table.
 * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
 * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
 * @since 2.5.0
 */
⋮----
/*
 * @hooked WC_Emails::email_footer() Output the email footer
 */
</file>

<file path="plugins/woocommerce/templates/emails/admin-order-withdrawal-requested.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
/* translators: %d: order ID. */
⋮----
absint( $matched_order->get_id() )
⋮----
<?php if ( '' !== $matched_order->get_edit_order_url() ) : ?>
<p><a href="<?php echo esc_url( $matched_order->get_edit_order_url() ); ?>"><?php esc_html_e( 'View matched order', 'woocommerce' ); ?></a></p>
⋮----
/**
 * Fires to output the email footer.
 *
 * @hooked WC_Emails::email_footer()
 * @since 3.7.0
 */
</file>

<file path="plugins/woocommerce/templates/emails/admin-payment-gateway-enabled.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
/* translators: %s: Username */
⋮----
/* translators: 1: gateway title, 2: site URL */
⋮----
/**
 * Output the email footer.
 *
 * @hooked WC_Emails::email_footer() Output the email footer.
 * @since 10.6.0
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-cancelled-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
/* translators: %1$s: Order number */
⋮----
$text = __( 'We’re getting in touch to let you know that your order #%1$s has been cancelled.', 'woocommerce' );
⋮----
<p><?php printf( esc_html( $text ), esc_html( $order->get_order_number() ) ); ?></p>
⋮----
/**
 * Hook: woocommerce_email_order_details.
 *
 * @hooked WC_Emails::order_details() Shows the order details table.
 * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
 * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
 * @since 2.5.0
 */
⋮----
/**
 * Hook: woocommerce_email_footer.
 *
 * @hooked WC_Emails::email_footer() Output the email footer
 * @since 2.5.0
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-completed-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
if ( ! empty( $order->get_billing_first_name() ) ) {
/* translators: %s: Customer first name */
printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) );
⋮----
/*
 * @hooked WC_Emails::order_details() Shows the order details table.
 * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
 * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
 * @since 2.5.0
 */
⋮----
/*
 * @hooked WC_Emails::email_footer() Output the email footer
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-failed-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
if ( ! empty( $order->get_billing_first_name() ) ) {
/* translators: %s: Customer first name */
printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) );
⋮----
/**
 * Hook for the woocommerce_email_order_details.
 *
 * @hooked WC_Emails::order_details() Shows the order details table.
 * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
 * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
 * @since 2.5.0
 */
⋮----
/**
 * Hook for the woocommerce_email_footer.
 *
 * @hooked WC_Emails::email_footer() Output the email footer
 * @since 3.7.0
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-fulfillment-created.php">

</file>

<file path="plugins/woocommerce/templates/emails/customer-fulfillment-deleted.php">

</file>

<file path="plugins/woocommerce/templates/emails/customer-fulfillment-updated.php">

</file>

<file path="plugins/woocommerce/templates/emails/customer-invoice.php">
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
if ( ! empty( $order->get_billing_first_name() ) ) {
/* translators: %s: Customer first name */
printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) );
⋮----
<?php if ( $order->needs_payment() ) { ?>
⋮----
if ( $order->has_status( OrderStatus::FAILED ) ) {
⋮----
'<a href="' . esc_url( $order->get_checkout_payment_url() ) . '" class="email-payment-link">' . esc_html__( 'Pay for this order', 'woocommerce' ) . '</a>'
⋮----
printf( esc_html__( 'Here are the details of your order placed on %s:', 'woocommerce' ), esc_html( wc_format_datetime( $order->get_date_created() ) ) );
⋮----
/**
 * Hook for the woocommerce_email_order_details.
 *
 * @hooked WC_Emails::order_details() Shows the order details table.
 * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
 * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
 * @since 2.5.0
 */
⋮----
/**
 * Executes the email footer.
 *
 * @hooked WC_Emails::email_footer() Output the email footer
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/templates/emails/customer-new-account.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
<?php /* translators: %s: Customer first name, or username if name is not available */ ?>
⋮----
/**
 * Show user-defined additional content - this is set in each email's settings.
 */
⋮----
/**
 * Fires to output the email footer.
 *
 * @hooked WC_Emails::email_footer()
 *
 * @since 3.7.0
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-note.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
if ( ! empty( $order->get_billing_first_name() ) ) {
/* translators: %s: Customer first name */
printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) );
⋮----
/*
 * @hooked WC_Emails::order_details() Shows the order details table.
 * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
 * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
 * @since 2.5.0
 */
⋮----
/*
 * @hooked WC_Emails::email_footer() Output the email footer
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-on-hold-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
if ( ! empty( $order->get_billing_first_name() ) ) {
/* translators: %s: Customer first name */
printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) );
⋮----
/*
 * @hooked WC_Emails::order_details() Shows the order details table.
 * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
 * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
 * @since 2.5.0
 */
⋮----
/*
 * @hooked WC_Emails::email_footer() Output the email footer
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-order-withdrawal-requested.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
/**
 * Fires to output the email footer.
 *
 * @hooked WC_Emails::email_footer()
 * @since 3.7.0
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-pos-completed-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
if ( ! empty( $order->get_billing_first_name() ) ) {
⋮----
printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) );
⋮----
/**
 * Show store information - store details are set in the Point of Sale settings.
 */
⋮----
/**
 * Show refund & returns policy - this is set in the Point of Sale settings.
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-pos-refunded-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
if ( ! empty( $order->get_billing_first_name() ) ) {
⋮----
printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) );
⋮----
/**
 * Show store information - store details are set in the Point of Sale settings.
 */
⋮----
/**
 * Show refund & returns policy - this is set in the Point of Sale settings.
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-processing-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
if ( ! empty( $order->get_billing_first_name() ) ) {
/* translators: %s: Customer first name */
printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) );
⋮----
<p><?php printf( esc_html__( 'Just to let you know &mdash; we\'ve received your order #%s, and it is now being processed:', 'woocommerce' ), esc_html( $order->get_order_number() ) ); ?></p>
⋮----
/*
 * @hooked WC_Emails::order_details() Shows the order details table.
 * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
 * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
 * @since 2.5.0
 */
⋮----
/*
 * @hooked WC_Emails::email_footer() Output the email footer
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-refunded-order.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
if ( ! empty( $order->get_billing_first_name() ) ) {
/* translators: %s: Customer first name */
printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) );
⋮----
/*
 * @hooked WC_Emails::order_details() Shows the order details table.
 * @hooked WC_Structured_Data::generate_order_data() Generates structured data.
 * @hooked WC_Structured_Data::output_structured_data() Outputs structured data.
 * @since 2.5.0
 */
⋮----
/*
 * @hooked WC_Emails::email_footer() Output the email footer
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-reset-password.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
<?php /* translators: %s: Customer first name, or username if name is not available */ ?>
⋮----
/**
 * Show user-defined additional content - this is set in each email's settings.
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-review-request.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
if ( ! empty( $order->get_billing_first_name() ) ) {
/* translators: %s: Customer first name */
printf( esc_html__( 'Hi %s,', 'woocommerce' ), esc_html( $order->get_billing_first_name() ) );
⋮----
$date_created = $order->get_date_created();
⋮----
/* translators: 1: order number, 2: order date */
⋮----
/**
 * Show user-defined additional content - this is set in each email's settings.
 */
⋮----
/**
 * Hook for the woocommerce_email_footer.
 *
 * @param WC_Email $email The email object.
 * @since 2.5.0
 *
 * @hooked WC_Emails::email_footer() Output the email footer
 */
</file>

<file path="plugins/woocommerce/templates/emails/customer-stock-notification-verified.php">

</file>

<file path="plugins/woocommerce/templates/emails/customer-stock-notification-verify.php">

</file>

<file path="plugins/woocommerce/templates/emails/customer-stock-notification.php">

</file>

<file path="plugins/woocommerce/templates/emails/customer-verify-email.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
<?php /* translators: %s: Customer first name, or username if name is not available. */ ?>
⋮----
/**
 * Show user-defined additional content - this is set in each email's settings.
 */
⋮----
/**
 * Fires to output the email footer.
 *
 * @hooked WC_Emails::email_footer()
 *
 * @since 3.7.0
 */
</file>

<file path="plugins/woocommerce/templates/emails/email-addresses.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$address  = $order->get_formatted_billing_address();
$shipping = $order->get_formatted_shipping_address();
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
<?php if ( $order->get_billing_phone() ) : ?>
<br/><?php echo wc_make_phone_clickable( $order->get_billing_phone() ); ?>
⋮----
<?php if ( $order->get_billing_email() ) : ?>
<br/><?php echo esc_html( $order->get_billing_email() ); ?>
⋮----
<?php if ( ! wc_ship_to_billing_address_only() && $order->needs_shipping_address() && $shipping ) : ?>
⋮----
<?php if ( $order->get_shipping_phone() ) : ?>
<br /><?php echo wc_make_phone_clickable( $order->get_shipping_phone() ); ?>
</file>

<file path="plugins/woocommerce/templates/emails/email-button.php">

</file>

<file path="plugins/woocommerce/templates/emails/email-customer-details.php">

</file>

<file path="plugins/woocommerce/templates/emails/email-downloads.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
</file>

<file path="plugins/woocommerce/templates/emails/email-footer.php">

</file>

<file path="plugins/woocommerce/templates/emails/email-fulfillment-details.php">
if ( null === $fulfillment->get_date_deleted() ) {
$tracking_number   = $fulfillment->get_meta( '_tracking_number', true );
$tracking_url      = $fulfillment->get_meta( '_tracking_url' );
$shipment_provider = $fulfillment->get_meta( '_shipment_provider' );
⋮----
$before = '<a class="link" href="' . esc_url( $order->get_edit_order_url() ) . '">';
⋮----
/* translators: %s: Order ID. */
⋮----
echo wp_kses_post( $before . sprintf( $order_number_string . $after . ' (<time datetime="%s">%s</time>)', $order->get_order_number(), $order->get_date_created()->format( 'c' ), wc_format_datetime( $order->get_date_created() ) ) );
</file>

<file path="plugins/woocommerce/templates/emails/email-fulfillment-items.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$product       = $item->item->get_product();
⋮----
/**
	 * Email Order Item Visibility hook.
	 *
	 * This filter allows you to control the visibility of order items in emails.
	 *
	 * @param bool $visible Whether the item is visible in the email.
	 * @param WC_Order_Item_Product $item The order item object.
	 * @since 2.1.0
	 */
⋮----
$sku           = $product->get_sku();
$purchase_note = $product->get_purchase_note();
$image         = $product->get_image( $image_size );
⋮----
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', $item->item->get_name(), $item->item, false ) );
⋮----
<?php echo wp_kses_post( $order->get_formatted_line_subtotal( $item->item ) ); ?>
</file>

<file path="plugins/woocommerce/templates/emails/email-header.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
</file>

<file path="plugins/woocommerce/templates/emails/email-mobile-messaging.php">
use Automattic\WooCommerce\Internal\Orders\MobileMessagingHandler;
⋮----
echo wp_kses_post( MobileMessagingHandler::prepare_mobile_message( $order, $blog_id, $now, $domain ) );
</file>

<file path="plugins/woocommerce/templates/emails/email-order-details.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
$block_email_editor_enabled = FeaturesUtil::feature_is_enabled( 'block_email_editor' );
⋮----
/**
	 * Filter the heading text shown in the order details section of emails.
	 *
	 * @since 10.8.0
	 * @param string   $heading The heading text.
	 * @param WC_Order $order   Order object.
	 * @param WC_Email $email   Email object.
	 */
⋮----
$before = '<a class="link" href="' . esc_url( $order->get_edit_order_url() ) . '"' . ( $block_email_editor_enabled ? ' style="text-decoration: none;"' : '' ) . '>';
⋮----
// Only output <br> when both a heading and order number are shown; otherwise, avoid leading line break.
⋮----
/* translators: %s: Order ID. */
⋮----
$order_number_string = __( 'Order #%s', 'woocommerce' );
⋮----
echo wp_kses_post( $before . sprintf( $order_number_string . $after . ' (<time datetime="%s">%s</time>)', $order->get_order_number(), $order->get_date_created()->format( 'c' ), wc_format_datetime( $order->get_date_created() ) ) );
⋮----
$item_totals       = $order->get_order_item_totals();
⋮----
if ( (bool) apply_filters( 'woocommerce_email_order_shipping_show_free_label', $order->has_shipping_method( 'free_shipping' ), $order ) ) {
⋮----
if ( $order->get_customer_note() && ! $email_improvements_enabled ) {
⋮----
... (6 lines truncated)
</file>

<file path="plugins/woocommerce/templates/emails/email-order-items.php">
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
⋮----
$block_email_editor_enabled = FeaturesUtil::feature_is_enabled( 'block_email_editor' );
⋮----
$product       = $item->get_product();
⋮----
/**
	 * Email Order Item Visibility hook.
	 *
	 * @param bool                  $visible Whether the order item is visible.
	 * @param WC_Order_Item_Product $item    The item being displayed.
	 * @since 2.1.0
	 */
⋮----
$sku           = $product->get_sku();
$purchase_note = $product->get_purchase_note();
$image         = $product->get_image( $image_size );
⋮----
$order_item_name = apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false );
⋮----
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false ) );
⋮----
$qty          = $item->get_quantity();
$refunded_qty = $order->get_qty_refunded_for_item( $item_id );
⋮----
<?php echo wp_kses_post( $order->get_formatted_line_subtotal( $item ) ); ?>
</file>

<file path="plugins/woocommerce/templates/emails/email-styles.php">
use Automattic\WooCommerce\Internal\Email\EmailFont;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
⋮----
$email_improvements_enabled = FeaturesUtil::feature_is_enabled( 'email_improvements' );
$block_email_editor_enabled = FeaturesUtil::feature_is_enabled( 'block_email_editor' );
</file>

<file path="plugins/woocommerce/templates/global/breadcrumb.php">

</file>

<file path="plugins/woocommerce/templates/global/form-login.php">
<?php echo ( $message ) ? wpautop( wptexturize( $message ) ) : ''; // @codingStandardsIgnoreLine ?>
</file>

<file path="plugins/woocommerce/templates/global/quantity-input.php">

</file>

<file path="plugins/woocommerce/templates/global/sidebar.php">

</file>

<file path="plugins/woocommerce/templates/global/wrapper-end.php">

</file>

<file path="plugins/woocommerce/templates/global/wrapper-start.php">

</file>

<file path="plugins/woocommerce/templates/loop/add-to-cart.php">
$aria_describedby = isset( $args['aria-describedby_text'] ) ? sprintf( 'aria-describedby="woocommerce_loop_add_to_cart_link_describedby_%s"', esc_attr( $product->get_id() ) ) : '';
⋮----
/**
 * Filters the loop add-to-cart link HTML.
 *
 * @param string     $link    The add-to-cart link HTML.
 * @param WC_Product $product The product object.
 * @param array      $args    Arguments used to build the link.
 *
 * @since 2.0.0
 */
echo apply_filters( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- The public filter intentionally allows extensions to return link markup.
⋮----
esc_url( $product->add_to_cart_url() ),
⋮----
esc_html( $product->add_to_cart_text() )
⋮----
<span id="woocommerce_loop_add_to_cart_link_describedby_<?php echo esc_attr( $product->get_id() ); ?>" class="screen-reader-text">
</file>

<file path="plugins/woocommerce/templates/loop/header.php">

</file>

<file path="plugins/woocommerce/templates/loop/loop-end.php">

</file>

<file path="plugins/woocommerce/templates/loop/loop-start.php">

</file>

<file path="plugins/woocommerce/templates/loop/no-products-found.php">

</file>

<file path="plugins/woocommerce/templates/loop/orderby.php">

</file>

<file path="plugins/woocommerce/templates/loop/pagination.php">

</file>

<file path="plugins/woocommerce/templates/loop/price.php">
<?php if ( $price_html = $product->get_price_html() ) : ?>
</file>

<file path="plugins/woocommerce/templates/loop/rating.php">
echo wc_get_rating_html( $product->get_average_rating() );
</file>

<file path="plugins/woocommerce/templates/loop/result-count.php">
// phpcs:disable WordPress.Security
</file>

<file path="plugins/woocommerce/templates/loop/sale-flash.php">
<?php if ( $product->is_on_sale() ) : ?>
</file>

<file path="plugins/woocommerce/templates/myaccount/dashboard.php">

</file>

<file path="plugins/woocommerce/templates/myaccount/downloads.php">
$downloads     = WC()->customer->get_downloadable_products();
</file>

<file path="plugins/woocommerce/templates/myaccount/form-add-payment-method.php">
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
⋮----
current( $available_gateways )->set_current();
⋮----
<label for="payment_method_<?php echo esc_attr( $gateway->id ); ?>"><?php echo wp_kses_post( $gateway->get_title() ); ?> <?php echo wp_kses_post( $gateway->get_icon() ); ?></label>
⋮----
if ( $gateway->has_fields() || $gateway->get_description() ) {
⋮----
$gateway->payment_fields();
</file>

<file path="plugins/woocommerce/templates/myaccount/form-edit-account.php">

</file>

<file path="plugins/woocommerce/templates/myaccount/form-edit-address.php">

</file>

<file path="plugins/woocommerce/templates/myaccount/form-login.php">

</file>

<file path="plugins/woocommerce/templates/myaccount/form-lost-password.php">

</file>

<file path="plugins/woocommerce/templates/myaccount/form-order-withdrawal.php">
/* translators: %s: Email address. */
⋮----
<input type="radio" class="input-radio" name="<?php echo esc_attr( $withdrawal_type_name ); ?>" id="<?php echo esc_attr( $withdrawal_type_id . '_' . $option_value ); ?>" value="<?php echo esc_attr( $option_value ); ?>" <?php checked( $data['withdrawal_type'] ?? '', $option_value ); ?> aria-required="true" <?php echo wc_implode_html_attributes( $withdrawal_type_error_attributes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> />
</file>

<file path="plugins/woocommerce/templates/myaccount/form-reset-password.php">

</file>

<file path="plugins/woocommerce/templates/myaccount/lost-password-confirmation.php">

</file>

<file path="plugins/woocommerce/templates/myaccount/my-account.php">

</file>

<file path="plugins/woocommerce/templates/myaccount/my-address.php">

</file>

<file path="plugins/woocommerce/templates/myaccount/my-downloads.php">
$downloads = WC()->customer->get_downloadable_products();
</file>

<file path="plugins/woocommerce/templates/myaccount/my-orders.php">
$item_count = $order->get_item_count();
⋮----
<a href="<?php echo esc_url( $order->get_view_order_url() ); ?>">
<?php echo _x( '#', 'hash before order number', 'woocommerce' ) . $order->get_order_number(); ?>
⋮----
<time datetime="<?php echo esc_attr( $order->get_date_created()->date( 'c' ) ); ?>"><?php echo esc_html( wc_format_datetime( $order->get_date_created() ) ); ?></time>
⋮----
<?php echo esc_html( wc_get_order_status_name( $order->get_status() ) ); ?>
⋮----
printf( _n( '%1$s for %2$s item', '%1$s for %2$s items', $item_count, 'woocommerce' ), $order->get_formatted_order_total(), $item_count );
</file>

<file path="plugins/woocommerce/templates/myaccount/navigation.php">

</file>

<file path="plugins/woocommerce/templates/myaccount/orders.php">
$item_count = $order->get_item_count() - $order->get_item_count_refunded();
⋮----
<tr class="woocommerce-orders-table__row woocommerce-orders-table__row--status-<?php echo esc_attr( $order->get_status() ); ?> order">
⋮----
<a href="<?php echo esc_url( $order->get_view_order_url() ); ?>" aria-label="<?php echo esc_attr( sprintf( __( 'View order number %s', 'woocommerce' ), $order->get_order_number() ) ); ?>">
<?php echo esc_html( _x( '#', 'hash before order number', 'woocommerce' ) . $order->get_order_number() ); ?>
⋮----
<time datetime="<?php echo esc_attr( $order->get_date_created()->date( 'c' ) ); ?>"><?php echo esc_html( wc_format_datetime( $order->get_date_created() ) ); ?></time>
⋮----
<?php echo esc_html( wc_get_order_status_name( $order->get_status() ) ); ?>
⋮----
echo wp_kses_post( sprintf( _n( '%1$s for %2$s item', '%1$s for %2$s items', $item_count, 'woocommerce' ), $order->get_formatted_order_total(), $item_count ) );
⋮----
$action_aria_label = sprintf( __( '%1$s order number %2$s', 'woocommerce' ), $action['name'], $order->get_order_number() );
</file>

<file path="plugins/woocommerce/templates/myaccount/payment-methods.php">
<?php if ( WC()->payment_gateways->get_available_payment_gateways() ) : ?>
</file>

<file path="plugins/woocommerce/templates/myaccount/stock-notifications.php">

</file>

<file path="plugins/woocommerce/templates/myaccount/view-order.php">
$notes = $order->get_customer_order_notes();
⋮----
'<mark class="order-number">' . $order->get_order_number() . '</mark>',
'<mark class="order-date">' . wc_format_datetime( $order->get_date_created() ) . '</mark>',
'<mark class="order-status">' . wc_get_order_status_name( $order->get_status() ) . '</mark>'
</file>

<file path="plugins/woocommerce/templates/notices/error.php">

</file>

<file path="plugins/woocommerce/templates/notices/notice.php">

</file>

<file path="plugins/woocommerce/templates/notices/success.php">

</file>

<file path="plugins/woocommerce/templates/order/attribution-details.php">
<?php if ( class_exists( 'WC_Marketplace_Suggestions' ) && \WC_Marketplace_Suggestions::allow_suggestions() ) : ?>
</file>

<file path="plugins/woocommerce/templates/order/customer-history.php">

</file>

<file path="plugins/woocommerce/templates/order/customer-review-order-empty.php">
$meta_parts = \Automattic\WooCommerce\Internal\OrderReviews\Meta::parts_for_order( $order );
</file>

<file path="plugins/woocommerce/templates/order/customer-review-order-row.php">
$item_id      = $item->get_id();
$product_id   = $product->get_id();
$product_link = $product->is_visible() ? get_permalink( $product_id ) : '';
$product_name = $item->get_name();
$image_html   = $product->get_image( 'woocommerce_thumbnail' );
⋮----
$variation_summary = \Automattic\WooCommerce\Internal\OrderReviews\ItemEligibility::format_variation_summary( $item );
⋮----
$rating_control = \Automattic\WooCommerce\Internal\OrderReviews\StarRating::render(
⋮----
<?php echo $image_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- get_image() returns escaped HTML. ?>
</file>

<file path="plugins/woocommerce/templates/order/customer-review-order.php">
$meta_parts = \Automattic\WooCommerce\Internal\OrderReviews\Meta::parts_for_order( $order );
⋮----
$items = (array) apply_filters( 'woocommerce_review_order_eligible_items', $order->get_items(), $order );
⋮----
\Automattic\WooCommerce\Internal\OrderReviews\ItemEligibility::preload_for_items( $items, $order );
⋮----
$product = $item->get_product();
⋮----
$decision = \Automattic\WooCommerce\Internal\OrderReviews\ItemEligibility::decide( $item, $order );
⋮----
$order_key       = (string) $order->get_order_key();
⋮----
<input type="hidden" name="order_id" value="<?php echo esc_attr( (string) $order->get_id() ); ?>" />
⋮----
$prefill = \Automattic\WooCommerce\Internal\OrderReviews\ItemEligibility::prefill_for_item( $item, $order );
</file>

<file path="plugins/woocommerce/templates/order/form-tracking.php">

</file>

<file path="plugins/woocommerce/templates/order/order-again.php">

</file>

<file path="plugins/woocommerce/templates/order/order-details-customer.php">
$show_shipping = ! wc_ship_to_billing_address_only() && $order->needs_shipping_address();
⋮----
<?php echo wp_kses_post( $order->get_formatted_billing_address( esc_html__( 'N/A', 'woocommerce' ) ) ); ?>
⋮----
<?php if ( $order->get_billing_phone() ) : ?>
<p class="woocommerce-customer-details--phone"><?php echo esc_html( $order->get_billing_phone() ); ?></p>
⋮----
<?php if ( $order->get_billing_email() ) : ?>
<p class="woocommerce-customer-details--email"><?php echo esc_html( $order->get_billing_email() ); ?></p>
⋮----
<?php echo wp_kses_post( $order->get_formatted_shipping_address( esc_html__( 'N/A', 'woocommerce' ) ) ); ?>
⋮----
<?php if ( $order->get_shipping_phone() ) : ?>
<p class="woocommerce-customer-details--phone"><?php echo esc_html( $order->get_shipping_phone() ); ?></p>
</file>

<file path="plugins/woocommerce/templates/order/order-details-fulfillment-item.php">
$is_visible        = $product && $product->is_visible();
$product_permalink = apply_filters( 'woocommerce_order_item_permalink', $is_visible ? $product->get_permalink( $item ) : '', $item, $order );
⋮----
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', $product_permalink ? sprintf( '<a href="%s">%s</a>', $product_permalink, $item->get_name() ) : $item->get_name(), $item, $is_visible ) );
⋮----
$refunded_qty = $is_pending_item ? $order->get_qty_refunded_for_item( $item_id ) : 0;
⋮----
$item->set_subtotal(
$item->get_subtotal() * $quantity / $item->get_quantity()
⋮----
echo $order->get_formatted_line_subtotal( $item );
</file>

<file path="plugins/woocommerce/templates/order/order-details-fulfillments.php">
use Automattic\WooCommerce\Admin\Features\Fulfillments\FulfillmentUtils;
⋮----
$order_items        = $order->get_items( apply_filters( 'woocommerce_purchase_order_item_types', 'line_item' ) );
$show_purchase_note = $order->has_status( apply_filters( 'woocommerce_purchase_note_order_statuses', array( 'completed', 'processing' ) ) );
$downloads          = $order->get_downloadable_items();
⋮----
$show_customer_details = $order->get_user_id() === get_current_user_id();
⋮----
$fulfillments_data_store = \WC_Data_Store::load( 'order-fulfillment' );
$fulfillments            = $fulfillments_data_store->read_fulfillments( WC_Order::class, (string) $order->get_id() );
⋮----
if ( FulfillmentUtils::has_pending_items( $order, $fulfillments ) ) {
$pending_items = FulfillmentUtils::get_pending_items( $order, $fulfillments );
⋮----
$product = $item['item']->get_product();
⋮----
'purchase_note'      => $product ? $product->get_purchase_note() : '',
⋮----
if ( ! $fulfillment->get_is_fulfilled() ) {
⋮----
$fulfillment_items = FulfillmentUtils::get_fulfillment_items( $order, $fulfillment );
⋮----
foreach ( $actions as $key => $action ) { // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
⋮----
$action_aria_label = sprintf( __( '%1$s order number %2$s', 'woocommerce' ), $action['name'], $order->get_order_number() );
⋮----
foreach ( $order->get_order_item_totals() as $key => $total ) {
⋮----
<?php if ( $order->get_customer_note() ) : ?>
⋮----
... (2 lines truncated)
</file>

<file path="plugins/woocommerce/templates/order/order-details-item.php">
$is_visible        = $product && $product->is_visible();
$product_permalink = apply_filters( 'woocommerce_order_item_permalink', $is_visible ? $product->get_permalink( $item ) : '', $item, $order );
⋮----
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', $product_permalink ? sprintf( '<a href="%s">%s</a>', $product_permalink, $item->get_name() ) : $item->get_name(), $item, $is_visible ) );
⋮----
$qty          = $item->get_quantity();
$refunded_qty = $order->get_qty_refunded_for_item( $item_id );
⋮----
<?php echo $order->get_formatted_line_subtotal( $item ); ?>
</file>

<file path="plugins/woocommerce/templates/order/order-details.php">
$order_items        = $order->get_items( apply_filters( 'woocommerce_purchase_order_item_types', 'line_item' ) );
$show_purchase_note = $order->has_status( apply_filters( 'woocommerce_purchase_note_order_statuses', array( 'completed', 'processing' ) ) );
$downloads          = $order->get_downloadable_items();
⋮----
$show_customer_details = $order->get_user_id() === get_current_user_id();
⋮----
$product = $item->get_product();
⋮----
'purchase_note'      => $product ? $product->get_purchase_note() : '',
⋮----
foreach ( $order->get_order_item_totals() as $key => $total ) {
⋮----
<?php if ( $order->get_customer_note() ) : ?>
⋮----
$customer_note = wc_wptexturize_order_note( $order->get_customer_note() );
⋮----
foreach ( $actions as $key => $action ) { // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
⋮----
$action_aria_label = sprintf( __( '%1$s order number %2$s', 'woocommerce' ), $action['name'], $order->get_order_number() );
</file>

<file path="plugins/woocommerce/templates/order/order-downloads.php">

</file>

<file path="plugins/woocommerce/templates/order/star-rating.php">
// Reverse so row-reverse + `~` selectors can fill stars 1..N without `:has()`.
⋮----
/* translators: 1: numeric star rating 2: label text e.g. "Good" */
</file>

<file path="plugins/woocommerce/templates/order/tracking.php">
$notes = $order->get_customer_order_notes();
⋮----
'<mark class="order-number">' . $order->get_order_number() . '</mark>',
'<mark class="order-date">' . wc_format_datetime( $order->get_date_created() ) . '</mark>',
'<mark class="order-status">' . wc_get_order_status_name( $order->get_status() ) . '</mark>'
⋮----
<?php do_action( 'woocommerce_view_order', $order->get_id() ); ?>
</file>

<file path="plugins/woocommerce/templates/parts/checkout-header.html">
<header class="wp-block-group">
		<div class="wp-block-group alignwide" style="padding-top:var(--wp--preset--spacing--20);padding-bottom:var(--wp--preset--spacing--20)">
		</div>
</header>
</file>

<file path="plugins/woocommerce/templates/parts/coming-soon-social-links.html">
<ul class="wp-block-social-links has-icon-color is-style-logos-only" style="margin-top:0px;margin-bottom:0px">
</ul>
</file>

<file path="plugins/woocommerce/templates/parts/external-product-add-to-cart-with-options.html">
<div class="wp-block-group"></div>
</file>

<file path="plugins/woocommerce/templates/parts/grouped-product-add-to-cart-with-options.html">
<div
	class="wp-block-woocommerce-add-to-cart-with-options-grouped-product-selector"
	role="list"
>
	<div
		class="wp-block-woocommerce-add-to-cart-with-options-grouped-product-item"
		role="listitem"
	>
		<div
			class="wp-block-group"
			style="margin-top: 1rem; margin-bottom: 1rem"
		>
			<div class="wp-block-group">
				</div>
		</div>
	</div>
</div>
<div class="wp-block-group"></div>
</file>

<file path="plugins/woocommerce/templates/parts/mini-cart.html">
<div class="wp-block-woocommerce-mini-cart-contents">
	<div class="wp-block-woocommerce-filled-mini-cart-contents-block">
		<div class="wp-block-woocommerce-mini-cart-title-block">
			<div class="wp-block-woocommerce-mini-cart-title-label-block">
			</div>
			<div class="wp-block-woocommerce-mini-cart-title-items-counter-block">
			</div>
		</div>
		<div class="wp-block-woocommerce-mini-cart-items-block">
			<div class="wp-block-woocommerce-mini-cart-products-table-block">
			</div>
		</div>
		<div class="wp-block-woocommerce-mini-cart-footer-block">
			<div class="wp-block-woocommerce-mini-cart-cart-button-block"></div>
			<div class="wp-block-woocommerce-mini-cart-checkout-button-block"></div>
		</div>
	</div>
	<div class="wp-block-woocommerce-empty-mini-cart-contents-block">
		<div class="wp-block-woocommerce-mini-cart-shopping-button-block"></div>
	</div>
</div>
</file>

<file path="plugins/woocommerce/templates/parts/simple-product-add-to-cart-with-options.html">
<div class="wp-block-group">
</div>
</file>

<file path="plugins/woocommerce/templates/parts/variable-product-add-to-cart-with-options.html">
<div
	class="wp-block-woocommerce-add-to-cart-with-options-variation-selector"
	role="list"
>
	<div
		class="wp-block-woocommerce-add-to-cart-with-options-variation-selector-attribute"
		role="listitem"
	>
		<div
			class="wp-block-group"
			style="margin-top: 1rem; margin-bottom: 1rem"
		>
			<div class="wp-block-woocommerce-product-filter-chips wc-block-product-filter-chips"></div>
		</div>
	</div>
</div>
<div class="wp-block-group">
</div>
</file>

<file path="plugins/woocommerce/templates/product-form/simple.php">

</file>

<file path="plugins/woocommerce/templates/single-product/add-to-cart/external.php">

</file>

<file path="plugins/woocommerce/templates/single-product/add-to-cart/grouped.php">
<form class="cart grouped_form" action="<?php echo esc_url( apply_filters( 'woocommerce_add_to_cart_form_action', $product->get_permalink() ) ); ?>" method="post" enctype='multipart/form-data'>
⋮----
$post_object        = get_post( $grouped_product_child->get_id() );
$quantites_required = $quantites_required || ( $grouped_product_child->is_purchasable() && ! $grouped_product_child->has_options() );
⋮----
if ( $grouped_product_child->is_in_stock() ) {
⋮----
echo '<tr id="product-' . esc_attr( $grouped_product_child->get_id() ) . '" class="woocommerce-grouped-product-list-item ' . esc_attr( implode( ' ', wc_get_product_class( '', $grouped_product_child ) ) ) . '">';
⋮----
// Output columns for each product.
⋮----
if ( ! $grouped_product_child->is_purchasable() || $grouped_product_child->has_options() || ! $grouped_product_child->is_in_stock() ) {
⋮----
} elseif ( $grouped_product_child->is_sold_individually() ) {
echo '<input type="checkbox" name="' . esc_attr( 'quantity[' . $grouped_product_child->get_id() . ']' ) . '" value="1" class="wc-grouped-product-add-to-cart-checkbox" id="' . esc_attr( 'quantity-' . $grouped_product_child->get_id() ) . '" />';
echo '<label for="' . esc_attr( 'quantity-' . $grouped_product_child->get_id() ) . '" class="screen-reader-text">';
if ( $grouped_product_child->is_on_sale() ) {
⋮----
/* translators: %1$s: Product name. %2$s: Sale price. %3$s: Regular price */
⋮----
esc_html( $grouped_product_child->get_name() ),
esc_html( wp_strip_all_tags( wc_price( $grouped_product_child->get_price() ) ) ),
esc_html( wp_strip_all_tags( wc_price( $grouped_product_child->get_regular_price() ) ) )
⋮----
esc_html( wp_strip_all_tags( wc_price( $grouped_product_child->get_price() ) ) )
⋮----
'input_name'  => 'quantity[' . $grouped_product_child->get_id() . ']',
'input_value' => isset( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ? wc_stock_amount( wc_clean( wp_unslash( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing
⋮----
'max_value'   => $grouped_product_child->get_max_purchase_quantity(),
... (10 lines truncated)
</file>

<file path="plugins/woocommerce/templates/single-product/add-to-cart/simple.php">
if ( ! $product->is_purchasable() ) {
⋮----
if ( $product->is_in_stock() ) : ?>
⋮----
<form class="cart" action="<?php echo esc_url( apply_filters( 'woocommerce_add_to_cart_form_action', $product->get_permalink() ) ); ?>" method="post" enctype='multipart/form-data'>
⋮----
'min_value'   => $product->get_min_purchase_quantity(),
'max_value'   => $product->get_max_purchase_quantity(),
'input_value' => isset( $_POST['quantity'] ) ? wc_stock_amount( wp_unslash( $_POST['quantity'] ) ) : $product->get_min_purchase_quantity(),
⋮----
<button type="submit" name="add-to-cart" value="<?php echo esc_attr( $product->get_id() ); ?>" class="single_add_to_cart_button button alt<?php echo esc_attr( wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '' ); ?>"><?php echo esc_html( $product->single_add_to_cart_text() ); ?></button>
</file>

<file path="plugins/woocommerce/templates/single-product/add-to-cart/variable.php">
<form class="variations_form cart" action="<?php echo esc_url( apply_filters( 'woocommerce_add_to_cart_form_action', $product->get_permalink() ) ); ?>" method="post" enctype='multipart/form-data' data-product_id="<?php echo absint( $product->get_id() ); ?>" data-product_variations="<?php echo $variations_attr; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped, WooCommerce.Commenting.CommentHooks.MissingHookComment -- $variations_attr is already escaped for an HTML attribute by wc_esc_json() or _wp_specialchars(). A hook docblock for woocommerce_add_to_cart_form_action cannot end on the line above this inline call without leaving content before a closing PHP tag. ?>">
⋮----
// Reset snapshot for cases where a theme/plugin loads the variation form later, like quick-view modals.
⋮----
<template class="wc-product-gallery-default-template"><?php echo wc_get_product_gallery_html( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></template>
</file>

<file path="plugins/woocommerce/templates/single-product/add-to-cart/variation-add-to-cart-button.php">
'min_value'   => $product->get_min_purchase_quantity(),
'max_value'   => $product->get_max_purchase_quantity(),
'input_value' => isset( $_POST['quantity'] ) ? wc_stock_amount( wp_unslash( $_POST['quantity'] ) ) : $product->get_min_purchase_quantity(),
⋮----
<button type="submit" class="single_add_to_cart_button button alt<?php echo esc_attr( wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '' ); ?>"><?php echo esc_html( $product->single_add_to_cart_text() ); ?></button>
⋮----
<input type="hidden" name="add-to-cart" value="<?php echo absint( $product->get_id() ); ?>" />
<input type="hidden" name="product_id" value="<?php echo absint( $product->get_id() ); ?>" />
</file>

<file path="plugins/woocommerce/templates/single-product/add-to-cart/variation.php">

</file>

<file path="plugins/woocommerce/templates/single-product/tabs/additional-information.php">

</file>

<file path="plugins/woocommerce/templates/single-product/tabs/description.php">

</file>

<file path="plugins/woocommerce/templates/single-product/tabs/tabs.php">

</file>

<file path="plugins/woocommerce/templates/single-product/back-in-stock-form.php">

</file>

<file path="plugins/woocommerce/templates/single-product/meta.php">
use Automattic\WooCommerce\Enums\ProductType;
⋮----
<?php if ( wc_product_sku_enabled() && ( $product->get_sku() || $product->is_type( ProductType::VARIABLE ) ) ) : ?>
⋮----
<span class="sku_wrapper"><?php esc_html_e( 'SKU:', 'woocommerce' ); ?> <span class="sku"><?php echo ( $sku = $product->get_sku() ) ? $sku : esc_html__( 'N/A', 'woocommerce' ); ?></span></span>
⋮----
$product->get_id(),
⋮----
'<span class="posted_in">' . _n( 'Category:', 'Categories:', count( $product->get_category_ids() ), 'woocommerce' ) . ' ',
⋮----
echo is_string( $product_category_list ) ? $product_category_list : ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
⋮----
<?php echo wc_get_product_tag_list( $product->get_id(), ', ', '<span class="tagged_as">' . _n( 'Tag:', 'Tags:', count( $product->get_tag_ids() ), 'woocommerce' ) . ' ', '</span>' ); ?>
</file>

<file path="plugins/woocommerce/templates/single-product/photoswipe.php">

</file>

<file path="plugins/woocommerce/templates/single-product/price.php">
<p class="<?php echo esc_attr( apply_filters( 'woocommerce_product_price_class', 'price' ) ); ?>"><?php echo $product->get_price_html(); ?></p>
</file>

<file path="plugins/woocommerce/templates/single-product/product-attributes.php">

</file>

<file path="plugins/woocommerce/templates/single-product/product-image.php">
use Automattic\WooCommerce\Enums\ProductType;
use Automattic\WooCommerce\Internal\ProductGallery\ProductMediaGallery;
⋮----
$post_thumbnail_id = $product->get_image_id();
$media_items       = ProductMediaGallery::get_product_media_gallery_items_for_display( $product );
⋮----
$html = ProductMediaGallery::get_gallery_video_html( $first_media_item, true );
⋮----
$wrapper_classname = $product->is_type( ProductType::VARIABLE ) && ! empty( $product->get_visible_children() ) && '' !== $product->get_price() ?
</file>

<file path="plugins/woocommerce/templates/single-product/product-thumbnails.php">
use Automattic\WooCommerce\Internal\ProductGallery\ProductMediaGallery;
⋮----
$media_items = ProductMediaGallery::get_product_media_gallery_items_for_display( $product );
⋮----
$html = ProductMediaGallery::get_gallery_video_html( $media_item, false );
⋮----
/**
			 * Filter product video thumbnail HTML string.
			 *
			 * @since 11.0.0
			 * @internal For exclusive usage of WooCommerce core, backwards compatibility not guaranteed.
			 *
			 * @param string $html          Product video thumbnail HTML string.
			 * @param int    $attachment_id Video attachment ID.
			 * @param array  $media_item    Product media gallery item.
			 */
</file>

<file path="plugins/woocommerce/templates/single-product/rating.php">
$rating_count = $product->get_rating_count();
$review_count = $product->get_review_count();
$average      = $product->get_average_rating();
</file>

<file path="plugins/woocommerce/templates/single-product/related.php">
$post_object = get_post( $related_product->get_id() );
</file>

<file path="plugins/woocommerce/templates/single-product/review-meta.php">

</file>

<file path="plugins/woocommerce/templates/single-product/review-rating.php">

</file>

<file path="plugins/woocommerce/templates/single-product/review.php">

</file>

<file path="plugins/woocommerce/templates/single-product/sale-flash.php">
<?php if ( $product->is_on_sale() ) : ?>
</file>

<file path="plugins/woocommerce/templates/single-product/share.php">

</file>

<file path="plugins/woocommerce/templates/single-product/short-description.php">

</file>

<file path="plugins/woocommerce/templates/single-product/stock.php">

</file>

<file path="plugins/woocommerce/templates/single-product/title.php">

</file>

<file path="plugins/woocommerce/templates/single-product/up-sells.php">
$post_object = get_post( $upsell->get_id() );
</file>

<file path="plugins/woocommerce/templates/templates/blockified/archive-product.html">
<main class="wp-block-group">
	<div class="wp-block-group alignwide">
	</div>
	<div class="wp-block-woocommerce-product-collection alignwide">
		<div class="wp-block-group">
		</div>
	</div>
</main>
</file>

<file path="plugins/woocommerce/templates/templates/blockified/coming-soon.html">

</file>

<file path="plugins/woocommerce/templates/templates/blockified/order-confirmation.html">
<main class="wp-block-group">
	<div class="wp-block-columns alignwide wc-block-order-confirmation-address-wrapper">
		<div class="wp-block-column">
		</div>
		<div class="wp-block-column">
		</div>
	</div>
</main>
</file>

<file path="plugins/woocommerce/templates/templates/blockified/page-cart.html">
<main class="wp-block-group">
</main>
</file>

<file path="plugins/woocommerce/templates/templates/blockified/page-checkout.html">
<main class="wp-block-group">
</main>
</file>

<file path="plugins/woocommerce/templates/templates/blockified/product-search-results.html">
<main class="wp-block-group">
	<div class="wp-block-group alignwide">
	</div>
	<div class="wp-block-woocommerce-product-collection alignwide">
	</div>
</main>
</file>

<file path="plugins/woocommerce/templates/templates/blockified/README.md">
# Blockified templates

This folder contains the blockified versions of the WooCommerce block templates. You can read more about overriding these templates in the [_Theming_ docs for block themes](/docs/block-theme-development/theming-woo-blocks.md#block-templates).
</file>

<file path="plugins/woocommerce/templates/templates/blockified/single-product.html">
<main class="wp-block-group">
	<div class="wp-block-columns alignwide">
		<div class="wp-block-column" style="flex-basis:512px">
		</div>
		<div class="wp-block-column">
			<div class="wp-block-woocommerce-product-meta">
				<div class="wp-block-group">
				</div>
			</div>
		</div>
	</div>
</main>
</file>

<file path="plugins/woocommerce/templates/templates/blockified/taxonomy-product_attribute.html">
<main class="wp-block-group">
	<div class="wp-block-group alignwide">
	</div>
	<div class="wp-block-woocommerce-product-collection alignwide">
		<div class="wp-block-group">
		</div>
	</div>
</main>
</file>

<file path="plugins/woocommerce/templates/templates/archive-product.html">
<main class="wp-block-group"></main>
</file>

<file path="plugins/woocommerce/templates/templates/coming-soon.html">

</file>

<file path="plugins/woocommerce/templates/templates/order-confirmation.html">
<main class="wp-block-group">
	<div class="wp-block-columns alignwide wc-block-order-confirmation-address-wrapper">
		<div class="wp-block-column">
		</div>
		<div class="wp-block-column">
		</div>
	</div>
</main>
</file>

<file path="plugins/woocommerce/templates/templates/page-cart.html">
<main class="wp-block-group">
</main>
</file>

<file path="plugins/woocommerce/templates/templates/page-checkout.html">
<main class="wp-block-group">
</main>
</file>

<file path="plugins/woocommerce/templates/templates/product-search-results.html">
<main class="wp-block-group">
</main>
</file>

<file path="plugins/woocommerce/templates/templates/single-product.html">
<main class="wp-block-group"></main>
</file>

<file path="plugins/woocommerce/templates/templates/taxonomy-product_attribute.html">
<main class="wp-block-group"></main>
</file>

<file path="plugins/woocommerce/templates/archive-product.php">

</file>

<file path="plugins/woocommerce/templates/content-product-cat.php">
/**
	 * The woocommerce_before_subcategory hook.
	 *
	 * @hooked woocommerce_template_loop_category_link_open - 10
	 */
</file>

<file path="plugins/woocommerce/templates/content-product.php">
if ( ! is_a( $product, WC_Product::class ) || ! $product->is_visible() ) {
⋮----
/**
	 * Hook: woocommerce_before_shop_loop_item.
	 *
	 * @hooked woocommerce_template_loop_product_link_open - 10
	 */
</file>

<file path="plugins/woocommerce/templates/content-single-product.php">
/**
	 * Hook: woocommerce_before_single_product_summary.
	 *
	 * @hooked woocommerce_show_product_sale_flash - 10
	 * @hooked woocommerce_show_product_images - 20
	 */
</file>

<file path="plugins/woocommerce/templates/content-widget-price-filter.php">

</file>

<file path="plugins/woocommerce/templates/content-widget-product.php">
<a href="<?php echo esc_url( $product->get_permalink() ); ?>">
<?php echo $product->get_image(); ?>
<span class="product-title"><?php echo wp_kses_post( $product->get_name() ); ?></span>
⋮----
<?php echo wc_get_rating_html( $product->get_average_rating() ); ?>
⋮----
<?php echo $product->get_price_html(); ?>
</file>

<file path="plugins/woocommerce/templates/content-widget-reviews.php">
<?php echo $product->get_image(); ?>
<span class="product-title"><?php echo wp_kses_post( $product->get_name() ); ?></span>
</file>

<file path="plugins/woocommerce/templates/dashboard-widget-reviews.php">
$product_name          = $product->get_name();
</file>

<file path="plugins/woocommerce/templates/product-searchform.php">

</file>

<file path="plugins/woocommerce/templates/single-product-reviews.php">
$count = $product->get_review_count();
⋮----
<?php if ( get_option( 'woocommerce_review_rating_verification_required' ) === 'no' || wc_customer_bought_product( '', get_current_user_id(), $product->get_id() ) ) : ?>
⋮----
/* translators: %s is product title */
</file>

<file path="plugins/woocommerce/templates/single-product.php">

</file>

<file path="plugins/woocommerce/templates/taxonomy-product-attribute.php">

</file>

<file path="plugins/woocommerce/templates/taxonomy-product-cat.php">

</file>

<file path="plugins/woocommerce/templates/taxonomy-product-tag.php">

</file>

<file path="plugins/woocommerce/.gitattributes">
# Remove files for archives generated using `git archive`.
/.*                     export-ignore
/README.md              export-ignore
/CODE_OF_CONDUCT.md     export-ignore
/NEXT_CHANGELOG.md      export-ignore
/changelog.txt          export-ignore
/changelog              export-ignore
/bin                    export-ignore
/composer.json          export-ignore
/composer.lock          export-ignore
/package.json           export-ignore
/package-lock.json      export-ignore
/client/legacy          export-ignore
/tsconfig.json          export-ignore
/tsconfig.base.json     export-ignore
/phpunit.xml            export-ignore
/phpunit.xml            export-ignore
/tests                  export-ignore
</file>

<file path="plugins/woocommerce/.phpunit-watcher.yml">
watch:
  directories:
    - src
    - includes
    - tests/php
    - tests/unit-tests
    - tests/legacy
  fileMask: '*.php'
phpunit:
  binaryPath: ./vendor/bin/phpunit
  timeout: 600
notifications:
  passingTests: false
  failingTests: false
</file>

<file path="plugins/woocommerce/.wp-env.e2e.json">
{
	"core": "https://wordpress.org/wordpress-latest.zip",
	"phpVersion": "8.1",
	"testsEnvironment": false,
	"port": 8086,
	"plugins": [
		".",
		"./tests/e2e/test-plugins/wc-email-template-sync-test-helper",
		"./tests/e2e/test-plugins/woocommerce-e2e-test-helper",
		"https://downloads.wordpress.org/plugin/akismet.zip",
		"https://github.com/WP-API/Basic-Auth/archive/master.zip",
		"https://downloads.wordpress.org/plugin/wp-mail-logging.zip",
		"https://downloads.wordpress.org/plugin/wordpress-importer.0.8.zip",
		"https://downloads.wordpress.org/plugin/plugin-check.zip"
	],
	"themes": [
		"https://downloads.wordpress.org/theme/storefront.zip",
		"https://downloads.wordpress.org/theme/twentytwenty.zip",
		"https://downloads.wordpress.org/theme/twentytwentytwo.zip"
	],
	"config": {
		"JETPACK_AUTOLOAD_DEV": true,
		"WP_DEBUG": false,
		"SCRIPT_DEBUG": false,
		"WP_DEBUG_LOG": true,
		"WP_DEBUG_DISPLAY": false,
		"WP_TESTS_DOMAIN": "localhost",
		"ALTERNATE_WP_CRON": false
	},
	"lifecycleScripts": {
... (25 lines truncated)
</file>

<file path="plugins/woocommerce/.wp-env.json">
{
	"core": "https://wordpress.org/wordpress-latest.zip",
	"phpVersion": "8.1",
	"testsEnvironment": false,
	"plugins": [ "." ],
	"config": {
		"JETPACK_AUTOLOAD_DEV": true,
		"WP_DEBUG_LOG": true,
		"WP_DEBUG_DISPLAY": true,
		"ALTERNATE_WP_CRON": true
	}
}
</file>

<file path="plugins/woocommerce/.wp-env.test.json">
{
	"core": "https://wordpress.org/wordpress-latest.zip",
	"phpVersion": "8.1",
	"testsEnvironment": false,
	"port": 8186,
	"plugins": [ "." ],
	"themes": [
		"https://downloads.wordpress.org/theme/storefront.zip",
		"https://downloads.wordpress.org/theme/twentytwentytwo.zip"
	],
	"config": {
		"JETPACK_AUTOLOAD_DEV": true,
		"WP_DEBUG": false,
		"SCRIPT_DEBUG": false,
		"WP_DEBUG_LOG": true,
		"WP_DEBUG_DISPLAY": false,
		"WP_TESTS_DOMAIN": "localhost",
		"ALTERNATE_WP_CRON": false
	},
	"lifecycleScripts": {
		"afterStart": "./tests/php/bin/test-env-setup.sh",
		"afterClean": "./tests/php/bin/test-env-setup.sh"
	}
}
</file>

<file path="plugins/woocommerce/composer.json">
{
	"name": "woocommerce/woocommerce",
	"description": "An eCommerce toolkit that helps you sell anything. Beautifully.",
	"homepage": "https://woocommerce.com/",
	"version": "11.3.0",
	"type": "wordpress-plugin",
	"license": "GPL-2.0-or-later",
	"prefer-stable": true,
	"minimum-stability": "dev",
	"repositories": [
		{
			"type": "path",
			"url": "lib"
		},
		{
			"type": "path",
			"url": "../../packages/php/monorepo-plugin",
			"options": {
				"symlink": false
			}
		},
		{
			"type": "path",
			"url": "../../packages/php/blueprint",
			"options": {
				"symlink": false
			}
		},
		{
			"type": "path",
... (175 lines truncated)
</file>

<file path="plugins/woocommerce/eslint.config.mjs">
/**
 * External dependencies
 */
⋮----
/**
 * Internal dependencies
 */
⋮----
/*
	 * These only scope `eslint .` so it does not walk into trees that own a
	 * config. They do not decide which rules a file gets: ESLint 10 resolves
	 * the nearest eslint.config.* for each file, so bin/eslint-branch.sh,
	 * which passes explicit paths, still lints a changed client/legacy or
	 * client/admin file with that package's own config.
	 *
	 * node_modules is ignored by default.
	 */
⋮----
/*
	 * The eslintrc this replaces declared neither `extends` nor `root`: it
	 * inherited WooCommerce's preset by cascading to the repo root config. Flat
	 * config does not cascade, so spread it explicitly.
	 */
⋮----
/*
		 * The eslintrc set `parser: '@babel/eslint-parser'`. That parser's v7 line
		 * calls scopeManager.addGlobals, which ESLint 10 removed, and v8 requires
		 * @babel/core ^8 while this repo is pinned to 7.x. WordPress works around
		 * it with an unexported compat shim. The TypeScript parser the shared
		 * config already installs parses every source here, so inherit it.
... (37 lines truncated)
</file>

<file path="plugins/woocommerce/license.txt">
WooCommerce - eCommerce for WordPress

Copyright 2015 by the contributors

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

This program incorporates work covered by the following copyright and
permission notices:

  Jigoshop is Copyright (c) 2011 Jigowatt Ltd.
  http://jigowatt.com - http://jigoshop.com

  Jigoshop is released under the GPL

and

  WooCommerce - eCommerce for WordPress

... (681 lines truncated)
</file>

<file path="plugins/woocommerce/NEXT_CHANGELOG.md">
# Changelog

---

[See changelogs for previous versions](https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/changelog.txt).
</file>

<file path="plugins/woocommerce/package.json">
{
	"name": "@woocommerce/plugin-woocommerce",
	"private": true,
	"title": "WooCommerce",
	"version": "11.3.0",
	"homepage": "https://woocommerce.com/",
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"license": "GPL-2.0-or-later",
	"scripts": {
		"build": "pnpm build:project",
		"build:admin": "pnpm build:project:admin",
		"build:blocks": "pnpm build:project:blocks",
		"build:classic-assets": "pnpm build:project:classic-assets",
		"build:zip": "./bin/build-zip.sh",
		"build:project": "pnpm --stream '/^build:project:.*$/'",
		"build:project:admin": "pnpm --filter='@woocommerce/admin-library' build",
		"build:project:blocks": "pnpm --filter='@woocommerce/block-library' build",
		"build:project:classic-assets": "pnpm --filter='@woocommerce/classic-assets' build",
		"build:project:packages": "XDEBUG_MODE=off composer install --quiet",
		"build:project:actualize-translation-domains": "node ./bin/package-update-textdomain.js",
		"changelog": "XDEBUG_MODE=off composer install --quiet && composer exec -- changelogger",
		"update:php": "XDEBUG_MODE=off composer update --quiet",
		"env:destroy": "pnpm env:dev:destroy",
		"env:dev": "pnpm env:dev:start",
		"env:dev:destroy": "pnpm wp-env destroy",
		"env:dev:restart": "pnpm wp-env destroy --force && pnpm wp-env start --update",
		"env:dev:start": "pnpm wp-env start --update",
... (1146 lines truncated)
</file>

<file path="plugins/woocommerce/phpcs.xml">
<?xml version="1.0"?>
<ruleset name="WordPress Coding Standards">
	<description>WooCommerce dev PHP_CodeSniffer ruleset.</description>
	<file>.</file>
	<exclude-pattern>tests/cli/</exclude-pattern>
	<exclude-pattern>client/admin/docs/examples/</exclude-pattern>
	<exclude-pattern>includes/libraries/</exclude-pattern>
	<exclude-pattern>includes/legacy/</exclude-pattern>
	<exclude-pattern>includes/api/legacy/</exclude-pattern>
	<exclude-pattern>includes/api/v1/</exclude-pattern>
	<exclude-pattern>includes/class-wc-geo-ip.php</exclude-pattern>
	<exclude-pattern>includes/wc-deprecated-functions.php</exclude-pattern>
	<exclude-pattern>*/node_modules/*</exclude-pattern>
	<exclude-pattern>*/vendor/*</exclude-pattern>
	<exclude-pattern>lib/</exclude-pattern>
	<exclude-pattern>php-stubs/</exclude-pattern>
	<exclude-pattern>bin/phpcs/</exclude-pattern>
	<exclude-pattern>tests/e2e/themes/blocks/</exclude-pattern>
	<exclude-pattern>tests/e2e/test-plugins/blocks/</exclude-pattern>
	<exclude-pattern>tests/e2e/bin/</exclude-pattern>
	<exclude-pattern>tests/Tools/phpcs/</exclude-pattern>
	<arg name="extensions" value="php" />
	<arg value="ps" />
	<arg name="basepath" value="./" />
	<arg name="parallel" value="8" />
	<config name="minimum_supported_wp_version" value="5.2" />
	<config name="testVersion" value="7.4-" />
	<rule ref="WooCommerce-Core" />
	<rule ref="./tests/Tools/phpcs/WooCommerceInternal/Sniffs/DB/IdentifierPlaceholderSniff.php">
		<include-pattern>src/</include-pattern>
		<include-pattern>includes/</include-pattern>
    </rule>
	<rule ref="./bin/phpcs/WooCommerceStoreApi/Sniffs/StoreApi/CartTokenSourceSniff.php">
		<exclude-pattern>src/StoreApi/Utilities/CartTokenUtils.php</exclude-pattern>
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="WooCommerce.Functions.InternalInjectionMethod">
		<include-pattern>src/</include-pattern>
		<include-pattern>tests/php/src/</include-pattern>
		<properties>
			<property name="injectionMethod" value="init"/>
		</properties>
	</rule>
	<rule ref="WordPress.WP.I18n">
		<properties>
			<property name="text_domain" type="array">
				<element value="woocommerce" />
			</property>
		</properties>
	</rule>
	<rule ref="PHPCompatibility">
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="SlevomatCodingStandard.Files.TypeNameMatchesFileName">
		<include-pattern>src/</include-pattern>
		<include-pattern>tests/php/src/</include-pattern>
		<exclude-pattern>plugins/woocommerce/src/Admin/Notes/DeprecatedNotes.php</exclude-pattern>
		<exclude-pattern>plugins/woocommerce/tests/php/src/Proxies/ExampleClasses/</exclude-pattern>
		<exclude-pattern>plugins/woocommerce/tests/php/src/Internal/DependencyManagement/ExampleClasses/</exclude-pattern>
		<properties>
			<property name="rootNamespaces" type="array">
				<element key="src" value="Automattic\WooCommerce"/>
				<element key="tests/php/src" value="Automattic\WooCommerce\Tests"/>
			</property>
		</properties>
	</rule>
	<rule ref="Generic.CodeAnalysis.UselessOverridingMethod.Found">
		<exclude-pattern>plugins/woocommerce/tests/php/src/Blocks/Mocks/</exclude-pattern>
	</rule>
	<rule ref="Generic.PHP.RequireStrictTypes">
		<include-pattern>includes/</include-pattern>
		<include-pattern>lib/</include-pattern>
		<include-pattern>src/</include-pattern>
		<include-pattern>tests/</include-pattern>
		<exclude-pattern>plugins/woocommerce/includes/admin/views/</exclude-pattern>
		<exclude-pattern>plugins/woocommerce/includes/emails/</exclude-pattern>
		<exclude-pattern>plugins/woocommerce/includes/react-admin/emails/</exclude-pattern>
	</rule>
	<rule ref="WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents">
		<exclude-pattern>tests/src</exclude-pattern>
	</rule>
	<rule ref="WordPress.WP.Capabilities">
		<properties>
			<property name="custom_capabilities" type="array">
				<element key="0" value="download_file"/>
				<element key="1" value="read_product"/>
				<element key="2" value="edit_products"/>
				<element key="3" value="edit_private_products"/>
				<element key="4" value="edit_others_products"/>
				<element key="5" value="edit_product"/>
				<element key="6" value="publish_shop_orders"/>
				<element key="7" value="edit_shop_orders"/>
				<element key="8" value="edit_others_shop_orders"/>
				<element key="9" value="view_order"/>
				<element key="10" value="pay_for_order"/>
				<element key="11" value="order_again"/>
				<element key="12" value="cancel_order"/>
				<element key="13" value="read_private_shop_orders"/>
				<element key="14" value="customer"/>
				<element key="15" value="manage_woocommerce"/>
				<element key="16" value="manage_product_terms"/>
				<element key="17" value="view_woocommerce_reports"/>
			</property>
		</properties>
	</rule>
	<rule ref="WordPress.Files.FileName.InvalidClassFileName">
		<exclude-pattern>includes/**/abstract-*.php</exclude-pattern>
		<exclude-pattern>tests/</exclude-pattern>
		<exclude-pattern>src/</exclude-pattern>
		<exclude-pattern>tests/php/src/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Classes.ClassFileName">
		<include-pattern>src/</include-pattern>
		<include-pattern>tests/php/src/</include-pattern>
	</rule>
	<rule ref="Squiz.Classes.ValidClassName">
		<include-pattern>src/</include-pattern>
		<include-pattern>tests/php/src/</include-pattern>
	</rule>
	<rule ref="Generic.Commenting">
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="WooCommerce.Commenting.CommentHooks">
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="WordPress.NamingConventions.ValidHookName.UseUnderscores">
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="PEAR.Functions.FunctionCallSignature.EmptyLine">
		<exclude-pattern>tests/e2e-tests/</exclude-pattern>
	</rule>
	<rule ref="WordPress.Files.FileName.NotHyphenatedLowercase">
		<exclude-pattern>i18n/</exclude-pattern>
		<exclude-pattern>src/</exclude-pattern>
		<exclude-pattern>tests/php</exclude-pattern>
		<exclude-pattern>tests/Tools/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FileComment.MissingPackageTag">
		<exclude-pattern>src/</exclude-pattern>
		<exclude-pattern>tests/php/</exclude-pattern>
		<exclude-pattern>patterns</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FileComment.SpacingAfterComment">
		<exclude-pattern>patterns</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FileComment.Missing">
		<exclude-pattern>includes/</exclude-pattern>
		<exclude-pattern>src/</exclude-pattern>
		<exclude-pattern>tests/php/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FunctionCommentThrowTag.Missing">
		<exclude-pattern>tests/php/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.LongConditionClosingComment.Missing">
		<severity>0</severity>
	</rule>
	<rule ref="Universal.Arrays.DisallowShortArraySyntax.Found">
		<exclude-pattern>src/Blocks/</exclude-pattern>
		<exclude-pattern>src/StoreApi/</exclude-pattern>
	</rule>
	<rule ref="WooCommerce.Functions.InternalInjectionMethod.MissingFinal">
		<exclude-pattern>src/Blocks/</exclude-pattern>
		<exclude-pattern>src/StoreApi/</exclude-pattern>
	</rule>
	<rule ref="WooCommerce.Functions.InternalInjectionMethod.MissingInternalTag">
		<exclude-pattern>src/Blocks/</exclude-pattern>
		<exclude-pattern>src/StoreApi/</exclude-pattern>
	</rule>
</ruleset>
</file>

<file path="plugins/woocommerce/phpstan-baseline.neon">
parameters:
	ignoreErrors:
		-
			message: '#^@param tag must not be named \$this\. Choose a descriptive alias, for example \$instance\.$#'
			identifier: phpDoc.parseError
			count: 3
			path: includes/abstracts/abstract-wc-data.php

		-
			message: '#^Argument of an invalid type array\<WC_Meta_Data\>\|null supplied for foreach, only iterables are supported\.$#'
			identifier: foreach.nonIterable
			count: 1
			path: includes/abstracts/abstract-wc-data.php

		-
			message: '#^Call to an undefined method object\:\:add_meta\(\)\.$#'
			identifier: method.notFound
			count: 1
			path: includes/abstracts/abstract-wc-data.php

		-
			message: '#^Call to an undefined method object\:\:create\(\)\.$#'
			identifier: method.notFound
			count: 1
			path: includes/abstracts/abstract-wc-data.php

		-
			message: '#^Call to an undefined method object\:\:delete\(\)\.$#'
			identifier: method.notFound
			count: 1
... (69951 lines truncated)
</file>

<file path="plugins/woocommerce/phpstan.neon">
includes:
	- phpstan-baseline.neon
	- vendor/szepeviktor/phpstan-wordpress/extension.neon

parameters:
	tmpDir: tmp
	level: 8
	phpVersion: 70400
	paths:
		- woocommerce.php
		- src/
		- includes/
	excludePaths:
		# Matches the prior test implementation; GeoIP relies on data files.
		- includes/class-wc-geo-ip.php
		- includes/react-admin/feature-config.php (?)
	bootstrapFiles:
		- vendor/autoload.php
	scanDirectories:
		- vendor/wordpress/abilities-api
		- packages/action-scheduler
		- ../../packages/php/woocommerce-analytics/src
	scanFiles:
		- php-stubs/wc-admin-feature-config.php
		- php-stubs/wc-constants.php
	treatPhpDocTypesAsCertain: false
	dynamicConstantNames:
		# WC_TAX_ROUNDING_MODE can be 1, 2 (ints) or 'auto' (string in tests).
		# See tests/legacy/bootstrap.php and wc-core-functions.php:wc_get_tax_rounding_mode()
		WC_TAX_ROUNDING_MODE: 1|2|'auto'
... (18 lines truncated)
</file>

<file path="plugins/woocommerce/phpunit.xml">
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	bootstrap="tests/legacy/bootstrap.php"
	backupGlobals="false"
	colors="true"
	convertErrorsToExceptions="true"
	convertNoticesToExceptions="true"
	convertWarningsToExceptions="true"
	verbose="true"
	defaultTestSuite="wc-phpunit-legacy,wc-phpunit-main"
	xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
	<testsuites>
		<testsuite name="wc-phpunit-legacy">
			<directory suffix=".php">./tests/legacy/unit-tests</directory>
		</testsuite>
		<testsuite name="wc-phpunit-main">
			<directory suffix=".php">./tests/php</directory>
			<exclude>./tests/php/helpers</exclude>
			<exclude>./tests/php/src/Blocks/BlockPatterns/patterns</exclude>
			<exclude>./tests/php/src/Internal/EmailEditor/WCTransactionalEmails/fixtures</exclude>
		</testsuite>
	</testsuites>
	<listeners>
		<listener class="JohnKary\PHPUnit\Listener\SpeedTrapListener">
			<arguments>
                <array>
					<element key="slowThreshold">
						<integer>1000</integer>
					</element>
					<element key="reportLength">
... (11 lines truncated)
</file>
			<file>uninstall.php</file>
		</include>
		<exclude>
			<directory suffix=".php">./includes/admin/helper/views</directory>
			<directory suffix=".php">./includes/admin/importers/views</directory>
			<directory suffix=".php">./includes/admin/meta-boxes/views</directory>
			<directory suffix=".php">./includes/admin/plugin-updates/views</directory>
			<directory suffix=".php">./includes/admin/views</directory>
			<directory suffix=".php">./includes/api/legacy</directory>
			<directory suffix=".php">./includes/api/v1</directory>
			<directory suffix=".php">./includes/legacy</directory>
			<directory suffix=".php">./includes/libraries</directory>
			<directory suffix=".php">./includes/shipping/legacy-flat-rate</directory>
			<directory suffix=".php">./includes/shipping/legacy-free-shipping</directory>
			<directory suffix=".php">./includes/shipping/legacy-international-delivery</directory>
			<directory suffix=".php">./includes/shipping/legacy-local-delivery</directory>
			<directory suffix=".php">./includes/shipping/legacy-local-pickup</directory>
			<directory suffix=".php">./includes/updates</directory>
			<directory suffix=".php">./includes/vendor</directory>
			<directory suffix=".php">./includes/widgets</directory>
			<directory suffix=".php">./packages</directory>
			<directory suffix=".php">./vendor</directory>
			<file>./includes/wc-deprecated-functions.php</file>
			<file>./includes/wc-template-hooks.php</file>
			<file>./includes/wc-widget-functions.php</file>
		</exclude>
	</coverage>
</phpunit>
</file>

<file path="plugins/woocommerce/README.md">
# [![WooCommerce](https://woocommerce.com/wp-content/themes/woo/images/logo-woocommerce@2x.png 'WooCommerce')](https://woocommerce.com/)

[![License](https://poser.pugx.org/woocommerce/woocommerce/license 'License')](https://packagist.org/packages/woocommerce/woocommerce)
![WordPress.org downloads](https://img.shields.io/wordpress/plugin/dt/woocommerce.svg 'WordPress.org downloads')
![WordPress.org rating](https://img.shields.io/wordpress/plugin/r/woocommerce.svg 'WordPress.org rating')
[![Build Status](https://github.com/woocommerce/woocommerce/actions/workflows/ci.yml/badge.svg?branch=trunk 'Build Status')](https://github.com/woocommerce/woocommerce/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/woocommerce/woocommerce/branch/trunk/graph/badge.svg 'codecov')](https://codecov.io/gh/woocommerce/woocommerce)

This is the WooCommerce Core plugin. Here you can browse the source and keep track of development. We recommend all developers to follow the [WooCommerce development blog](https://developer.woocommerce.com/) to stay up to date about everything happening in the project. You can also [follow @DevelopWoo](https://twitter.com/DevelopWoo) on Twitter for the latest development updates.

If you are not a developer, please use the [WooCommerce plugin page](https://wordpress.org/plugins/woocommerce/) on WordPress.org.

## Getting Started

### Quick start

Ensure your system meets [the requirements](../../README.md#getting-started) (TLDR: Node.js, PNPM, PHP 7.4+, and Composer are required for development; NVM is optional, since PNPM uses the pinned Node version automatically).

Depending on the preferred environment for running the development instance of WooCommerce, you might need [Docker](https://docs.docker.com/get-docker/) as well. You can learn more about supported environments [here in the developer docs](https://developer.woocommerce.com/docs/setting-up-your-development-environment/).

Once you have verified the prerequisites, you can start the development environment:

```bash
## Watch for changes in WooCommerce and all of its dependencies.
pnpm --filter='@woocommerce/plugin-woocommerce' watch:build

# Start a wp-env based development environment, which will be accessible via http://localhost:8888/.
# This step is optional and you can skip it if you are running WooCommerce on a custom setup.
pnpm --filter='@woocommerce/plugin-woocommerce' env:dev
```
... (78 lines truncated)
</file>

<file path="plugins/woocommerce/readme.txt">
=== WooCommerce ===
Contributors: automattic, woocommerce, mikejolley, jameskoster, claudiosanches, rodrigosprimo, peterfabian1000, vedjain, jamosova, obliviousharmony, konamiman, sadowski, wpmuguru, royho, barryhughes-1, claudiulodro, tiagonoronha, ryelle, levinmedia, aljullu, nerrad, joshuawold, assassinateur, haszari, mppfeiffer, nielslange, opr18, ralucastn, tjcafferkey, danielwrobert, patriciahillebrandt, albarin, dinhtungdu, imanish003, karolmanijak, sunyatasattva, alexandrelara, gigitux, danieldudzic, samueljseay, alexflorisca, opr18, tarunvijwani, pauloarromba, saadtarhi, bor0, kloon, coreymckrill, jorgeatorres, leifsinger, neosinner
Tags: online store, ecommerce, shop, shopping cart, sell online
Requires at least: 7.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 11.1.0
License: GPLv3
License URI: https://www.gnu.org/licenses/gpl-3.0.html

Everything you need to launch an online store in days and keep it growing for years. From your first sale to millions in revenue, Woo is with you.

== Description ==

[WooCommerce](https://woocommerce.com/woocommerce/) is the open-source ecommerce platform for WordPress.

Our core platform is free, flexible, and amplified by a global community. The freedom of open-source means you retain full ownership of your store’s content and data forever.

Whether you’re launching a business, taking brick-and-mortar retail online, or developing sites for clients, use WooCommerce for a store that powerfully blends content and commerce.

- **Create beautiful, enticing storefronts** with [themes](https://woocommerce.com/product-category/themes/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) suited to your brand and industry.
- **Increase revenue** with an optimized [shopping cart experience](https://woocommerce.com/checkout-blocks/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing) that converts.
- **Customize product pages in minutes** using modular [product blocks](https://woocommerce.com/document/woocommerce-blocks/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).
- Showcase physical and digital goods, product variations, custom configurations, instant downloads, and affiliate items.
- Sell [subscriptions](https://woocommerce.com/products/woocommerce-subscriptions/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), [bookings](https://woocommerce.com/products/woocommerce-bookings/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), or [memberships](https://woocommerce.com/products/woocommerce-memberships/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing), with our developer-vetted extensions.
- **Rise to the top of search results** by leveraging [WordPress’ SEO advantage](https://www.searchenginejournal.com/wordpress-best-cms-seo/).
- **Build on a platform that scales.** Get flexible ecommerce for [high-volume stores](https://woocommerce.com/high-volume-stores/?utm_medium=referral&utm_source=wordpress.org&utm_campaign=wp_org_repo_listing).

= ALL THE TOOLS YOU NEED TO SELL =

... (146 lines truncated)
</file>

<file path="plugins/woocommerce/tsconfig.json">
{
	"extends": "../../tsconfig.base.json",
	"references": [
		{
			"path": "client/admin"
		},
		{
			"path": "client/blocks"
		}
	],
	"files": [],
	"compilerOptions": {
		"composite": true
	}
}
</file>

<file path="plugins/woocommerce/uninstall.php">
error_log( 'WooCommerce: Action Scheduler threw while loading during uninstall: ' . $e->getMessage() );
⋮----
if ( class_exists( 'ActionScheduler', false ) && ActionScheduler::is_initialized() ) {
ActionScheduler::runner()->unhook_dispatch_async_request();
⋮----
if ( class_exists( ActionScheduler::class ) && ActionScheduler::is_initialized() && function_exists( 'as_unschedule_all_actions' ) ) {
⋮----
$index_exists = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->comments} WHERE key_name = 'woo_idx_comment_type';" );
⋮----
$wpdb->query( "ALTER TABLE {$wpdb->comments} DROP INDEX woo_idx_comment_type;" );
⋮----
$date_type_index_exists = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->comments} WHERE key_name = 'woo_idx_comment_date_type';" );
⋮----
$wpdb->query( "ALTER TABLE {$wpdb->comments} DROP INDEX woo_idx_comment_date_type;" );
⋮----
$comment_approved_type_index_exists = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->comments} WHERE key_name = 'woo_idx_comment_approved_type';" );
⋮----
$wpdb->query( "ALTER TABLE {$wpdb->comments} DROP INDEX woo_idx_comment_approved_type;" );
⋮----
WC_Install::remove_roles();
⋮----
if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}woocommerce_attribute_taxonomies';" ) ) {
$wc_attributes = array_filter( (array) $wpdb->get_col( "SELECT attribute_name FROM {$wpdb->prefix}woocommerce_attribute_taxonomies;" ) );
⋮----
WC_Install::drop_tables();
⋮----
foreach ( WC_Install::get_action_scheduler_tables() as $as_table ) {
⋮----
$wpdb->query( "DROP TABLE IF EXISTS {$as_table}" );
⋮----
... (23 lines truncated)
</file>

<file path="plugins/woocommerce/woocommerce.php">
if ( ! \Automattic\WooCommerce\Autoloader::init() ) {
⋮----
\Automattic\WooCommerce\Packages::init();
⋮----
\Automattic\WooCommerce\Autoloader::register_woocommerce_psr4_fallback();
⋮----
$GLOBALS['wc_container'] = new Automattic\WooCommerce\Container();
⋮----
function WC() {
return WooCommerce::instance();
⋮----
function wc_get_container() {
⋮----
\Automattic\Jetpack\Connection\Rest_Authentication::init();
</file>

<file path="plugins/woocommerce-beta-tester/api/admin-notes/add-note.php">
use Automattic\WooCommerce\Admin\Notes\Note;
⋮----
function admin_notes_add_note( $request ) {
⋮----
$type           = $request->get_param( 'type' );
⋮----
$note->set_name( $request->get_param( 'name' ) );
$note->set_title( $request->get_param( 'title' ) );
$note->set_content( $mock_note_data['content'] );
$note->set_type( $type );
⋮----
$note->save();
⋮----
function add_email_note_params( $note ) {
⋮----
$note->set_content_data( (object) $additional_data );
⋮----
function possibly_add_action( $note ) {
if ( $note->get_type() === 'info' ) {
⋮----
$note->get_name()
⋮----
$note->add_action( $action_name, 'Test action', wc_admin_url() );
⋮----
function get_mock_note_data() {
</file>

<file path="plugins/woocommerce-beta-tester/api/admin-notes/delete-all-notes.php">
function admin_notes_delete_all_notes() {
⋮----
$deleted_note_count   = $wpdb->query( "DELETE FROM {$wpdb->prefix}wc_admin_notes" );
$deleted_action_count = $wpdb->query( "DELETE FROM {$wpdb->prefix}wc_admin_note_actions" );
</file>

<file path="plugins/woocommerce-beta-tester/api/features/features.php">
function toggle_feature( $request ) {
⋮----
$feature_name          = $request->get_param( 'feature_name' );
⋮----
function reset_features() {
⋮----
function get_features() {
</file>

<file path="plugins/woocommerce-beta-tester/api/live-branches/install.php">
function check_live_branches_permissions() {
⋮----
return new \WP_Error(
⋮----
function get_latest_wc_release( $include_pre_releases = false ) {
⋮----
function install_latest_version( $request ) {
$params               = json_decode( $request->get_body() );
⋮----
$result    = $installer->install(
⋮----
return new WP_Error( 400, sprintf( 'Could not install %s with error %s', $version, $result->get_error_message() ), '' );
⋮----
function install_version( $request ) {
$params       = json_decode( $request->get_body() );
⋮----
$result    = $installer->install( $download_url, $version );
⋮----
return new WP_Error( 400, "Could not install $pr_name with error {$result->get_error_message()}", '' );
⋮----
function activate_version( $request ) {
$params  = json_decode( $request->get_body() );
⋮----
$result    = $installer->activate( $version );
⋮----
return new WP_Error( 400, "Could not activate version: $version with error {$result->get_error_message()}", '' );
⋮----
function deactivate_woocommerce() {
⋮----
$installer->deactivate_woocommerce();
... (1 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/api/live-branches/manifest.php">
function fetch_live_branches_manifest() {
⋮----
$error_message = $response->get_error_message();
⋮----
$value->install_status = $installer->check_install_status( $value->version );
⋮----
$obj->master->install_status = $installer->check_install_status( $obj->master->version );
</file>

<file path="plugins/woocommerce-beta-tester/api/options/rest-api.php">
use function WP_CLI\Utils\esc_like;
⋮----
function wca_test_helper_delete_option( $request ) {
⋮----
$option_names  = explode( ',', $request->get_param( 'option_names' ) );
⋮----
$wpdb->query(
$wpdb->prepare(
⋮----
function wca_test_helper_get_options( $request ) {
⋮----
$per_page = $request->get_param( 'per_page' );
$page     = $request->get_param( 'page' );
$search   = $request->get_param( 'search' );
⋮----
$search = $wpdb->esc_like( $search );
⋮----
$query = $wpdb->prepare( $query, $search, $per_page, $offset );
⋮----
$query = $wpdb->prepare( $query, $per_page, $offset );
⋮----
$options = $wpdb->get_results( $query );
⋮----
function wca_test_helper_update_option( $request ) {
$data     = $request->get_json_params();
</file>

<file path="plugins/woocommerce-beta-tester/api/remote-inbox-notifications/class-wc-beta-tester-remote-inbox-notifications-helper.php">
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\SpecRunner;
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsEngine;
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsDataSourcePoller;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\GetRuleProcessor;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
⋮----
class WC_Beta_Tester_Remote_Inbox_Notifications_Helper {
⋮----
public static function get_transient_name() {
⋮----
public static function get_transient() {
return get_transient( static::get_transient_name() );
⋮----
public static function delete_by_id( $id ) {
⋮----
$wpdb->delete( $wpdb->prefix . 'wc_admin_notes', array( 'note_id' => $id ) );
$wpdb->delete( $wpdb->prefix . 'wc_admin_note_actions', array( 'note_id' => $id ) );
⋮----
public static function delete_all() {
⋮----
$deleted_note_count   = $wpdb->query( "DELETE FROM {$wpdb->prefix}wc_admin_notes" );
$deleted_action_count = $wpdb->query( "DELETE FROM {$wpdb->prefix}wc_admin_note_actions" );
⋮----
public static function test( $name, $locale = null, $run = false ) {
$notifications = static::get_transient();
⋮----
$processor        = $rule_processor->get_processor( $rule->type );
$processor_result = $processor->process( $rule, null );
⋮----
$stored_state = RemoteInboxNotificationsEngine::get_stored_state();
... (8 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/api/remote-inbox-notifications/class-wca-test-helper-remote-inbox-notifications.php">
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\SpecRunner;
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsEngine;
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsDataSourcePoller;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\GetRuleProcessor;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
⋮----
class WCA_Test_Helper_Remote_Inbox_Notifications {
⋮----
public static function delete( $request ) {
WC_Beta_Tester_Remote_Inbox_Notifications_Helper::delete_by_id( $request->get_param( 'id' ) );
⋮----
public static function delete_all_items() {
$deleted = WC_Beta_Tester_Remote_Inbox_Notifications_Helper::delete_all();
⋮----
private static function get_notes_to_exclude() {
⋮----
$property = $reflection->getProperty( $var );
$property->setAccessible( true );
$notes      = $property->getValue();
⋮----
public static function get_items() {
⋮----
$items = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}wc_admin_notes ORDER BY note_id desc", ARRAY_A );
⋮----
$notes_added_via_classes = self::get_notes_to_exclude();
⋮----
public static function test( $request ) {
$name   = $request->get_param( 'name' );
$result = WC_Beta_Tester_Remote_Inbox_Notifications_Helper::test( $name, null, true );
⋮----
... (7 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/api/remote-logging/remote-logging.php">
use Automattic\WooCommerce\Internal\Logging\RemoteLogger;
⋮----
function get_remote_logging_status() {
$remote_logger = wc_get_container()->get( RemoteLogger::class );
⋮----
'isEnabled'     => $remote_logger->is_remote_logging_allowed(),
⋮----
function toggle_remote_logging( $request ) {
$enable = $request->get_param( 'enable' );
⋮----
'isEnabled' => $remote_logger->is_remote_logging_allowed(),
⋮----
function log_remote_event() {
⋮----
$result        = $remote_logger->handle(
⋮----
function reset_php_rate_limit() {
⋮----
$wpdb->query(
</file>

<file path="plugins/woocommerce-beta-tester/api/remote-spec-validator/class-wca-test-helper-remote-spec-validator.php">
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
⋮----
function wca_test_helper_validate_remote_spec( $request ) {
$spec           = json_decode( $request->get_param( 'spec' ) );
⋮----
'valid' => $rule_evaluator->evaluate( $spec ),
</file>

<file path="plugins/woocommerce-beta-tester/api/rest-api-filters/class-wca-test-helper-rest-api-filters.php">
class WCA_Test_Helper_Rest_Api_Filters {
⋮----
public static function create( $request ) {
$endpoint     = $request->get_param( 'endpoint' );
$dot_notation = $request->get_param( 'dot_notation' );
$replacement  = $request->get_param( 'replacement' );
⋮----
self::update(
⋮----
public static function update( callable $callback ) {
⋮----
$filters = $callback( $filters );
⋮----
public static function delete( $request ) {
⋮----
array_splice( $filters, $request->get_param( 'index' ), 1 );
⋮----
public static function toggle( $request ) {
⋮----
$index                        = $request->get_param( 'index' );
</file>

<file path="plugins/woocommerce-beta-tester/api/rest-api-filters/hook.php">
function array_dot_set( &$array, $key, $value ) {
⋮----
$route   = $request->get_route();
⋮----
$data = $response->get_data();
⋮----
$response->set_data( $data );
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/templates/9.7.1 - Coming soon entire site.html">
<div class="wp-block-woocommerce-coming-soon woocommerce-coming-soon-entire-site wp-block-woocommerce-background-color">
<div class="wp-block-cover is-light coming-soon-is-vertically-aligned-center coming-soon-cover" style="min-height:100vh"><span aria-hidden="true" class="wp-block-cover__background has-background-dim-100 has-background-dim"></span><div class="wp-block-cover__inner-container">
<div class="wp-block-group woocommerce-coming-soon-banner-container">
<div class="wp-block-group alignwide woocommerce-coming-soon-header has-background" style="padding-top:10px;padding-bottom:14px">
<div class="wp-block-group alignwide">
<div class="wp-block-group">
<div class="wp-block-group"></div>
</div>
<div class="wp-block-group woocommerce-coming-soon-social-login">
</div>
</div>
</div>
<div class="wp-block-group">
<h1 class="wp-block-heading alignwide has-text-align-center woocommerce-coming-soon-banner has-heading-font-family">Pardon our dust! We're working on something amazing — check back soon!</h1>
</div>
<div class="wp-block-group woocommerce-coming-soon-powered-by-woo" style="padding-top:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--10)">
<div class="wp-block-group alignwide" style="padding-top:var(--wp--preset--spacing--30);padding-bottom:0">
<p class="has-text-align-center has-contrast-2-color has-text-color has-link-color has-small-font-size">&nbsp;</p>
</div>
</div>
</div>
</div></div>
</div>
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/templates/9.7.1 - Coming soon store only.html">
<div class="wp-block-woocommerce-coming-soon woocommerce-coming-soon-store-only">
  <div class="wp-block-group">
  <div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div>
  <h1 class="wp-block-heading has-text-align-center has-heading-font-family">Great things are on the horizon</h1>
  <div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div>
  <p class="has-text-align-center has-body-font-family">Something big is brewing! Our store is in the works and will be launching soon!</p>
  <div style="height:0px" aria-hidden="true" class="wp-block-spacer"></div>
  </div>
  </div>
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/class-fake-wcpayments.php">
class Fake_WCPayments extends WC_Payment_Gateway_WCPay {
⋮----
public function __construct() {
⋮----
$this->method_description = $this->get_method_description();
⋮----
public function needs_setup() {
⋮----
public function is_connected() {
⋮----
public function get_connection_url() {
⋮----
/**
	 * Checks if the gateway is enabled, and also if it's configured enough to accept payments from customers.
	 *
	 * Use parent method value alongside other business rules to make the decision.
	 *
	 * @return bool Whether the gateway is enabled and ready to accept payments.
	 */
public function is_available() {
⋮----
public function is_account_partially_onboarded(): bool {
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/delete-all-products.php">
function tools_delete_all_products() {
$query    = new \WC_Product_Query();
$products = $query->get_products();
⋮----
$product->delete( true );
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/disable-wc-email.php">
function toggle_emails() {
⋮----
function get_email_status() {
⋮----
function disable_wc_emails( $key ) {
⋮----
function unhook_other_wc_emails( $email ) {
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/fake-woo-payments-gateway.php">
function tools_get_fake_wcpay_completion_status() {
⋮----
function tools_set_fake_wcpay_completion( $request ) {
$enabled = $request->get_param( 'enabled' );
⋮----
function tools_fake_wcpay( $gateways ) {
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/load-template-version.php">
function get_predefined_templates() {
⋮----
function tools_load_template_version( $request ) {
$template_name = $request->get_param( 'template_name' );
$version = $request->get_param( 'version' );
⋮----
return new \WP_REST_Response(
⋮----
'message' => 'Failed to create template: ' . $template_id->get_error_message(),
⋮----
function tools_get_available_templates() {
⋮----
return new \WP_REST_Response( $available_templates, 200 );
⋮----
function tools_get_available_versions( $request ) {
⋮----
return new \WP_REST_Response( array(), 200 );
⋮----
return new \WP_REST_Response( $versions, 200 );
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/reset-launch-your-store.php">
function tools_reset_launch_your_store() {
⋮----
$result = ( new \Automattic\WooCommerce\Admin\API\LaunchYourStore() )->initialize_coming_soon();
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/run-wc-admin-daily.php">
function tools_run_wc_admin_daily() {
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/set-block-template-logging-threshold.php">
function tools_get_logging_levels() {
⋮----
function tools_get_block_template_logging_threshold() {
⋮----
function tools_update_block_template_logging_threshold( $request ) {
$threshold = $request->get_param( 'threshold' );
⋮----
if ( ! isset( $threshold ) || ! \WC_Log_Levels::is_valid_level( $threshold ) ) {
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/set-coming-soon-mode.php">
use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonCacheInvalidator;
⋮----
function tools_set_coming_soon_mode( $request ) {
$mode = $request->get_param( 'mode' );
⋮----
wc_get_container()->get( ComingSoonCacheInvalidator::class )->invalidate_caches();
⋮----
function tools_get_coming_soon_mode() {
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/set-wccom-base-url.php">
function tools_set_wccom_base_url( $request ) {
$url = $request->get_param( 'url' );
⋮----
function tools_get_wccom_base_url() {
⋮----
$url = WC_Helper::get_woocommerce_com_base_url();
⋮----
/**
 * Filter WooCommerce.com base URL.
 *
 * @param string $default_url Default WooCommerce.com base URL.
 * @return string
 */
function filter_wccom_base_url( $default_url ) {
⋮----
function filter_http_request_args_for_custom_wccom_url( $args, $url ) {
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/trigger-cron-job.php">
function tools_get_cron_list() {
⋮----
function trigger_selected_cron( $request ) {
$hook      = $request->get_param( 'hook' );
$signature = $request->get_param( 'signature' );
⋮----
function schedule_event( $hook, $args = array() ) {
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/trigger-update-callbacks.php">
function tools_get_wc_admin_versions() {
$db_updates = \WC_Install::get_db_update_callbacks();
⋮----
function trigger_selected_update_callbacks( $request ) {
$version = $request->get_param( 'version' );
⋮----
$db_updates       = \WC_Install::get_db_update_callbacks();
⋮----
\WC_Install::run_update_callback( $update_callback );
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/trigger-wca-install.php">
function tools_trigger_wca_install() {
\WC_Install::install();
</file>

<file path="plugins/woocommerce-beta-tester/api/tools/wccom-request-errors.php">
function tools_set_wccom_request_errors( $request ) {
$mode = $request->get_param( 'mode' );
⋮----
function tools_get_wccom_request_errors() {
</file>

<file path="plugins/woocommerce-beta-tester/api/tracks/class-tracks-debug-log.php">
class Tracks_Debug_Log {
⋮----
private $logger;
⋮----
private $source = 'tracks';
⋮----
private function get_logger() {
⋮----
public function __construct() {
⋮----
public function log_event( $event_name, $properties ) {
$logger = $this->get_logger();
⋮----
$logger->debug(
⋮----
public function log_footer_pixels() {
$events = WC_Tracks_Footer_Pixel::get_events();
⋮----
$this->log_event( $event->_en, $event );
⋮----
public function log_remote_pixels( $preempt, $parsed_args, $url ) {
⋮----
$this->log_event( $params['_en'], $params );
</file>

<file path="plugins/woocommerce-beta-tester/api/api.php">
function register_woocommerce_admin_test_helper_rest_route( $route, $callback, $additional_options = array() ) {
⋮----
return new \WP_Error(
</file>

<file path="plugins/woocommerce-beta-tester/changelog/.gitkeep">

</file>

<file path="plugins/woocommerce-beta-tester/changelog/49120-remove-async-product-editor-category-field">
Significance: patch
Type: update

Remove async product editor category field from live branch feature flags.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/55796-add-54370-hide_flat_rate_when_free">
Significance: patch
Type: add

Implement hide shipping rates when free is available option
</file>

<file path="plugins/woocommerce-beta-tester/changelog/56506-remove-wp-components-types">
Significance: patch
Type: dev
Comment: Remove deprecated `@types/wordpress__components`
</file>

<file path="plugins/woocommerce-beta-tester/changelog/56746-dev-webpack-deps-review">
Significance: patch
Type: dev

Monorepo: Webpack deps review and consolidation and a bit of deps grooming
</file>

<file path="plugins/woocommerce-beta-tester/changelog/57299-fix-wireit-in-ci">
Significance: patch
Type: dev

Bump wireit dependency version to latest.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/57605-fix-wc-beta-tester-cys-reset">
Significance: patch
Type: tweak

Beta Tester: Remove not necessary endpoints to reset CYS.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/58755-dev-53714">
Significance: patch
Type: dev
Comment: Bumped PHP version to 8.1
</file>

<file path="plugins/woocommerce-beta-tester/changelog/58941-dev-consolidate-packages-license-version">
Significance: patch
Type: dev

Monorepo: consolidate packages licenses to `GPL-2.0-or-later`.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/61753-fix-support-composer-update">
Significance: major
Type: update

Updated all PHP dependencies.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/64076-remove-legacy-rest-api-options">
Significance: minor
Type: dev

Remove Legacy REST API settings section, admin notices, auto-install logic, and UI nudges from WooCommerce core. The Legacy REST API extension continues to work if manually installed.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/66078-dehoist-react">
Significance: patch
Type: dev
Comment: Declare react/react-dom as devDependencies alongside the existing peerDependencies. Tooling only; no runtime change.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/66097-bump-wp-env-and-playwright">
Significance: patch
Type: dev
Comment: Bump @wordpress/env to 11.9.0 and @playwright/test to 1.61.1 (dev dependencies; no merchant-facing change).
</file>

<file path="plugins/woocommerce-beta-tester/changelog/add-55908-beta-tester-ci-config">
Significance: patch
Type: dev
Comment: Add CI configuration to the WooCommerce Beta Tester package.json so lint and JavaScript unit test jobs run when the package's code changes; the JavaScript test job additionally runs when a monorepo dependency changes.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/add-simplify-cys-remove-unnecessary-code">
Significance: patch
Type: update

Reset Customize Your Store: simplify the action to adjust to journey updates
</file>

<file path="plugins/woocommerce-beta-tester/changelog/add-woocommerce-beta-tester-template-load-tool">
Significance: minor
Type: add

Add template loading tool in beta tester
</file>

<file path="plugins/woocommerce-beta-tester/changelog/dev-add-note-drop-image-layout">
Significance: patch
Type: dev
Comment: Remove the image and layout fields from the test "Add admin note" tool now that inbox notes no longer render images.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/dev-drop-phpunit-and-bump-symfony-process">
Significance: patch
Type: dev

Remove the unused PHPUnit dev dependency and move symfony/process to a patched version.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/dev-eslint-no-floating-promises">
Significance: patch
Type: dev

Add void to intentionally-unawaited promises for the new no-floating-promises lint rule
</file>

<file path="plugins/woocommerce-beta-tester/changelog/fix-beta-tester-delete-option-error">
Significance: patch
Type: fix

Fix TypeError when deleting the simulate WooCommerce JS error option
</file>

<file path="plugins/woocommerce-beta-tester/changelog/fix-beta-tester-live-branch">
Significance: patch
Type: fix

Fix live-branches api request body structure to use 'data' instead of 'body'
</file>

<file path="plugins/woocommerce-beta-tester/changelog/fix-live-branches-github-selectors">
Significance: patch
Type: fix

Fix live-branches userscript broken by GitHub DOM changes: extract PR data from embedded JSON instead of removed CSS selectors, and fix checkbox change listeners that were never attached due to arrow function misuse.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/fix-missing-index-build">
Significance: patch
Type: fix

Restore the main Beta Tester JavaScript bundle and correct asset version fallback paths.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/fix-wordpress-data-dependency">
Significance: patch
Type: dev
Comment: Declare the WordPress data package used by the beta tester tools.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/remove-product-editor-devtools">
Significance: patch
Type: dev

Remove product editor devtools for the deprecated product block editor.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/update-migrate-reactify-feature-flag">
Significance: minor
Type: update

Remove reactify-classic-payments-settings flag as it was migrated to Core features
</file>

<file path="plugins/woocommerce-beta-tester/changelog/update-php-dev-dependency-security-patches">
Significance: patch
Type: dev

Update PHP development dependencies to versions that resolve reported security advisories.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/update-pnpm-10-upgrade">
Significance: patch
Type: dev

Update @wordpress/* peerDependencies from dist-tags to semver ranges for pnpm 10 compatibility.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/update-switch-version-button-location">
Significance: minor
Type: enhancement

Added additional switch version button to the top of versions list
</file>

<file path="plugins/woocommerce-beta-tester/changelog/update-wp-68-packages">
Significance: major
Type: update

Update @wordpress/* dependencies to wp-6.8 minimum.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/update-wpcs-3-4-1">
Significance: patch
Type: dev

Update woocommerce-sniffs to 1.0.1 / wp-coding-standards/wpcs to 3.4.1 (security release).
</file>

<file path="plugins/woocommerce-beta-tester/changelog/wooplug-5699-add-license-file-to-root">
Significance: patch
Type: dev
Comment: Add a license file to the repository root and reference it from the README. Documentation only; no runtime change.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/wooplug-6930-adopt-import-order">
Significance: patch
Type: dev
Comment: Remove obsolete @woocommerce/dependency-group eslint-disable directives following the switch to import/order in @woocommerce/eslint-plugin.
</file>

<file path="plugins/woocommerce-beta-tester/changelog/wooplug-6930-eslint-v10-flat-config">
Significance: patch
Type: dev
Comment: Migrate to ESLint v10 Flat Config. Tooling only; no runtime change.
</file>

<file path="plugins/woocommerce-beta-tester/includes/views/html-admin-missing-woocommerce.php">

</file>

<file path="plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-admin-assets.php">
class WC_Beta_Tester_Admin_Assets {
⋮----
public function __construct() {
⋮----
public function admin_scripts() {
⋮----
wp_register_style( 'wc-beta-tester-admin', WC_Beta_Tester::instance()->plugin_url() . '/assets/css/admin.css', array( 'woocommerce_admin_styles' ), WC_BETA_TESTER_VERSION );
⋮----
wp_register_script( 'wc-beta-tester-version-info', WC_Beta_Tester::instance()->plugin_url() . '/assets/js/version-information' . $suffix . '.js', array( 'wc-backbone-modal' ), WC_BETA_TESTER_VERSION, false );
wp_register_script( 'wc-beta-tester-version-picker', WC_Beta_Tester::instance()->plugin_url() . '/assets/js/version-picker' . $suffix . '.js', array( 'wc-backbone-modal' ), WC_BETA_TESTER_VERSION, false );
</file>

<file path="plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-admin-menus.php">
class WC_Beta_Tester_Admin_Menus {
⋮----
public function __construct() {
⋮----
protected function get_ticket_template() {
⋮----
private function get_theme_ssr_info( $theme ) {
⋮----
private function get_plugins_ssr_info( $active_plugins, $untested_plugins ) {
⋮----
protected function construct_ssr() {
⋮----
// Get SSR.
⋮----
$schema   = $api->get_item_schema();
$mappings = $api->get_item_mappings();
⋮----
$active_plugins   = $api->get_active_plugins();
⋮----
$untested_plugins = $plugin_updates->get_untested_plugins( WC()->version, 'minor' );
$ssr             .= $this->get_plugins_ssr_info( $active_plugins, $untested_plugins );
$theme            = $api->get_theme_info();
$ssr             .= $this->get_theme_ssr_info( $theme );
⋮----
protected function get_github_ticket_url() {
$bug_tpl = $this->get_ticket_template();
$ssr     = $this->construct_ssr();
⋮----
$body    = str_replace( '```', '', $body ); // Remove since this break how is displayed.
⋮----
... (14 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-admin-notices.php">
class WC_Beta_Tester_Admin_Notices {
⋮----
public function woocoommerce_not_installed() {
</file>

<file path="plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-channel.php">
class WC_Beta_Tester_Channel {
⋮----
public function __construct() {
⋮----
public function settings_init() {
⋮----
public function update_section_html( $args ) {
⋮----
public function version_select_html( $args ) {
$settings = WC_Beta_Tester::get_settings();
⋮----
public function automatic_update_checkbox_html( $args ) {
⋮----
public function add_to_menus() {
⋮----
public function settings_page_html() {
</file>

<file path="plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-cli.php">
class WC_Beta_Tester_CLI extends WP_CLI_Command {
⋮----
public function install( $args ) {
⋮----
$info = $installer->get_branch_info_from_manifest( $branch );
⋮----
WP_CLI::error( "Could not find branch $branch in manifest" );
⋮----
$install_result = $installer->install( $info->download_url, $info->version );
⋮----
WP_CLI::error( $install_result->get_error_message() );
⋮----
WP_CLI::success( "Installed $branch" );
⋮----
public function deactivate_woocommerce() {
⋮----
$installer->deactivate_woocommerce();
⋮----
WP_CLI::success( 'Deactivated WooCommerce' );
⋮----
public function activate( $args ) {
⋮----
$info      = $installer->get_branch_info_from_manifest( $branch );
⋮----
$installer->activate( $info->version );
⋮----
WP_CLI::success( "Activated $branch" );
</file>

<file path="plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-import-export.php">
class WC_Beta_Tester_Import_Export {
⋮----
protected $message;
⋮----
public function __construct() {
$this->add_hooks();
⋮----
public function add_hooks() {
⋮----
public function add_to_menu() {
⋮----
public function settings_page_html() {
⋮----
$this->maybe_import_settings();
⋮----
public function export_settings() {
⋮----
echo wp_json_encode( $this->get_settings() );
⋮----
public function maybe_import_settings() {
⋮----
$this->add_message( __( 'Invalid submission', 'woocommerce-beta-tester' ) );
⋮----
$this->add_message( __( 'No file uploaded.', 'woocommerce-beta-tester' ) );
⋮----
$this->add_message( __( 'File could not be read.', 'woocommerce-beta-tester' ) );
⋮----
foreach ( $this->get_setting_list() as $option_name ) {
⋮----
$this->add_message( __( 'Settings Imported', 'woocommerce-beta-tester' ), 'updated' );
... (9 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-live-branches-installer.php">
class WC_Beta_Tester_Live_Branches_Installer {
⋮----
private $file_system;
⋮----
public function __construct() {
$this->file_system = $this->init_filesystem();
⋮----
private function init_filesystem() {
⋮----
public function get_branch_info_from_manifest( $branch ) {
⋮----
public function install( $download_url, $version ) {
⋮----
sprintf( __( 'Error Downloading: <a href="%1$s">%1$s</a> - Error: %2$s', 'woocommerce-beta-tester' ), $download_url, $tmp_dir->get_error_message() )
⋮----
$plugin_dir  = str_replace( ABSPATH, $this->file_system->abspath(), WP_PLUGIN_DIR );
⋮----
$this->file_system->delete( $tmp_dir );
⋮----
return new WP_Error( 'unzip_error', sprintf( __( 'Error Unzipping file: Error: %1$s', 'woocommerce-beta-tester' ), $unzip->get_error_message() ) );
⋮----
$this->file_system->mkdir( $plugin_path );
$this->move( $source, $plugin_path );
⋮----
$this->file_system->delete( $unzip_path, true );
⋮----
$this->file_system->delete( $tmp_dir, true );
⋮----
private function move( $from, $to ) {
⋮----
... (8 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-live-branches.php">
class WC_Beta_Tester_Live_Branches {
⋮----
public function __construct() {
⋮----
private function woocommerce_is_installed() {
⋮----
public function register_scripts() {
if ( ! $this->woocommerce_is_installed() ) {
⋮----
$script_url        = WC_Beta_Tester::instance()->plugin_url() . $script_path;
⋮----
public function register_page() {
</file>

<file path="plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-override-coming-soon-options.php">
class WC_Beta_Tester_Override_Coming_Soon_Options {
⋮----
public function __construct() {
$this->wc_beta_tester_override_coming_soon_options();
⋮----
public function wc_beta_tester_override_coming_soon_options() {
⋮----
&& ! defined( 'DOING_CRON' ) && ! WC()->is_rest_api_request();
⋮----
$this->override_woocommerce_coming_soon_option( $mode );
$this->override_woocommerce_store_pages_only_option( $mode );
⋮----
private function override_woocommerce_coming_soon_option( $mode ) {
⋮----
private function override_woocommerce_store_pages_only_option( $mode ) {
</file>

<file path="plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-plugin-upgrader.php">
class WC_Beta_Tester_Plugin_Upgrader extends Plugin_Upgrader {
⋮----
public function switch_version( $plugin, $args = array() ) {
⋮----
$this->init();
$this->upgrade_strings();
⋮----
$download_url = WC_Beta_Tester::instance()->get_download_url( $plugin_version );
⋮----
$this->run(
</file>

<file path="plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-version-picker.php">
class WC_Beta_Tester_Version_Picker {
⋮----
protected $current_version = '';
⋮----
/**
	 * Constructor
	 */
public function __construct() {
⋮----
public function handle_version_switch() {
⋮----
$result   = $upgrader->switch_version( $plugin );
⋮----
throw new Exception( $skin->result->get_error_message() );
⋮----
WC_Admin_Notices::add_custom_notice(
⋮----
$e->getMessage()
⋮----
wp_die( esc_html( $e->getMessage() ) );
⋮----
public function add_to_menus() {
⋮----
public function get_versions_html( $channel ) {
$tags = WC_Beta_Tester::instance()->get_tags( $channel );
⋮----
// The nonce is validated upstream.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
⋮----
$plugin_data           = WC_Beta_Tester::instance()->get_plugin_data();
... (7 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/includes/class-wc-beta-tester-wccom-requests.php">
class WC_Beta_Tester_WCCOM_Requests {
⋮----
public function __construct() {
$this->wc_beta_tester_modify_wccom_responses();
⋮----
public function wc_beta_tester_modify_wccom_responses() {
⋮----
public function override_http_request_timeout( $response, $args, $url ) {
⋮----
public function override_http_request_error( $response, $args, $url ) {
</file>

<file path="plugins/woocommerce-beta-tester/includes/class-wc-beta-tester.php">
class WC_Beta_Tester {
⋮----
private $plugin_config;
⋮----
private $plugin_name;
⋮----
protected static $instance = null;
⋮----
private $wporg_data;
⋮----
public static function instance() {
⋮----
public static function activate() {
⋮----
public static function get_settings() {
⋮----
public function plugin_url() {
⋮----
public function __construct() {
⋮----
if ( 'stable' !== $this->get_settings()->channel ) {
⋮----
$this->includes();
⋮----
public function includes() {
⋮----
public function overrule_transients() {
⋮----
public function is_prerelease( $version ) {
⋮----
... (67 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/includes/wc-beta-tester-settings-list.php">
function wc_beta_tester_setting_list() {
</file>

<file path="plugins/woocommerce-beta-tester/src/admin-notes/add-note.js">
export const AddNote = () =>
⋮----
async function triggerAddNote()
⋮----
function onTypeChange( val )
⋮----
function getAddNoteDescription()
</file>

<file path="plugins/woocommerce-beta-tester/src/admin-notes/admin-notes.js">
export const AdminNotes = () =>
</file>

<file path="plugins/woocommerce-beta-tester/src/admin-notes/delete-all-notes.js">
export const DeleteAllNotes = () =>
⋮----
async function triggerDeleteAllNotes()
</file>

<file path="plugins/woocommerce-beta-tester/src/admin-notes/index.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/app/app.js">
const getTabByName = ( tabName, availableTabs ) =>
⋮----
const getActiveTab = () =>
⋮----
export function App()
⋮----
const handleTabSelect = ( tabName ) =>
⋮----
// Handle browser back/forward navigation
⋮----
const handlePopState = () =>
⋮----
// Tab panel manages its own state, but doesn't apply the active class to the correct tab when navigating back so we don't use it.
</file>

<file path="plugins/woocommerce-beta-tester/src/app/index.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/example-fills/experimental-woocommerce-wcpay-feature.js">
const MyFill = () => (
	<Fill name="experimental_woocommerce_wcpay_feature">
		<div className="woocommerce-experiments-placeholder-slotfill">
			<div className="placeholder-slotfill-content">
				Slotfill goes in here!
			</div>
		</div>
	</Fill>
);
</file>

<file path="plugins/woocommerce-beta-tester/src/experiments/data/action-types.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/experiments/data/actions.js">
function toggleFrontendExperiment( experimentName, newVariation )
⋮----
function* toggleBackendExperiment( experimentName, newVariation )
⋮----
export function* toggleExperiment( experimentName, currentVariation )
⋮----
export function setExperiments( experiments )
⋮----
export function* addExperiment( experimentName, variation )
⋮----
export function* deleteExperiment( experimentName )
</file>

<file path="plugins/woocommerce-beta-tester/src/experiments/data/constants.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/experiments/data/index.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/experiments/data/reducer.js">
const reducer = ( state = DEFAULT_STATE, action ) =>
</file>

<file path="plugins/woocommerce-beta-tester/src/experiments/data/resolvers.js">
function getExperimentsFromFrontend()
⋮----
export function* getExperiments()
</file>

<file path="plugins/woocommerce-beta-tester/src/experiments/data/selectors.js">
export function getExperiments( state )
</file>

<file path="plugins/woocommerce-beta-tester/src/experiments/index.js">
function Experiments( {
	experiments,
	toggleExperiment,
	deleteExperiment,
	isTrackingEnabled,
	isResolving,
} )
</file>

<file path="plugins/woocommerce-beta-tester/src/experiments/NewExperimentForm.js">
function NewExperimentForm(
⋮----
const getInputValue = ( event ) =>
⋮----
const getVariationInput = ( event ) =>
⋮----
const AddNewExperiment = () =>
</file>

<file path="plugins/woocommerce-beta-tester/src/features/data/action-types.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/features/data/actions.js">
export function setFeatures( features )
⋮----
export function setModifiedFeatures( modifiedFeatures )
⋮----
export function* resetModifiedFeatures()
⋮----
export function* toggleFeature( featureName )
</file>

<file path="plugins/woocommerce-beta-tester/src/features/data/constants.ts">

</file>

<file path="plugins/woocommerce-beta-tester/src/features/data/index.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/features/data/reducer.js">
const reducer = ( state = DEFAULT_STATE, action ) =>
</file>

<file path="plugins/woocommerce-beta-tester/src/features/data/resolvers.js">
export function* getModifiedFeatures()
⋮----
export function* getFeatures()
</file>

<file path="plugins/woocommerce-beta-tester/src/features/data/selectors.js">
export function getFeatures( state )
⋮----
export function getModifiedFeatures( state )
</file>

<file path="plugins/woocommerce-beta-tester/src/features/index.js">
function Features()
</file>

<file path="plugins/woocommerce-beta-tester/src/live-branches/components/BranchList.tsx">
import {
	__experimentalItemGroup as ItemGroup,
	__experimentalItem as Item,
	Button,
	Spinner,
	Card,
	CardHeader,
	CardBody,
	CardFooter,
	ComboboxControl,
} from '@wordpress/components';
import { useState, Fragment } from 'react';
import { css } from '@emotion/react';
⋮----
import { Branch, useLiveBranchInstall } from '../hooks/live-branches';
⋮----
const activateBranch = async () =>
⋮----
const installAndActivateBranch = async () =>
⋮----
const BranchInfo = (
⋮----
const WooCommerceVersionInfo = () =>
</file>

<file path="plugins/woocommerce-beta-tester/src/live-branches/hooks/live-branches.tsx">
import apiFetch from '@wordpress/api-fetch';
import { useEffect, useState } from 'react';
⋮----
import { API_NAMESPACE } from '../../features/data/constants';
⋮----
type PluginStatus = 'not-installed' | 'installed' | 'active';
⋮----
export type Branch = {
	branch: string;
	commit: string;
	download_url: string;
	update_date: string;
	version: string;
	pr: number;
	install_status: PluginStatus;
};
⋮----
type LiveBranchesResponse = {
	pr: { [ key: string ]: Branch };
	master: Branch;
};
⋮----
export const useLiveBranchesData = () =>
⋮----
const getBranches = async () =>
⋮----
export const useLiveBranchInstall = (
	downloadUrl: string,
	prName: string,
	version: string,
... (7 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/src/live-branches/App.tsx">
import { Spinner } from '@woocommerce/components';
import {
	__experimentalHeading as Heading,
} from '@wordpress/components';
⋮----
import { useLiveBranchesData } from './hooks/live-branches';
import { BranchList } from './components/BranchList';
⋮----
export const App = () =>
</file>

<file path="plugins/woocommerce-beta-tester/src/live-branches/index.tsx">
import { addFilter } from '@wordpress/hooks';
⋮----
import { App } from './App';
</file>

<file path="plugins/woocommerce-beta-tester/src/options/data/action-types.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/options/data/actions.js">
export function setOptions( options )
⋮----
export function setLoadingState( isLoading )
⋮----
export function setOptionForEditing( editingOption )
⋮----
export function setNotice( notice )
⋮----
export function* deleteOption( optionName )
⋮----
export function* saveOption( optionName, newOptionValue )
</file>

<file path="plugins/woocommerce-beta-tester/src/options/data/constants.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/options/data/index.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/options/data/reducer.js">
const reducer = ( state = DEFAULT_STATE, action ) =>
</file>

<file path="plugins/woocommerce-beta-tester/src/options/data/resolvers.js">
export function* getOptions( search )
⋮----
export function* getOptionForEditing( optionName )
</file>

<file path="plugins/woocommerce-beta-tester/src/options/data/selectors.js">
export function getOptions( state )
⋮----
export function isLoading( state )
⋮----
export function getOptionForEditing( state )
⋮----
export function getNotice( state )
</file>

<file path="plugins/woocommerce-beta-tester/src/options/index.js">
function shorten( input )
⋮----
function Options( {
	options,
	getOptions,
	deleteOption,
	isLoading,
	invalidateResolution,
	getOptionForEditing,
	editingOption,
	saveOption,
	notice,
	setNotice,
} )
⋮----
const deleteOptionByName = ( optionName ) =>
⋮----
const openEditModal = ( optionName ) =>
⋮----
const handleSaveOption = ( optionName, newValue ) =>
⋮----
const renderLoading = () =>
⋮----
const renderTableData = () =>
⋮----
const searchOption = ( event ) =>
</file>

<file path="plugins/woocommerce-beta-tester/src/options/option-modal.js">
export const OptionModal = ( props ) =>
⋮----
const handleChange = ( event ) =>
⋮----
const handleSave = () =>
</file>

<file path="plugins/woocommerce-beta-tester/src/payments/index.js">
const Payments = () =>
⋮----
const isTestOrder = ( order )
⋮----
const onToggle = async ( order, isChecked ) =>
⋮----
const renderOrders = ( orderList ) =>
</file>

<file path="plugins/woocommerce-beta-tester/src/remote-inbox-notifications/data/action-types.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/remote-inbox-notifications/data/actions.js">
export function setNotifications( notifications )
⋮----
export function setLoadingState( isLoading )
⋮----
export function setNotice( notice )
⋮----
export function* importNotifications( notifications )
⋮----
export function* deleteNotification( id )
⋮----
export function* testNotification( name )
⋮----
export function* deleteAllNotifications()
</file>

<file path="plugins/woocommerce-beta-tester/src/remote-inbox-notifications/data/constants.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/remote-inbox-notifications/data/index.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/remote-inbox-notifications/data/reducer.js">
const reducer = ( state = DEFAULT_STATE, action ) =>
</file>

<file path="plugins/woocommerce-beta-tester/src/remote-inbox-notifications/data/resolvers.js">
export function* getNotifications()
</file>

<file path="plugins/woocommerce-beta-tester/src/remote-inbox-notifications/data/selectors.js">
export function getNotifications( state )
⋮----
export function isLoading( state )
⋮----
export function getNotice( state )
</file>

<file path="plugins/woocommerce-beta-tester/src/remote-inbox-notifications/index.js">
function RemoteInboxNotifications( {
	notifications,
	deleteNotification,
	importNotifications,
	deleteAllNotifications,
	testNotification,
	isLoading,
	notice,
	setNotice,
} )
⋮----
const importFromUrl = async ( _url ) =>
const renderLoading = () =>
⋮----
const renderTableData = () =>
</file>

<file path="plugins/woocommerce-beta-tester/src/remote-logging/constants.ts">

</file>

<file path="plugins/woocommerce-beta-tester/src/remote-logging/index.tsx">
import { useState, useEffect } from '@wordpress/element';
import { Button, ToggleControl, Notice, Spinner } from '@wordpress/components';
import apiFetch from '@wordpress/api-fetch';
import { log, init as initRemoteLogging } from '@woocommerce/remote-logging';
⋮----
import { dispatch } from '@wordpress/data';
⋮----
import { API_NAMESPACE } from './constants';
⋮----
import { STORE_KEY as optionsStore } from '../options/data/constants';
⋮----
interface RemoteLoggingStatus {
	isEnabled: boolean;
	wpEnvironment: string;
}
⋮----
interface NoticeState {
	status: 'success' | 'error' | 'warning' | 'info';
	message: string;
}
⋮----
const fetchRemoteLoggingStatus = async () =>
⋮----
const toggleRemoteLogging = async () =>
⋮----
const simulatePhpException = async ( context: 'core' | 'beta-tester' ) =>
⋮----
const logPhpEvent = async () =>
⋮----
const resetPhpRateLimit = async () =>
... (7 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/src/remote-logging/register-exception-filter.tsx">
import { addFilter } from '@wordpress/hooks';
⋮----
import apiFetch from '@wordpress/api-fetch';
⋮----
import { API_NAMESPACE } from './constants';
⋮----
const getSimulateErrorOptions = async () =>
⋮----
const deleteSimulateErrorOption = async () =>
⋮----
const addCoreExceptionFilter = () =>
⋮----
const throwBetaTesterException = () =>
⋮----
export const registerExceptionFilter = async () =>
</file>

<file path="plugins/woocommerce-beta-tester/src/remote-spec-validator/data/action-types.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/remote-spec-validator/data/actions.js">
export function* validate( jsonString )
⋮----
export function setMessage( type, text )
</file>

<file path="plugins/woocommerce-beta-tester/src/remote-spec-validator/data/constants.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/remote-spec-validator/data/index.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/remote-spec-validator/data/reducer.js">
const reducer = ( state = DEFAULT_STATE, action ) =>
</file>

<file path="plugins/woocommerce-beta-tester/src/remote-spec-validator/data/resolvers.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/remote-spec-validator/data/selectors.js">
export function getMessage( state )
</file>

<file path="plugins/woocommerce-beta-tester/src/remote-spec-validator/index.js">
function RemoteSpecValidator(
</file>

<file path="plugins/woocommerce-beta-tester/src/rest-api-filters/data/action-types.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/rest-api-filters/data/actions.js">
export function setFilters( filters )
⋮----
export function setLoadingState( isLoading )
⋮----
export function* toggleFilter( index )
⋮----
export function* deleteFilter( index )
⋮----
export function* saveFilter( endpoint, dotNotation, replacement )
</file>

<file path="plugins/woocommerce-beta-tester/src/rest-api-filters/data/constants.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/rest-api-filters/data/index.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/rest-api-filters/data/reducer.js">
const reducer = ( state = DEFAULT_STATE, action ) =>
</file>

<file path="plugins/woocommerce-beta-tester/src/rest-api-filters/data/resolvers.js">
export function* getFilters()
</file>

<file path="plugins/woocommerce-beta-tester/src/rest-api-filters/data/selectors.js">
export function getFilters( state )
⋮----
export function isLoading( state )
</file>

<file path="plugins/woocommerce-beta-tester/src/rest-api-filters/index.js">
function RestAPIFilters( {
	filters,
	deleteFilter,
	isLoading,
	saveFilter,
	toggleFilter,
} )
⋮----
const submitAddForm = ( e ) =>
⋮----
const renderLoading = () =>
⋮----
const renderTableData = () =>
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/commands/disable-email.js">
export const DisableEmail = () =>
⋮----
const getEmailStatus = () =>
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/commands/fake-woo-payments.js">
export const FakeWooPayments = () =>
⋮----
const getDescription = () =>
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/commands/index.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/tools/commands/load-template-version.js">
export const LoadTemplateVersion = () =>
⋮----
/**
	 * Load available templates
	 */
const loadTemplates = async () =>
⋮----
const loadVersions = async ( templateName ) =>
⋮----
/**
	 * Handle template selection change
	 *
	 * @param {string} value Selected template
	 */
const handleTemplateChange = ( value ) =>
⋮----
/**
	 * Handle version selection change
	 *
	 * @param {string} value Selected version
	 */
const handleVersionChange = ( value ) =>
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/commands/set-coming-soon-mode.js">
export const SetComingSoonMode = () =>
⋮----
function onChange( mode )
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/commands/set-wccom-base-url.js">
export const SetWccomBaseUrl = () =>
⋮----
function onUpdate( newUrl )
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/commands/set-wccom-request-errors.js">
export const SetWccomRequestErrors = () =>
⋮----
function onChange( mode )
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/commands/trigger-cron.js">
export const TriggerCronJob = () =>
⋮----
function onCronChange( selectedValue )
⋮----
function getOptions()
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/commands/trigger-update-callbacks.js">
export const TriggerUpdateCallbacks = () =>
⋮----
function onChange( version )
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/commands/update-block-template-logging-threshold.tsx">
import { SelectControl } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
⋮----
import { store } from '../data';
⋮----
interface LoggingLevel {
	label: string;
	value: string;
}
⋮----
function onThresholdChange( selectedThreshold: string )
⋮----
function getOptions()
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/data/action-types.ts">

</file>

<file path="plugins/woocommerce-beta-tester/src/tools/data/actions.js">
export function addCurrentlyRunning( command )
⋮----
export function removeCurrentlyRunning( command )
⋮----
export function addMessage( source, message )
⋮----
export function updateMessage( source, message, status )
⋮----
export function removeMessage( source )
⋮----
export function updateCommandParams( source, params )
⋮----
export function setCronJobs( cronJobs )
⋮----
export function setDBUpdateVersions( versions )
⋮----
export function setIsEmailDisabled( isEmailDisabled )
⋮----
function* runCommand( commandName, func )
⋮----
export function* triggerWcaInstall()
⋮----
export function* resetOnboardingWizard()
⋮----
export function* resetJetpackConnection()
⋮----
export function* enableTrackingDebug()
⋮----
export function* updateStoreAge()
⋮----
... (32 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/data/constants.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/tools/data/constants.ts">

</file>

<file path="plugins/woocommerce-beta-tester/src/tools/data/index.js">

</file>

<file path="plugins/woocommerce-beta-tester/src/tools/data/index.ts">
import { createReduxStore, register } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
⋮----
import reducer from './reducer';
import { STORE_KEY } from './constants';
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/data/reducer.js">
const reducer = ( state = DEFAULT_STATE, action ) =>
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/data/resolvers.js">
export function* getCronJobs()
⋮----
export function* getDBUpdateVersions()
⋮----
export function* getIsEmailDisabled()
⋮----
export function* getLoggingLevels()
⋮----
export function* getBlockTemplateLoggingThreshold()
⋮----
export function* getComingSoonMode()
⋮----
export function* getWccomRequestErrorsMode()
⋮----
export function* getIsFakeWooPaymentsEnabled()
⋮----
export function* getWccomBaseUrl()
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/data/selectors.js">
export function getCurrentlyRunning( state )
⋮----
export function getMessages( state )
⋮----
export function getStatus( state )
⋮----
export function getCommandParams( state )
⋮----
export function getCronJobs( state )
⋮----
export function getIsEmailDisabled( state )
⋮----
export function getDBUpdateVersions( state )
⋮----
export function getLoggingLevels( state )
⋮----
export function getBlockTemplateLoggingThreshold( state )
⋮----
export function getComingSoonMode( state )
⋮----
export function getWccomRequestErrorsMode( state )
⋮----
export function getIsFakeWooPaymentsEnabled( state )
⋮----
export function getWccomBaseUrl( state )
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/index.js">
function Tools( {
	actions,
	currentlyRunningCommands,
	messages,
	commandParams,
} )
</file>

<file path="plugins/woocommerce-beta-tester/src/tools/README.md">
# Tools

## Adding a New Command

1. Open `commands.js` and add a new object with command, description, and action keys. Action value must be a valid function name.
2. Open `data/actions.js` and add a function. The function name must be the value of `Action` from the first step.

Sample function:
```
export function* helloWorld() {
	yield runCommand( 'Hello World', function* () {
        console.log('Hello World');
	} );
}
```

3. Run `npm start` to compile and test.
</file>

<file path="plugins/woocommerce-beta-tester/src/index.js">

</file>

<file path="plugins/woocommerce-beta-tester/typing/global.d.ts">
interface Window {
		wcSettings: {
			isRemoteLoggingEnabled: boolean;
		};
		wc: {
			wcSettings: {
				WC_VERSION: string;
			}
		}
	}
</file>

<file path="plugins/woocommerce-beta-tester/userscripts/README.md">
# WooCommerce Live Branches User Script

`wc-live-branches.user.js` is a Tampermonkey script that allows you to preview a site with a given Pull Request changeset.

## Installation

1. Install Tampermonkey or equivalent user script extension.
2. Click https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/plugins/woocommerce-beta-tester/userscripts/wc-live-branches.user.js Once installed, it should be able to auto-update

## Development

Make sure you update the version in the wc-live-branches.user.js file.
Create a PR in this repo.
</file>

<file path="plugins/woocommerce-beta-tester/userscripts/wc-live-branches.user.js">
function determineRepo()
⋮----
function getPRDataFromEmbeddedJson()
⋮----
// Fall through to legacy method.
⋮----
/**
	 * Determine PR data from legacy DOM selectors.
	 *
	 * @return {object|null} Data with currentBranch and branchStatus, or null.
	 */
function getPRDataFromDom()
⋮----
/** Function. */
function doit()
⋮----
function encodeHtmlEntities( s )
⋮----
/**
		 * Build the JN create URI.
		 *
		 * @return {string} URI.
		 */
function getLink()
⋮----
// prettier-ignore
⋮----
/**
		 * Build HTML for a single option checkbox.
		 *
... (47 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/.prettierrc.js">

</file>

<file path="plugins/woocommerce-beta-tester/.travis.yml">
language: php
before_script:
  - |
    if [ -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini ]; then
      phpenv config-rm xdebug.ini
    else
      echo "xdebug.ini does not exist"
    fi
  - composer install
script:
  - ./vendor/bin/phpcs -s -n -p *
branches:
  only:
    - master
</file>

<file path="plugins/woocommerce-beta-tester/.wp-env.json">
{
	"phpVersion": "8.1",
	"plugins": [ 
        ".",
        "https://downloads.wordpress.org/plugin/woocommerce.zip"
     ]
}
</file>

<file path="plugins/woocommerce-beta-tester/changelog.txt">
*** WooCommerce Beta Tester Changelog ***

2025-02-20 - version 3.0.0
* Patch - Fix warnings on the Plugins page when a plugin requires another plugin
* Patch - Add tab navigation with URL state management in WooCommerce Admin Test Helper
* Patch - Change remote logging event level from critical to info
* Patch - Enhance live branches API with permission checks to allow install desired WC version without WC exists
* Patch - Update links to download WooCommerce Beta Tester
* Minor - Bump @wordpress/env to 10.14.0 and remove patch for 10.10.0
* Patch - Bump @wordpress/env to 10.17.0
* Minor - Fix TS errors and re-enable type checking
* Minor - Monorepo: bump pnpm version to 9.15.0
* Major [ **BREAKING CHANGE** ] - Updated declared dependencies to React 18 and Wordpress 6.6
* Patch - Update import of OPTIONS_STORE_NAME to optionsStore
* Patch - Update orders store import to use ordersStore from @woocommerce/data
* Patch - Update wireit to 0.14.10
* Minor - Upgraded Typescript in the monorepo to 5.7.2
* Minor - Split JS into multiple chunks to avoid loading on every admin page.

2024-11-26 - version 2.5.1
* Patch - Fix wc plugin file path
* Patch - Add coming soon newsletter feature flag
* Patch - Update WC Admin Test Helper's Reset Onboarding Wizard tool
* Patch - Monorepo: bump and patch wp-env to reduce amount of crashes in CI.
* Patch - Stabilize JS dependency updates

2024-10-21 - version 2.5.0
* Patch - Flush cache after deleting option and resetting PHP rate limit
* Minor - Add a tool to simulate server problems with woocommerce.com
* Minor - Add fake WooPayments completion tool
... (124 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/composer.json">
{
	"name": "woocommerce/woocommerce-beta-tester",
	"description": "Run the beta versions of WooCommerce.",
	"homepage": "https://woocommerce.com/",
	"type": "wordpress-plugin",
	"license": "GPL-2.0-or-later",
	"prefer-stable": true,
	"minimum-stability": "dev",
	"version": "3.0.0",
	"require": {
		"composer/installers": "~1.7"
	},
	"require-dev": {
		"woocommerce/woocommerce-sniffs": "^1.0.0",
		"automattic/jetpack-changelogger": "3.3.0"
	},
	"scripts": {
		"phpcs": [
			"phpcs -s -p"
		],
		"phpcs-pre-commit": [
			"phpcs -s -p -n"
		],
		"phpcbf": [
			"phpcbf -p"
		]
	},
	"extra": {
		"scripts-description": {
			"phpcs": "Analyze code against the WordPress coding standards with PHP_CodeSniffer",
... (30 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/eslint.config.mjs">
/**
 * External dependencies
 */
⋮----
/**
 * Internal dependencies
 */
⋮----
// node_modules is ignored by default.
</file>

<file path="plugins/woocommerce-beta-tester/EXTENDING-WC-ADMIN-HELPER.md">
# Extending WC Admin helper

There are two client-side filters available if you want to extend the test
helper with your own plugin's test setup code.

This example adds a new tab:

```jsx
import { addFilter } from '@wordpress/hooks';

const SuperSekret = () => (
	<>
		<h2>Super sekret</h2>
		<p>This section contains super sekret tools.</p>
		<NewTool/>
	</>
);
addFilter(
	'woocommerce_admin_test_helper_tabs',
	'watch',
	( tabs ) => [
		...tabs,
		{
			name: 'super-sekret',
			title: 'Super sekret',
			content: <SuperSekret/>,
		}
	]
);
```
... (62 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/NEXT_CHANGELOG.md">
# Changelog

---

[See changelogs for previous versions](https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/plugins/woocommerce-beta-tester/readme.txt).
</file>

<file path="plugins/woocommerce-beta-tester/package.json">
{
	"private": true,
	"name": "@woocommerce/plugin-woocommerce-beta-tester",
	"description": "Setting up the local beta tester scripts.",
	"license": "GPL-2.0-or-later",
	"repository": {
		"type": "git",
		"url": "git://github.com/woocommerce/woocommerce-beta-tester.git"
	},
	"title": "WooCommerce Beta Tester",
	"version": "3.0.0",
	"homepage": "http://github.com/woocommerce/woocommerce-beta-tester",
	"devDependencies": {
		"@types/react": "18.3.x",
		"@types/react-dom": "18.3.x",
		"@types/wordpress__block-editor": "catalog:wp-min",
		"@woocommerce/dependency-extraction-webpack-plugin": "workspace:*",
		"@woocommerce/eslint-config": "workspace:*",
		"@woocommerce/eslint-plugin": "workspace:*",
		"@wordpress/env": "11.9.0",
		"@wordpress/prettier-config": "4.49.0",
		"@wordpress/scripts": "^32.6.0",
		"eslint": "^10.0.0",
		"globals": "^16.5.0",
		"prettier": "npm:wp-prettier@3.0.3",
		"react": "18.3.x",
		"react-dom": "18.3.x",
		"ts-loader": "9.5.x",
		"typescript": "5.7.x",
		"uglify-js": "^3.17.4"
... (109 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/phpcs.xml">
<?xml version="1.0"?>
<ruleset name="WooCommerce Beta Tester Coding Standards">
	<description>WooCommerce Beta Tester PHP_CodeSniffer ruleset.</description>
	<file>./woocommerce-beta-tester.php</file>
	<file>./includes/</file>
	<file>./api/</file>
	<arg value="ps" />
	<arg name="basepath" value="./" />
	<arg name="parallel" value="8" />
	<config name="minimum_supported_wp_version" value="5.2" />
	<config name="testVersion" value="7.4-" />
	<rule ref="WooCommerce-Core" />
	<rule ref="WordPress.WP.I18n">
		<properties>
			<property name="text_domain" type="array" value="woocommerce-beta-tester" />
		</properties>
	</rule>
	<rule ref="WooCommerce.Commenting.CommentHooks.MissingHookComment">
		<exclude-pattern>includes/</exclude-pattern>
		<exclude-pattern>api/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FileComment.Missing">
		<exclude-pattern>includes/</exclude-pattern>
		<exclude-pattern>api/</exclude-pattern>
	</rule>
</ruleset>
</file>

<file path="plugins/woocommerce-beta-tester/plugin.php">
function enqueue_beta_tester_app_script() {
</file>

<file path="plugins/woocommerce-beta-tester/README.md">
# WooCommerce Beta Tester

A plugin that makes it easy to test out pre-releases such as betas release candidates and even final releases. It also comes with WooCommerce Admin Test Helper that helps test WooCommerce Admin functionalities.

## Installation

You can either install the latest version from [woocommerce.com](https://woocommerce.com/products/woocommerce-beta-tester/) or symlink this directory by running `ln -s ./ :path-to-your-wp-plugin-directory/woocommerce-beta-tester`

## Development

To get started, run the following commands:

```text
pnpm --filter=@woocommerce/plugin-woocommerce-beta-tester install
pnpm --filter=@woocommerce/plugin-woocommerce-beta-tester start
```

See [wp-scripts](https://github.com/WordPress/gutenberg/tree/trunk/packages/scripts) for more usage information.

## Usage

You can get to the settings and features from your top admin bar under the name WC Beta Tester.

For more information, see [Extending WooCommerce Admin Test Helper](./EXTENDING-WC-ADMIN-HELPER.md).

Run `./bin/build-zip.sh` to make a zip file.

## License

Like WooCommerce itself, the WooCommerce Beta Tester plugin is open-source software licensed under the GPL v2 (or later). See [license](../../license.txt).
... (1 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/tsconfig.json">
{
	"compilerOptions": {
		// Target latest version of ECMAScript.
		"target": "esnext",

		// Make sure we're not pulling types from external projects.
		"typeRoots": [ "./typings", "./node_modules/@types" ],

		// Search under node_modules for non-relative imports.
		"moduleResolution": "node",

		"jsx": "react-jsx",

		// Temporary for resolving the test data json, remove when moving to using the API
		"resolveJsonModule": true,

		"jsxImportSource": "@emotion/react",

		// Enable strictest settings like strictNullChecks & noImplicitAny.
		"strict": true,

		// Import non-ES modules as default imports.
		"esModuleInterop": true,

		// Skip type checking of declaration files because some libraries define two copies of the same type in an inconsistent way
		"skipLibCheck": true,
		"module": "esnext"
	},
	"include": [ "typing/**/*", "src/**/*" ]
}
... (1 lines truncated)
</file>

<file path="plugins/woocommerce-beta-tester/webpack.config.js">

</file>

<file path="plugins/woocommerce-beta-tester/woocommerce-beta-tester.php">
WP_CLI::add_command( 'wc-beta-tester', WC_Beta_Tester_CLI::class );
⋮----
function _wc_beta_tester_load_textdomain() {
⋮----
function _wc_beta_tester_bootstrap() {
⋮----
function add_extension_register_script() {
⋮----
if ( class_exists( '\Automattic\WooCommerce\Admin\PageController' ) && \Automattic\WooCommerce\Admin\PageController::is_admin_page() ) {
⋮----
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true );
⋮----
function simulate_woocommerce_error() {
⋮----
WC()->template_path();
</file>

<file path="tools/changelogger/class-formatter.php">
namespace Automattic\WooCommerce\MonorepoTools\Changelogger;
⋮----
use Automattic\Jetpack\Changelog\Changelog;
use Automattic\Jetpack\Changelog\KeepAChangelogParser;
use Automattic\Jetpack\Changelogger\PluginTrait;
⋮----
class Formatter extends KeepAChangelogParser {
⋮----
public $bullet = '-   ';
⋮----
public $prologue = "# Changelog \n\n";
⋮----
public $epilogue = '';
⋮----
/**
	 * Entry pattern regex.
	 *
	 * @var string
	 */
public $entry_pattern = '/^
⋮----
public $heading_pattern = '/^## \[+(\[?[^] ]+\]?)\]\(.+\) - (.+?)\n/s';
⋮----
public function getEpilogue() {
⋮----
public function getReleaseLink( string $version ): string {
⋮----
public function parse( $changelog ) {
⋮----
// Parse the heading and create a ChangelogEntry for it.
... (68 lines truncated)
</file>

<file path="tools/changelogger/class-legacy-core-formatter.php">
namespace Automattic\WooCommerce\MonorepoTools\Changelogger;
⋮----
use Automattic\Jetpack\Changelog\Changelog;
use Automattic\Jetpack\Changelogger\FormatterPlugin;
⋮----
class Legacy_Core_Formatter extends Formatter implements FormatterPlugin {
⋮----
public $bullet = '* ';
⋮----
public $entry_pattern = '/^##?#\s+([^\n=]+)\s+((?:(?!^##).)+)/ms';
⋮----
private function getSubheadingTypeMapping() {
⋮----
public function format( Changelog $changelog ) {
⋮----
$subheading_map = $this->getSubheadingTypeMapping();
⋮----
foreach ( $changelog->getEntries() as $entry ) {
$version = $entry->getVersion();
⋮----
foreach ( $entry->getChangesBySubheading() as $heading => $changes ) {
⋮----
$text = trim( $change->getContent() );
</file>

<file path="tools/changelogger/class-package-formatter.php">
namespace Automattic\WooCommerce\MonorepoTools\Changelogger;
⋮----
use Automattic\Jetpack\Changelogger\FormatterPlugin;
⋮----
class Package_Formatter extends Formatter implements FormatterPlugin {
⋮----
public $prologue = "# Changelog \n\nThis project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).";
⋮----
public function getEpilogue() {
⋮----
public function getReleaseLink( string $version ): string {
⋮----
throw new \InvalidArgumentException( 'Invalid directory.' );
</file>

<file path="tools/changelogger/class-php-package-formatter.php">
namespace Automattic\WooCommerce\MonorepoTools\Changelogger;
⋮----
use Automattic\Jetpack\Changelogger\FormatterPlugin;
⋮----
class Php_Package_Formatter extends Formatter implements FormatterPlugin {
⋮----
public $prologue = "# Changelog \n\nThis project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).";
⋮----
public function getReleaseLink( string $version ): string {
⋮----
throw new \InvalidArgumentException( "Can't find package name in composer.json." );
</file>

<file path="tools/changelogger/class-plugin-formatter.php">
namespace Automattic\WooCommerce\MonorepoTools\Changelogger;
⋮----
use Automattic\Jetpack\Changelogger\FormatterPlugin;
⋮----
class Plugin_Formatter extends Formatter implements FormatterPlugin {
⋮----
public $epilogue = "---\n\n[See changelogs for previous versions](https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/changelog.txt).";
⋮----
public $entry_pattern = '/^##?#\s+([^\n=]+)\s+((?:(?!^##).)+)/ms';
</file>

<file path="tools/code-analyzer/src/commands/analyzer/analyzer-lint.ts">
import { Command, Option } from '@commander-js/extra-typings';
import { Logger } from '@woocommerce/monorepo-utils/src/core/logger';
import { join } from 'path';
⋮----
import { scanForChanges } from '../../lib/scan-changes';
import {
	printDatabaseUpdates,
	printHookResults,
	printTemplateResults,
} from '../../print';
</file>

<file path="tools/code-analyzer/src/commands/analyzer/analyzer-major-minor.ts">
import { join } from 'path';
import { readFile } from 'fs/promises';
import simpleGit from 'simple-git';
import { cloneRepo } from '@woocommerce/monorepo-utils/src/core/git';
import { Logger } from '@woocommerce/monorepo-utils/src/core/logger';
import { Command } from '@commander-js/extra-typings';
⋮----
const getPluginData = async (
	tmpRepoPath: string,
	pathToMainFile: string,
	hashOrBranch: string
): Promise< string | void > =>
</file>

<file path="tools/code-analyzer/src/commands/analyzer/analyzer-scan.ts">
import { Command } from '@commander-js/extra-typings';
import { Logger } from '@woocommerce/monorepo-utils/src/core/logger';
import { join } from 'path';
⋮----
import {
	scanChangesForDB,
	scanChangesForHooks,
	scanChangesForTemplates,
	ScanType,
} from '../../lib/scan-changes';
import {
	printDatabaseUpdates,
	printHookResults,
	printTemplateResults,
} from '../../print';
⋮----
const printEmptyNotice = ( scanType: ScanType ) =>
</file>

<file path="tools/code-analyzer/src/commands/analyzer/index.ts">
import { program } from '@commander-js/extra-typings';
import dotenv from 'dotenv';
</file>

<file path="tools/code-analyzer/src/print.ts">
import { setOutput } from '@actions/core';
⋮----
import { HookChangeDescription } from './lib/hook-changes';
import { TemplateChangeDescription } from './lib/template-changes';
⋮----
export const printTemplateResults = (
	data: TemplateChangeDescription[],
	output: string,
	title: string,
	log: ( s: string ) => void
): void =>
⋮----
export const printHookResults = (
	data: HookChangeDescription[],
	output: string,
	sectionTitle: string,
	log: ( s: string ) => void
) =>
⋮----
export const printDatabaseUpdates = (
	{
		updateFunctionName,
		updateFunctionVersion,
	}: { updateFunctionName: string; updateFunctionVersion: string },
	output: string,
	log: ( s: string ) => void
): void =>
</file>

<file path="tools/code-analyzer/src/utils.ts">
import { exec } from 'child_process';
import { promisify } from 'util';
⋮----
export const getVersionRegex = ( rawVersion: string ): string =>
⋮----
export const getHookName = ( name: string ): string =>
⋮----
/**
 * Extract hook description from a raw diff.
 *
 * @param {string} diff raw diff.
 * @param {string} name hook name.
 * @return {string|false} hook description or false if none exists.
 */
⋮----
export const getHookChangeType = ( diff: string ) =>
</file>

<file path="tools/code-analyzer/eslint.config.mjs">
/**
 * External dependencies
 */
⋮----
/**
 * Internal dependencies
 */
</file>

<file path="tools/code-analyzer/index.ts">

</file>

<file path="tools/code-analyzer/jest.config.js">

</file>

<file path="tools/code-analyzer/package.json">
{
	"name": "code-analyzer",
	"version": "1.0.0",
	"description": "A tool to analyze code changes in WooCommerce Monorepo.",
	"author": "Automattic",
	"homepage": "https://github.com/woocommerce/woocommerce",
	"license": "GPL-2.0-or-later",
	"repository": "woocommerce/woocommerce",
	"private": true,
	"types": "dist/index.d.ts",
	"scripts": {
		"analyzer": "node -r ts-node/register ./src/commands/analyzer/index.ts",
		"lint": "eslint .",
		"test": "pnpm test:js",
		"test:js": "jest"
	},
	"dependencies": {
		"@actions/core": "^2.0.3",
		"@commander-js/extra-typings": "^10.0.3",
		"@oclif/core": "^2.15.0",
		"@tsconfig/node16": "^1.0.4",
		"@woocommerce/monorepo-utils": "workspace:*",
		"commander": "^9.5.0",
		"dotenv": "^10.0.0",
		"simple-git": "^3.21.0"
	},
	"devDependencies": {
		"@types/jest": "29.5.x",
		"@types/node": "^24.1.0",
		"@woocommerce/eslint-config": "workspace:*",
... (36 lines truncated)
</file>

<file path="tools/code-analyzer/README.md">
# Code Analyzer

## Description

`code-analyzer` is a CLI tool designed to analyze change information about plugins in the WooCommerce monorepo.

## Commands

Currently there are 3 commands:

1. `lint`. Analyzer is used as a linter for PRs to check if hook/template/db changes were introduced. It produces output either directly on CI or via setting output variables in GH actions.

Here is an example `analyzer` command, run from this directory:

`pnpm analyzer lint "release/6.8" "6.8.0" -b release/6.7`

In this command we compare the `release/6.7` and `release/6.8` branches to find differences, and we're looking for changes introduced since `6.8.0` (using the `@since` tag).

To find out more about the other arguments to the command you can run `pnpm analyzer -- --help`

2. `major-minor`. This simple CLI tool gives you the latest `.0` major/minor released version of a plugin's mainfile based on Woo release conventions.

Here is an example `major-minor` command, run from this directory:

`pnpm analyzer major-minor "release/6.8" "plugins/woocommerce/woocommerce.php"`

In this command we checkout the branch `release/6.8` and check the version of the woocommerce.php mainfile located at the path passed. Note that at the time of
writing the main file in this particular branch reports `6.8.1` so the output of this command is `6.8.0`.

This command is particularly useful combined with the analyzer, allowing you to determine the last major/minor.0 version of a branch or ref before passing that as the
... (10 lines truncated)
</file>

<file path="tools/code-analyzer/tsconfig.json">
{
	"extends": "./node_modules/@tsconfig/node16/tsconfig.json",
	"compilerOptions": {
		"module": "Node16",
		"moduleResolution": "Node16",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		]
	},
	"ts-node": {
		"transpileOnly": true,
		"files": true,
	},
	"include": [
		"index.ts",
		"src/**/*"
	]
}
</file>

<file path="tools/compare-perf/calculate-delta.ts">
function calculateDelta( testSuites: string[], branches: string[] ): void
</file>

<file path="tools/compare-perf/config.js">
const getPnpmPackage = ( sourceDir ) =>
⋮----
getSetupTestRunner: ( sourceDir ) =>
getSetupCommand: ( sourceDir ) =>
getTestCommand: ( sourceDir ) =>
</file>

<file path="tools/compare-perf/index.js">
const catchException = ( command ) =>
</file>

<file path="tools/compare-perf/log-to-codevitals.js">

</file>

<file path="tools/compare-perf/metric-utils.js">
function median( array )
⋮----
function getMetricUnit( metric )
⋮----
function formatMetricValue( metric, value )
</file>

<file path="tools/compare-perf/package.json">
{
	"name": "compare-perf",
	"version": "0.0.1",
	"description": "A tool to compare performance across two branches in WooCommerce Monorepo.",
	"author": "Automattic",
	"homepage": "https://github.com/woocommerce/woocommerce",
	"license": "GPL-2.0-or-later",
	"repository": "woocommerce/woocommerce",
	"scripts": {
		"compare": "node -r ts-node/register index.js",
		"log": "node log-to-codevitals.js"
	},
	"dependencies": {
		"@types/node": "^24.1.0",
		"@tsconfig/node16": "^1.0.4",
		"@wordpress/env": "11.9.0",
		"commander": "9.5.0",
		"chalk": "^4.1.2",
		"inquirer": "^7.1.0",
		"simple-git": "^3.21.0",
		"ts-node": "^10.9.2",
		"tslib": "^2.6.2"
	},
	"engines": {
		"node": "^24.15.0"
	}
}
</file>

<file path="tools/compare-perf/performance.js">
function withNodeVersion( command )
⋮----
async function runTestSuite( testSuite, testRunnerDir, runKey )
⋮----
async function runPerformanceTests( branches, options )
</file>

<file path="tools/compare-perf/process-reports.ts">
async function processPerformanceReports(
	testSuites: string[],
	branches: string[]
): Promise< void >
</file>

<file path="tools/compare-perf/tsconfig.json">
{
	"extends": "./node_modules/@tsconfig/node16/tsconfig.json",
	"compilerOptions": {
		"module": "Node16",
		"moduleResolution": "Node16",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		]
	},
	"ts-node": {
		"transpileOnly": true,
		"files": true,
	},
}
</file>

<file path="tools/compare-perf/utils.js">
function runShellScript( script, cwd, env =
⋮----
function readJSONFile( fileName )
⋮----
async function askForConfirmation(
	message,
	isDefault = true,
	abortMessage = 'Aborting.'
)
⋮----
function getFilesFromDir( dir )
⋮----
function logAtIndent( indent, msg, ...args )
⋮----
/**
 * Sanitizes branch name to be used in a path or a filename.
 *
 * @param {string} branch
 *
 * @return {string} Sanitized branch name.
 */
function sanitizeBranchName( branch )
</file>

<file path="tools/eslint-config/core-modules.js">

</file>

<file path="tools/eslint-config/index.js">

</file>

<file path="tools/eslint-config/package.json">
{
	"name": "@woocommerce/eslint-config",
	"version": "0.0.1",
	"description": "The WooCommerce monorepo's internal ESLint Flat Config layer.",
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"private": true,
	"engines": {
		"node": "^24.15.0"
	},
	"main": "index.js",
	"files": [
		"index.js",
		"core-modules.js"
	],
	"scripts": {
		"lint": "pnpm --if-present '/^lint:lang:.*$/'",
		"lint:fix": "pnpm --if-present '/^lint:fix:lang:.*$/'",
		"lint:lang:js": "eslint ./index.js ./core-modules.js",
		"lint:fix:lang:js": "eslint ./index.js ./core-modules.js --fix"
	},
	"dependencies": {
		"@woocommerce/eslint-plugin": "workspace:*"
	},
	"devDependencies": {
		"eslint": "^10.0.0"
	},
	"config": {
		"ci": {
			"lint": {
... (10 lines truncated)
</file>

<file path="tools/eslint-config/README.md">
# `@woocommerce/eslint-config`

The WooCommerce monorepo's internal ESLint Flat Config layer. This package is private and is never published: it exists so that monorepo-only lint decisions have somewhere to live that is not the public plugin.

## Why this package exists

WooCommerce's lint setup is split across two layers, and the split is the whole point of this package.

| | [`@woocommerce/eslint-plugin`](../../packages/js/eslint-plugin/README.md) | `@woocommerce/eslint-config` |
| --- | --- | --- |
| Published to npm | Yes | No (`private: true`) |
| Consumed by | Third-party extensions, and this package | Packages inside this monorepo only |
| Holds | The portable WooCommerce ruleset | Monorepo-only relaxations and strictness |

The public plugin is consumed by extension authors we cannot see or coordinate with, so it stays **portable**: it assumes no type information and no covering `tsconfig.json`, and its rule severities are deliberate upstream policy for every consumer. Anything that only makes sense inside this repository belongs here instead.

The practical consequence: **when this monorepo needs a rule's severity changed, change it here, not in the plugin.** A relaxation added upstream silently weakens linting for every extension author who installs the published package; the same relaxation here affects only this repository.

## Usage

Each package in the monorepo has its own `eslint.config.mjs` that spreads this config:

```js
/**
 * Internal dependencies
 */
import woocommerce from '@woocommerce/eslint-config';

export default [ ...woocommerce ];
```
... (55 lines truncated)
</file>

<file path="tools/executors/changelogger/executor.json">
{
	"executors": {
		"changelog": {
			"implementation": "./impl",
			"schema": "./schema.json",
			"description": "Executes Jetpack Changelogger scripts."
		}
	}
}
</file>

<file path="tools/executors/changelogger/impl.js">
function adopt(value)
⋮----
function fulfilled(value)
function rejected(value)
function step(result)
⋮----
function verb(n)
function step(op)
⋮----
function runChangelogger(_a)
function changelogExecutor(options, context)
</file>

<file path="tools/executors/changelogger/impl.ts">
import { ExecutorContext } from '@nrwl/devkit';
import { spawn } from 'child_process';
import { join } from 'path';
import { existsSync } from 'fs';
⋮----
export interface ChangelogExecutorOptions {
	action: string;
	cwd: string;
}
⋮----
async function runChangelogger( {
	action,
	cwd,
	...extraArgs
}: ChangelogExecutorOptions ): Promise<
⋮----
export default async function changelogExecutor(
	options: ChangelogExecutorOptions,
	context: ExecutorContext
)
</file>

<file path="tools/executors/changelogger/package.json">
{
	"executors": "./executor.json"
}
</file>

<file path="tools/executors/changelogger/schema.json">
{
	"cli": "nx",
	"id": "Changelogger",
	"description": "Executes Jetpack Changelogger scripts.",
	"type": "object",
	"properties": {
		"action": {
			"type": "string",
			"description": "Action to take"
		}
	},
	"required": [ "action" ]
}
</file>

<file path="tools/monorepo/check-changelogger-use.php">
function usage() {
⋮----
function debug( ...$args ) {
⋮----
function debug() {
</file>

<file path="tools/monorepo-merge/codemods/rename-intl-domain.js">
const isFunctionNamed = ( path, names ) =>
⋮----
export default function transformer( file, api )
</file>

<file path="tools/monorepo-merge/src/commands/merge/index.ts">
import { Args, Command, Flags, ux } from '@oclif/core';
import { execFile } from 'child_process';
import { rm } from 'fs/promises';
import { isAbsolute, join, relative, resolve, sep } from 'path';
import { tmpdir } from 'os';
import { promisify } from 'util';
⋮----
import { MONOREPO_ROOT } from '../../const';
import { access, exec } from '../../node-async';
⋮----
export default class Merge extends Command
⋮----
async run(): Promise< void >
⋮----
private async checkDependencies(): Promise< void >
⋮----
private async validateArgs(
		source: string,
		destination: string
): Promise< void >
⋮----
private static createMessageCallback( source: string ): string
⋮----
private async cloneRepository( source: string ): Promise< string >
⋮----
private async alterRepositoryHistory(
		source: string,
		cloneDir: string,
		destination: string
): Promise< void >
... (7 lines truncated)
</file>

<file path="tools/monorepo-merge/src/commands/transfer-issues/index.ts">
import { Args, Command, Flags, ux } from '@oclif/core';
import { graphql, GraphqlResponseError } from '@octokit/graphql';
import { RequestError } from '@octokit/request-error';
⋮----
interface GitHubLabel {
	id: string;
	name: string;
}
⋮----
interface GitHubProjectField {
	projectId: string;
	fieldId: string;
	fieldName: string;
	itemId: string;
	dataType: string;
	value: {
		text?: string;
		number?: number;
		date?: string;
		singleSelectOptionId?: string;
		iterationId?: string;
	};
}
⋮----
interface GitHubIssue {
	id: string;
	newID?: string;
	title: string;
	projectFields: GitHubProjectField[];
}
... (49 lines truncated)
</file>

<file path="tools/monorepo-merge/src/const.ts">
import { dirname } from 'path';
</file>

<file path="tools/monorepo-merge/src/index.ts">

</file>

<file path="tools/monorepo-merge/src/node-async.ts">
import { access as nodeAccess, PathLike } from 'fs';
import { exec as nodeExec, ExecOptions } from 'child_process';
⋮----
export async function access( path: PathLike, mode?: number ): Promise< void >
⋮----
export async function exec(
	command: string,
	options?: ExecOptions
): Promise< string | Buffer >
</file>

<file path="tools/monorepo-merge/eslint.config.mjs">
/**
 * External dependencies
 */
⋮----
/**
 * Internal dependencies
 */
</file>

<file path="tools/monorepo-merge/package.json">
{
	"name": "monorepo-merge",
	"version": "0.0.0",
	"description": "A tool for merging repositories into the WooCommerce Monorepo.",
	"author": "Automattic",
	"bin": {
		"monorepo-merge": "./bin/run"
	},
	"homepage": "https://github.com/woocommerce/woocommerce",
	"license": "GPL-2.0-or-later",
	"main": "dist/index.js",
	"repository": "woocommerce/woocommerce",
	"files": [
		"/bin",
		"/dist",
		"/npm-shrinkwrap.json",
		"/oclif.manifest.json"
	],
	"scripts": {
		"build": "shx rm -rf dist && tsc --project tsconfig.json",
		"lint": "eslint .",
		"prepack": "pnpm build && oclif manifest",
		"postpack": "shx rm -f oclif.manifest.json",
		"posttest": "pnpm lint",
		"test": "pnpm build && node --test test/merge.test.mjs"
	},
	"dependencies": {
		"@inquirer/confirm": "^6.1.1",
		"@inquirer/password": "^5.1.1",
		"@oclif/core": "^4.13.5",
... (65 lines truncated)
</file>

<file path="tools/monorepo-merge/tsconfig.json">
{
	"compilerOptions": {
		"declaration": true,
		"importHelpers": true,
		"target": "esnext",
		"module": "nodenext",
		"moduleResolution": "nodenext",
		"outDir": "dist",
		"rootDir": "src",
		"strict": true,
		"typeRoots": [
			"./node_modules/@types"
		],
		"skipLibCheck": true
	},
	"ts-node": {
		"esm": false
	},
	"include": [
		"src/**/*"
	]
}
</file>

<file path="tools/monorepo-utils/fonts/Standard.flf">
flf2a$ 6 5 16 15 13 0 24463 229
Standard by Glenn Chappell & Ian Chai 3/93 -- based on Frank's .sig
Includes ISO Latin-1
figlet release 2.1 -- 12 Aug 1994
Modified for figlet 2.2 by John Cowan <cowan@ccil.org>
  to add Latin-{2,3,4,5} support (Unicode U+0100-017F).
Permission is hereby given to modify this font, as long as the
modifier's name is placed on a comment line.

Modified by Paul Burton <solution@earthlink.net> 12/96 to include new parameter
supported by FIGlet and FIGWin.  May also be slightly modified for better use
of new full-width/kern/smush alternatives, but default output is NOT changed.

Font modified May 20, 2012 by patorjk to add the 0xCA0 character
 $@
 $@
 $@
 $@
 $@
 $@@
  _ @
 | |@
 | |@
 |_|@
 (_)@
    @@
  _ _ @
 ( | )@
  V V @
   $  @
... (2207 lines truncated)
</file>

<file path="tools/monorepo-utils/src/changefile/index.ts">
import { Command } from '@commander-js/extra-typings';
import simpleGit from 'simple-git';
import nodePath from 'path';
import { existsSync, readFileSync, rmSync, writeFileSync } from 'fs';
⋮----
import { Logger } from '../core/logger';
import { cloneAuthenticatedRepo, checkoutRemoteBranch } from '../core/git';
import {
	getPullRequestData,
	shouldAutomateChangelog,
	shouldAutomateNoChangelog,
	getChangelogDetails,
	getChangelogDetailsError,
} from './lib/github';
import {
	getAllProjectPaths,
	getTouchedProjectsRequiringChangelog,
} from './lib/projects';
</file>

<file path="tools/monorepo-utils/src/changefile/README.md">
# Changelog CLI Utility

CLI for creating changelog entries from pull request details. 

Usage: `pnpm utils changefile <pr-number>`
</file>

<file path="tools/monorepo-utils/src/ci-jobs/index.ts">
import { Command } from '@commander-js/extra-typings';
import { setOutput } from '@actions/core';
import { writeFileSync } from 'fs';
⋮----
import { Logger } from '../core/logger';
import { buildProjectGraph } from './lib/project-graph';
import { getFileChanges } from './lib/file-changes';
import { createJobsForChanges } from './lib/job-processing';
import { isGithubCI } from '../core/environment';
⋮----
// Logger.notice( `-  ${ job.name }` );
</file>

<file path="tools/monorepo-utils/src/ci-jobs/README.md">
# CI Job Command

A CLI command for generating the jobs needed by the `ci.yml` file.

A CLI command for parsing CI workflow configuration from `package.json` files.

Usage: `pnpm utils ci-jobs` (Considers all projects changed and returns all jobs)
Usage: `pnpm utils ci-jobs --base-ref <base-ref>` (Checks for changes between HEAD and `base-ref`)

## Ignoring files

A project can declare an `ignore` list in its `config.ci`, and any job can declare its
own next to its `changes`. Both take a glob or an array of globs, in the same syntax as
`changes`. Jobs inherit the project-level list unless they declare their own, which
**replaces** the default — so `"ignore": []` opts a job out of the project policy
entirely:

```json
{
    "config": {
        "ci": {
            "ignore": [ "{,**/}*.md", "{,**/}readme.txt" ],
            "lint": {
                "command": "lint",
                "changes": [ "**/*.php" ]
            },
            "tests": [
                {
                    "name": "docs tests",
                    "command": "test:docs",
... (30 lines truncated)
</file>

<file path="tools/monorepo-utils/src/code-freeze/commands/accelerated-prep/index.ts">
import { Command } from '@commander-js/extra-typings';
import simpleGit from 'simple-git';
⋮----
import { Logger } from '../../../core/logger';
import {
	sparseCheckoutRepoShallow,
	checkoutRemoteBranch,
} from '../../../core/git';
import { createPullRequest } from '../../../core/github/repo';
import { getEnvVar } from '../../../core/environment';
import { Options } from './types';
import { addHeader, createChangelog } from './lib/prep';
</file>

<file path="tools/monorepo-utils/src/code-freeze/commands/accelerated-prep/types.ts">
export type Options = {
	owner?: string;
	name?: string;
	base?: string;
	dryRun?: boolean;
	commitDirectToBase?: boolean;
};
</file>

<file path="tools/monorepo-utils/src/code-freeze/commands/branch/index.ts">
import { Command } from '@commander-js/extra-typings';
import { parse } from 'semver';
import { confirm } from 'promptly';
import chalk from 'chalk';
import ora from 'ora';
import { setOutput } from '@actions/core';
⋮----
import {
	getLatestGithubReleaseVersion,
	doesGithubBranchExist,
	getRefFromGithubBranch,
	createGithubBranch,
	deleteGithubBranch,
} from '../../../core/github/repo';
import { WPIncrement } from '../../../core/version';
import { Logger } from '../../../core/logger';
import { isGithubCI } from '../../../core/environment';
⋮----
const getNextReleaseBranch = async ( options: {
	owner?: string;
	name?: string;
} ) =>
</file>

<file path="tools/monorepo-utils/src/code-freeze/commands/changelog/index.ts">
import { Command } from '@commander-js/extra-typings';
import { execSync } from 'child_process';
⋮----
import { Logger } from '../../../core/logger';
import { cloneAuthenticatedRepo } from '../../../core/git';
import {
	updateTrunkChangelog,
	updateReleaseBranchChangelogs,
	updateIntermediateBranches,
} from './lib';
import { Options } from './types';
</file>

<file path="tools/monorepo-utils/src/code-freeze/commands/changelog/types.ts">
export type Options = {
	owner?: string;
	name?: string;
	version: string;
	branch?: string;
	devRepoPath?: string;
	commitDirectToBase?: boolean;
	override?: string;
	appendChangelog?: boolean;
	githubActor?: string;
};
</file>

<file path="tools/monorepo-utils/src/code-freeze/commands/get-version/index.ts">
import { Command } from '@commander-js/extra-typings';
import { DateTime } from 'luxon';
import { setOutput } from '@actions/core';
import chalk from 'chalk';
⋮----
import { Logger } from '../../../core/logger';
import { isGithubCI } from '../../../core/environment';
import {
	getToday,
	getMonthlyCycle,
	getAcceleratedCycle,
	getVersionsBetween,
} from './lib/index';
⋮----
const getRange = ( override, between ) =>
</file>

<file path="tools/monorepo-utils/src/code-freeze/commands/milestone/index.ts">
import { Command } from '@commander-js/extra-typings';
import ora from 'ora';
⋮----
import { getLatestGithubReleaseVersion } from '../../../core/github/repo';
import { octokitWithAuth } from '../../../core/github/api';
import { WPIncrement } from '../../../core/version';
import { Logger } from '../../../core/logger';
</file>

<file path="tools/monorepo-utils/src/code-freeze/commands/version-bump/bump.ts">
import { stripPrereleaseParameters } from './lib/validate';
import {
	updatePluginFile,
	updateReadmeChangelog,
	updateJSON,
	updateClassPluginFile,
} from './lib/update';
⋮----
export const bumpFiles = async ( tmpRepoPath, version ) =>
</file>

<file path="tools/monorepo-utils/src/code-freeze/commands/version-bump/index.ts">
import { Command } from '@commander-js/extra-typings';
import simpleGit from 'simple-git';
⋮----
import { Logger } from '../../../core/logger';
import {
	sparseCheckoutRepoShallow,
	checkoutRemoteBranch,
} from '../../../core/git';
import { createPullRequest } from '../../../core/github/repo';
import { getEnvVar } from '../../../core/environment';
import { getMajorMinor } from '../../../core/version';
import { bumpFiles } from './bump';
import { validateArgs, getIsAccelRelease } from './lib/validate';
import { Options } from './types';
</file>

<file path="tools/monorepo-utils/src/code-freeze/commands/version-bump/types.ts">
export type Options = {
	owner?: string;
	name?: string;
	base?: string;
	dryRun?: boolean;
	commitDirectToBase?: boolean;
	allowAccel?: boolean;
	force?: boolean;
};
</file>

<file path="tools/monorepo-utils/src/code-freeze/commands/index.ts">
import { Command } from '@commander-js/extra-typings';
⋮----
import { getVersionCommand } from './get-version';
import { milestoneCommand } from './milestone';
import { branchCommand } from './branch';
import { versionBumpCommand } from './version-bump';
import { changelogCommand } from './changelog';
import { acceleratedPrepCommand } from './accelerated-prep';
</file>

<file path="tools/monorepo-utils/src/code-freeze/README.md">
# Code Freeze CLI Utility

CLI for performing Monorepo utilities relating to Code Freeze
</file>

<file path="tools/monorepo-utils/src/core/github/api.ts">
import { graphql as gql } from '@octokit/graphql';
import { Octokit } from 'octokit';
import { graphql } from '@octokit/graphql/dist-types/types';
⋮----
import { getEnvVar } from '../environment';
⋮----
export const graphqlWithAuth = (): graphql =>
⋮----
export const octokitWithAuth = (): Octokit =>
</file>

<file path="tools/monorepo-utils/src/core/github/repo.ts">
import { Repository } from '@octokit/graphql-schema';
import { Endpoints } from '@octokit/types';
⋮----
import { graphqlWithAuth, octokitWithAuth } from './api';
⋮----
export const getLatestGithubReleaseVersion = async ( options: {
	owner?: string;
	name?: string;
} ): Promise< string > =>
⋮----
export const getRepositoryLabel = async (
	options: {
		owner?: string;
		name?: string;
	},
	label: string
): Promise<
	Endpoints[ 'GET /repos/{owner}/{repo}/labels/{name}' ][ 'response' ][ 'data' ]
> => {
	const { owner, name } = options;
	try {
		const { data } = await octokitWithAuth().request(
			'GET /repos/{owner}/{repo}/labels/{label}',
			{
				owner,
				repo: name,
				label,
			}
		);
⋮----
... (94 lines truncated)
</file>

<file path="tools/monorepo-utils/src/core/github/types.ts">
import { Endpoints } from '@octokit/types';
⋮----
export type CreatePullRequestEndpointResponse =
	Endpoints[ 'POST /repos/{owner}/{repo}/pulls' ][ 'response' ];
⋮----
export type GetPullRequestEndpointResponse =
	Endpoints[ 'GET /repos/{owner}/{repo}/pulls/{pull_number}' ][ 'response' ];
</file>

<file path="tools/monorepo-utils/src/core/environment.ts">
import { Logger } from './logger';
⋮----
export const getEnvVar = ( varName: string, isRequired = false ) =>
⋮----
export const isGithubCI = () =>
</file>

<file path="tools/monorepo-utils/src/core/git.ts">
import { execSync } from 'child_process';
import { join } from 'path';
import { tmpdir } from 'os';
import { mkdirSync } from 'fs';
import { simpleGit, TaskOptions } from 'simple-git';
import { randomUUID as v4 } from 'crypto';
import { mkdir, rm } from 'fs/promises';
import { URL } from 'node:url';
⋮----
import { getEnvVar } from './environment';
⋮----
export const getFilename = ( str: string ): string =>
⋮----
export const getStartingLineNumber = ( str: string ): number =>
⋮----
export const getPatches = ( content: string, regex: RegExp ): string[] =>
⋮----
const isUrl = ( maybeURL: string ) =>
⋮----
export const cloneRepo = async (
	repoPath: string,
	options: TaskOptions = {}
) =>
⋮----
export const cloneRepoShallow = async ( repoPath: string ) =>
⋮----
export const getAuthenticatedRemote = ( options: {
	owner: string;
	name: string;
} ) =>
... (65 lines truncated)
</file>

<file path="tools/monorepo-utils/src/core/logger.ts">
import ora, { Ora } from 'ora';
import chalk from 'chalk';
import Table from 'cli-table';
⋮----
import { getEnvVar, isGithubCI } from './environment';
⋮----
export class Logger
⋮----
private static get loggingLevel()
⋮----
static error( err: unknown, failOnErr = true )
⋮----
static warn( message: string )
⋮----
static notice( message: string )
⋮----
static startTask( message: string, isSilentInCI = false )
⋮----
static table( head: Array< string >, rows: Array< string[] > )
⋮----
static endTask( isSilentInCI = false )
</file>

<file path="tools/monorepo-utils/src/core/util.ts">
import { promisify } from 'util';
import { exec } from 'child_process';
import { RequestOptions, request } from 'https';
import { IncomingMessage } from 'http';
⋮----
type HttpsResponse = {
	[ K in keyof IncomingMessage as IncomingMessage[ K ] extends Function
		? never
		: K ]: IncomingMessage[ K ];
} & {
	body: string;
};
⋮----
export const requestAsync = (
	options: string | RequestOptions | URL,
	data?: string | Uint8Array | Buffer
) =>
</file>

<file path="tools/monorepo-utils/src/core/version.ts">
import { parse, inc } from 'semver';
⋮----
export const WPIncrement = ( version: string ): string =>
⋮----
export const getMajorMinor = ( version: string ) =>
</file>

<file path="tools/monorepo-utils/src/core/wpenv.ts">
import { createServer, Server } from 'net';
import { join } from 'path';
⋮----
import { execAsync } from './util';
⋮----
export const isWPEnvPortTaken = () =>
⋮----
export const startWPEnv = async (
	tmpRepoPath: string,
	error: ( s: string ) => void
) =>
⋮----
/**
 * Stop wp-env.
 *
 * @param {string}   tmpRepoPath - path to the temporary repo to stop wp-env from.
 * @param {Function} error       - error print method.
 * @return {boolean} if stopping the container succeeded.
 */
export const stopWPEnv = async (
	tmpRepoPath: string,
	error: ( s: string ) => void
): Promise< boolean > =>
</file>

<file path="tools/monorepo-utils/src/github/commands/replace-labels/index.ts">
import { Command } from '@commander-js/extra-typings';
⋮----
import {
	getIssuesByLabel,
	updateIssue,
	getRepositoryLabel,
} from '../../../core/github/repo';
import { Logger } from '../../../core/logger';
</file>

<file path="tools/monorepo-utils/src/github/commands/index.ts">
import { Command } from '@commander-js/extra-typings';
⋮----
import { replaceLabelsCommand } from './replace-labels';
</file>

<file path="tools/monorepo-utils/src/github/README.md">
# Github CLI Utility

CLI for performing Monorepo utilities relating to Github issues.
</file>

<file path="tools/monorepo-utils/src/pull-requests/commands/add-changelog-file.ts">
import { Argument, Command } from '@commander-js/extra-typings';
import { exit } from 'process';
import { error } from 'console';
⋮----
import { graphqlWithAuth } from '../../core/github/api';
import { Logger } from '../../core/logger';
⋮----
const run = async (
	prNumberOrUrl: string,
	significance: string,
	type: string,
	changelogMessageWords: string[],
	options: {
		owner: string;
		name: string;
		createModifyCommit: true;
		dryRun: true;
	}
) =>
</file>

<file path="tools/monorepo-utils/src/pull-requests/commands/index.ts">
import { Command } from '@commander-js/extra-typings';
⋮----
import { addChangelogFileCommand } from './add-changelog-file';
</file>

<file path="tools/monorepo-utils/src/pull-requests/README.md">
# Pull Request Utilities

Utilities for tasks related to GitHub pull requests.

To see available commands run `pnpm utils pull-request --help` from the project root.
</file>

<file path="tools/monorepo-utils/src/slack/index.ts">
import { Command } from '@commander-js/extra-typings';
import { WebClient } from '@slack/web-api';
⋮----
import { getEnvVar } from '../core/environment';
import { resolveChannels, sendFile, sendMessage } from './slack-service';
⋮----
export async function postToSlack( text: string, options )
</file>

<file path="tools/monorepo-utils/src/slack/README.md">
# Slack Utilities

Utilities for automated posting to Slack.

**Note:** You must set the `SLACK_TOKEN` environment variable with your Slack authentication token, and `SLACK_CHANNELS` with a comma-separated list of channel IDs.

To see available commands run `pnpm utils slack --help` from the project root.

## Basic Usage

You can use the CLI to send messages or upload files to Slack channels:

### Send a message to Slack

```sh
pnpm utils slack "Hello from the CLI!"
```

This will send the message to all channels specified in the `SLACK_CHANNELS` environment variable.

#### Sending Multiline Messages

You can send multiline messages in several ways:

- **Using literal newlines in your shell:**

```sh
  pnpm utils slack "Hello from the CLI!
This is a second line.
And a third line."
... (36 lines truncated)
</file>

<file path="tools/monorepo-utils/src/slack/slack-service.ts">
import { setOutput } from '@actions/core';
import { WebClient, ErrorCode } from '@slack/web-api';
import { basename } from 'path';
import { existsSync } from 'fs';
⋮----
import { isGithubCI } from '../core/environment';
import { Logger } from '../core/logger';
⋮----
export function resolveChannels(): string[]
⋮----
export async function sendMessage(
	client: WebClient,
	text: string,
	channels: string[],
	replyTs: string
)
⋮----
export async function sendFile(
	client: WebClient,
	text: string,
	filePath: string,
	channels: string[],
	replyTs: string
)
</file>

<file path="tools/monorepo-utils/src/slack-test-report/index.ts">
import { Command } from '@commander-js/extra-typings';
import { WebClient } from '@slack/web-api';
⋮----
import { Logger } from '../core/logger';
import { getEnvVar } from '../core/environment';
import { createMessage, postMessage } from './lib/message';
import {
	getConfiguredChannels,
	loadConfig,
	parseConfig,
	resolveChannels,
} from './lib/config';
</file>

<file path="tools/monorepo-utils/src/slack-test-report/README.md">
# Slack Test Report

A utility tool to send test reports to Slack channels. This tool is particularly useful for notifying teams about test results, especially failures, directly in Slack.

## Usage

To see available commands run `pnpm utils slack-test-report --help` from the project root.

## Command Options

-    `-c, --conclusion <conclusion>` (Required): Test run conclusion. Expected one of: success, failure, skipped, cancelled
-    `-r, --report-name <reportName>`: The name of the report (e.g., "post-merge tests", "daily e2e tests")
-    `-u, --username <username>`: The Slack username (default: "Github reporter")
-    `-n, --pr-number <prNumber>`: The PR number to include in the message (for pull_request events)
-    `-t, --pr-title <prTitle>`: The PR title to include in the message (for pull_request events)
-    `-m, --commit-message <commitMessage>`: The commit message
-    `--config <configPath>`: Path to a JSON config file containing notification rules or settings

## Environment Variables

The following environment variables are required:

-    `SLACK_TOKEN`: Slack API token for sending messages
-    `DEFAULT_CHECKS_CHANNEL`: Default Slack channel ID for notifications
-    `GITHUB_SHA`: Git commit SHA
-    `GITHUB_ACTOR`: GitHub username of the person who triggered the action
-    `GITHUB_TRIGGERING_ACTOR`: GitHub username of the person who triggered the workflow
-    `GITHUB_EVENT_NAME`: Name of the GitHub event that triggered the workflow
-    `GITHUB_RUN_ID`: Unique identifier of the workflow run
-    `GITHUB_RUN_ATTEMPT`: Attempt number of the workflow run
... (75 lines truncated)
</file>

<file path="tools/monorepo-utils/src/workflow-profiler/commands/list/index.ts">
import { Command } from '@commander-js/extra-typings';
⋮----
import { getAllWorkflows } from '../../lib/data';
import { Logger } from '../../../core/logger';
</file>

<file path="tools/monorepo-utils/src/workflow-profiler/commands/profile/index.ts">
import { Command } from '@commander-js/extra-typings';
⋮----
import {
	getWorkflowRunData,
	getWorkflowData,
	getRunJobData,
} from '../../lib/data';
import {
	logWorkflowRunResults,
	logJobResults,
	logStepResults,
} from '../../lib/log';
import { Logger } from '../../../core/logger';
</file>

<file path="tools/monorepo-utils/src/workflow-profiler/commands/index.ts">
import { Command } from '@commander-js/extra-typings';
⋮----
import List from './list';
import Profile from './profile';
</file>

<file path="tools/monorepo-utils/src/workflow-profiler/config.ts">

</file>

<file path="tools/monorepo-utils/src/index.ts">
import { Command } from '@commander-js/extra-typings';
import figlet from 'figlet';
import chalk from 'chalk';
import dotenv from 'dotenv';
⋮----
import PullRequest from './pull-requests/commands';
import CodeFreeze from './code-freeze/commands';
import Github from './github/commands';
import Slack from './slack';
import Changefile from './changefile';
import CIJobs from './ci-jobs';
import WorkflowProfiler from './workflow-profiler/commands';
import SlackTestReport from './slack-test-report';
import { Logger } from './core/logger';
import { isGithubCI } from './core/environment';
⋮----
const run = async () =>
</file>

<file path="tools/monorepo-utils/eslint.config.mjs">
/**
 * External dependencies
 */
⋮----
/**
 * Internal dependencies
 */
</file>

<file path="tools/monorepo-utils/jest.config.js">

</file>

<file path="tools/monorepo-utils/package.json">
{
	"name": "@woocommerce/monorepo-utils",
	"version": "0.0.1",
	"description": "WooCommerce Monorepo utility tooling.",
	"author": "Automattic",
	"homepage": "https://github.com/woocommerce/woocommerce",
	"license": "GPL-2.0-or-later",
	"repository": "woocommerce/woocommerce",
	"private": true,
	"bin": {
		"monorepo-utils": "./bin/run"
	},
	"main": "dist/index.js",
	"files": [
		"bin",
		"dist",
		"fonts"
	],
	"scripts": {
		"build": "webpack --config webpack.config.js && replace '\r\n' '\n' fonts/Standard.flf",
		"lint": "eslint .",
		"start": "webpack --config webpack.config.js --watch",
		"test": "pnpm test:js",
		"test:js": "jest"
	},
	"dependencies": {
		"@actions/core": "^2.0.3",
		"@commander-js/extra-typings": "^10.0.3",
		"@octokit/graphql": "4.8.0",
		"@octokit/graphql-schema": "^14.45.1",
... (63 lines truncated)
</file>

<file path="tools/monorepo-utils/README.md">
# Monorepo Utils

## Description

A set of CLI tools and scripts for managing the WooCommerce monorepo.

## Usage

This command is built on postinstall and can be run from the root of the project.
To see a list of available commands you can run this from project root:

```
pnpm utils
```

## Development

During development you can watch for changes via `pnpm start` in this directory, this will
update the script referenced at the root package.json so you will see immediate changes as you
re-run the CLI.
</file>

<file path="tools/monorepo-utils/tsconfig.json">
{
	"compilerOptions": {
		"rootDir": "src",
		"outDir": "dist",
		"target": "esnext",
		"module": "commonjs",
		"esModuleInterop": true,
		"moduleResolution": "node",
		"skipLibCheck": true,
		"typeRoots": [ "./node_modules/@types", "./node_modules/@commander-js" ]
	}
}
</file>

<file path="tools/monorepo-utils/webpack.config.js">

</file>

<file path="tools/package-release/src/commands/prepare/index.ts">
import { Args, Command, Flags, ux } from '@oclif/core';
import { writeFileSync } from 'fs';
import { execSync } from 'child_process';
⋮----
import {
	getAllPackages,
	validatePackage,
	getFilepathFromPackageName,
	getPackageJson,
	getComposerJson,
	getPackageType,
} from '../../validate';
import {
	getNextVersion,
	validateChangelogEntries,
	writeChangelog,
	hasValidChangelogs,
} from '../../changelogger';
import { WOOCOMMERCE_PLUGIN_ROOT } from '../../const';
⋮----
export default class PackagePrepare extends Command
⋮----
async run(): Promise< void >
⋮----
private async preparePackages(
		packages: Array< string >,
		initialRelease?: boolean
)
⋮----
private bumpPackageVersion( name: string, version: string )
... (1 lines truncated)
</file>

<file path="tools/package-release/src/commands/publish/index.ts">
import { Args, Command, Flags, ux } from '@oclif/core';
import { execSync } from 'child_process';
⋮----
import {
	getAllPackages,
	validatePackage,
	getFilepathFromPackageName,
	isValidUpdate,
} from '../../validate';
import { MONOREPO_ROOT } from '../../const';
⋮----
export default class PackageRelease extends Command
⋮----
async run(): Promise< void >
⋮----
private publishPackages(
		packages: Array< string >,
		{
			'dry-run': dryRun,
			branch,
			'initial-release': initialRelease,
		}: { 'dry-run': boolean; branch: string; 'initial-release': boolean }
)
</file>

<file path="tools/package-release/src/changelogger.ts">
import { execSync } from 'child_process';
import { readdirSync, readFileSync } from 'fs';
import { join } from 'path';
⋮----
import { getFilepathFromPackageName } from './validate';
import { MONOREPO_ROOT } from './const';
⋮----
export const getNextVersion = ( name: string ) =>
⋮----
export const validateChangelogEntries = ( name: string ) =>
⋮----
export const writeChangelog = ( name: string, nextVersion?: string ) =>
⋮----
export const hasValidChangelogs = ( name: string ): boolean | void =>
</file>

<file path="tools/package-release/src/const.ts">
import { dirname, join } from 'path';
</file>

<file path="tools/package-release/src/index.ts">

</file>

<file path="tools/package-release/src/validate.ts">
import { existsSync, readFileSync } from 'fs';
import { execSync } from 'child_process';
import { gt as greaterVersionThan } from 'semver';
⋮----
import { MONOREPO_ROOT, excludedPackages } from './const';
⋮----
const getPackageData = ( name?: string ) =>
⋮----
export const getPackageType = ( name: string ) =>
⋮----
export const getFilepathFromPackageName = ( name: string ): string =>
⋮----
export const getPackageJson = ( name: string ) =>
⋮----
export const getComposerJson = ( name: string ) =>
⋮----
export const getAllPackages = (): Array< string > =>
⋮----
export const validatePackage = (
	name: string,
	error: ( s: string ) => void
) =>
⋮----
export const isValidUpdate = (
	name: string,
	initialRelease: boolean
): boolean =>
</file>

<file path="tools/package-release/eslint.config.mjs">
/**
 * External dependencies
 */
⋮----
/**
 * Internal dependencies
 */
</file>

<file path="tools/package-release/package.json">
{
	"name": "package-release",
	"version": "0.1.0",
	"description": "A tool to Monorepo JS packages.",
	"author": "Automattic",
	"bin": {
		"package-release": "./bin/run"
	},
	"homepage": "https://github.com/woocommerce/woocommerce",
	"license": "GPL-2.0-or-later",
	"main": "dist/index.js",
	"repository": "woocommerce/woocommerce",
	"files": [
		"/bin",
		"/dist",
		"/npm-shrinkwrap.json",
		"/oclif.manifest.json"
	],
	"scripts": {
		"build": "shx rm -rf dist && tsc --project tsconfig.json",
		"lint": "eslint .",
		"prepack": "pnpm build && oclif manifest",
		"postpack": "shx rm -f oclif.manifest.json",
		"posttest": "pnpm lint"
	},
	"dependencies": {
		"@oclif/core": "^4.13.5",
		"@oclif/plugin-help": "^6.2.58",
		"@oclif/plugin-plugins": "^5.4.87",
		"@types/semver": "^7.5.6",
... (42 lines truncated)
</file>

<file path="tools/package-release/README.md">
# Releasing Javascript packages

When a package contains sufficient changes to justify a release to [NPM](https://www.npmjs.com/), follow these instructions to create a new release from the monorepo.

Below are instructions for releasing using Github Workflows (recommended) and the command line. When releasing packages for the first time, release from the command line.

## Release packages using Github Workflows (recommended)

### Prepare packages

In order to prepare a package for release, a changelog will need to be compiled along with an appropriate version bump.

1. Visit the monorepo Action [Prepare Package Release workflow](https://github.com/woocommerce/woocommerce/actions/workflows/prepare-package-release.yml). Click the "Run workflow" button.

![image](https://user-images.githubusercontent.com/1922453/179434424-f08af974-5597-4c6f-955b-43faf062c7a7.png)

2. Select the branch you'd like to release from. Typically, this would be `trunk`. You can also choose which packages to prepare for release by supplying them as comma separated values in the input box. To loop through all packages, simply leave the `-a` flag. Packages that don't have any changes will be skipped and left as is.

![image](https://user-images.githubusercontent.com/1922453/179434508-8f44fcca-0f01-47f2-8b9e-f5ef5ff3a577.png)

3. Once the action has finished, check [open pull requests](https://github.com/woocommerce/woocommerce/pulls) for a pull request generated by Github Actions Bot. This pull request should include version bumps and changelog changes for applicable packages. Approve and merge the pull request once checks pass.

### Release Packages

1. Release the packages to NPM by kicking off another workflow. The [Packages Release workflow](https://github.com/woocommerce/woocommerce/actions/workflows/package-release.yml) has the same inputs as the prepare workflow. Be sure to release from the same branch and select the same packages to release.

![image](https://user-images.githubusercontent.com/1922453/179435048-ad2cd168-55b1-471a-b05f-3aed4a9e499b.png)

2. Confirm the package has been updated by visiting NPM. For example see https://www.npmjs.com/package/@woocommerce/components. Note: it may take several minutes after a release for the update to be reflected on NPM.

... (36 lines truncated)
</file>

<file path="tools/package-release/tsconfig.json">
{
	"compilerOptions": {
		"declaration": true,
		"importHelpers": true,
		"target": "esnext",
		"module": "commonjs",
		"outDir": "dist",
		"rootDir": "src",
		"strict": true,
		"typeRoots": [
			"./node_modules/@types"
		],
		"skipLibCheck": true
	},
	"include": [
		"src/**/*"
	]
}
</file>

<file path="tools/release-posts/commands/release-post/index.ts">
import { program } from '@commander-js/extra-typings';
import dotenv from 'dotenv';
</file>

<file path="tools/release-posts/commands/release-post/release-post-beta.ts">
import semver from 'semver';
import { writeFile } from 'fs/promises';
import { tmpdir } from 'os';
import { join } from 'path';
import { Logger } from '@woocommerce/monorepo-utils/src/core/logger';
import { getEnvVar } from '@woocommerce/monorepo-utils/src/core/environment';
import { Command } from '@commander-js/extra-typings';
import dotenv from 'dotenv';
⋮----
import { Select } from 'enquirer';
⋮----
import { renderTemplate } from '../../lib/render-template';
import { getWordpressComAuthToken } from '../../lib/oauth-helper';
import { getMostRecentFinal } from '../../lib/github-api';
import {
	getFirstTuesdayOfTheMonth,
	getSecondTuesdayOfTheMonth,
} from '../../lib/dates';
import {
	createWpComDraftPost,
	searchForPostsByCategory,
} from '../../lib/draft-post';
</file>

<file path="tools/release-posts/commands/release-post/release-post-contributors.ts">
import { Command } from '@commander-js/extra-typings';
import { Logger } from '@woocommerce/monorepo-utils/src/core/logger';
import { writeFile } from 'fs/promises';
import { tmpdir } from 'os';
import { join } from 'path';
⋮----
import { generateContributors } from '../../lib/contributors';
import { renderTemplate } from '../../lib/render-template';
</file>

<file path="tools/release-posts/commands/release-post/release-post-rc.ts">
import semver from 'semver';
import { writeFile } from 'fs/promises';
import { tmpdir } from 'os';
import { join } from 'path';
import { Logger } from '@woocommerce/monorepo-utils/src/core/logger';
import { getEnvVar } from '@woocommerce/monorepo-utils/src/core/environment';
import { Command } from '@commander-js/extra-typings';
import dotenv from 'dotenv';
⋮----
import { Select } from 'enquirer';
⋮----
import { renderTemplate } from '../../lib/render-template';
import { getWordpressComAuthToken } from '../../lib/oauth-helper';
import { getMostRecentBeta } from '../../lib/github-api';
import { getSecondTuesdayOfTheMonth } from '../../lib/dates';
import {
	createWpComDraftPost,
	searchForPostsByCategory,
} from '../../lib/draft-post';
</file>

<file path="tools/release-posts/commands/release-post/release-post-release.ts">
import { scanForChanges } from 'code-analyzer/src/lib/scan-changes';
import semver from 'semver';
import { writeFile } from 'fs/promises';
import { tmpdir } from 'os';
import { join } from 'path';
import {
	cloneRepo,
	getCommitHash,
} from '@woocommerce/monorepo-utils/src/core/git';
import { Logger } from '@woocommerce/monorepo-utils/src/core/logger';
import { getEnvVar } from '@woocommerce/monorepo-utils/src/core/environment';
import { Command } from '@commander-js/extra-typings';
import dotenv from 'dotenv';
⋮----
import { renderTemplate } from '../../lib/render-template';
import {
	createWpComDraftPost,
	fetchWpComPost,
	editWpComPostContent,
} from '../../lib/draft-post';
import { getWordpressComAuthToken } from '../../lib/oauth-helper';
import { generateContributors } from '../../lib/contributors';
import { editPostHTML } from '../../lib/edit-post';
</file>

<file path="tools/release-posts/templates/beta-release.ejs">
<!-- wp:paragraph -->
<p>
	Beta <%= betaNumber %> for the <%=
	finalReleaseDate.toLocaleDateString('en-US', {month: 'long', day:
	'numeric'}) %> release of WooCommerce is now available for testing! You can
	either
	<a
		href="https://downloads.wordpress.org/plugin/woocommerce.<%= version.version %>.zip"
		target="_blank"
		rel="noreferrer noopener"
		>download it directly from WordPress.org</a
	>
	or install our
	<a
		rel="noreferrer noopener"
		href="https://woocommerce.wordpress.com/2018/07/30/woocommerce-beta-tester-2-0-0/"
		target="_blank"
		>WooCommerce Beta Tester Plugin</a
	>.
</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Highlights</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>
	Since the release of
	<a href="<%= lastReleasePostUrl %>"><%= prettyPreviousVersion %></a>, the
... (135 lines truncated)
</file>

<file path="tools/release-posts/templates/contributor.ejs">
<!-- wp:column -->      
<div class="wp-block-column">
  <!-- wp:image {"sizeSlug":"large","linkDestination":"custom"} -->
  <figure class="wp-block-image size-large">
    <a href="https://github.com/<%= contributor.login %>" target="_blank">
      <img src="<%= contributor.avatar_url %>" alt=""/>
    </a>
    <figcaption><%= contributor.login %></figcaption>
  </figure>
  <!-- /wp:image -->
</div>
<!-- /wp:column -->
</file>

<file path="tools/release-posts/templates/contributors.ejs">
<% const NUMBER_COLUMNS_TO_DISPLAY = 6 %>
<% for ( const packageName in contributors ) { %>  
  <% const packageContributors = contributors[packageName].contributors %>

  <% if (packageContributors) { %> 
    <% if (packageContributors.length) { %>
      <h2><%= packageName.replace('-', ' ') %></h2>
    <% } %>
    <% const lastContributor = packageContributors[packageContributors.length - 1] %>
    <% let column = 1 %>
    <% for ( const contributor of packageContributors ) { %>
      <% if (column % NUMBER_COLUMNS_TO_DISPLAY === 1) { %>
        <!-- wp:columns -->
        <div class="wp-block-columns">
          <%- include('contributor', { contributor: contributor }) %>        
      <% } else { %>
        <%- include('contributor', { contributor: contributor }) %>
      <% } %>      
      
      <% if ( contributor.login === lastContributor.login &&  packageContributors.length  % NUMBER_COLUMNS_TO_DISPLAY !== 0 ) { %>
        <% const columnsToAdd = NUMBER_COLUMNS_TO_DISPLAY - ( packageContributors.length % NUMBER_COLUMNS_TO_DISPLAY ) %>
        <% for ( let i = 0; i < columnsToAdd; i++ ) { %>
          <!-- wp:column -->
          <div class="wp-block-column"></div>
          <!-- /wp:column -->
        <% } %>
      <% } %>
      <% column ++ %>
      <% if ( ( column % NUMBER_COLUMNS_TO_DISPLAY === 1 ) || contributor.login === lastContributor.login ) { %>
        </div>
... (6 lines truncated)
</file>

<file path="tools/release-posts/templates/database.ejs">
<!-- wp:heading -->
<h2 id="database-changes">Database Changes</h2>
<!-- /wp:heading -->

<% if (changes.db) { %>
  <!-- wp:heading -->
  <h3 id="db-updates">DB Updates</h3>
  <!-- /wp:heading -->

  <!-- wp:table -->
  <figure class="wp-block-table">
    <table>
      <tbody>
        <tr>
          <th>
            <strong>Function Name</strong>
          </th>
        </tr>
        <tr>
          <td><code><%= changes.db.functionName %></code></td>
        </tr>
      </tbody>
    </table>
  </figure>
  <!-- /wp:table -->
<% } else { %>
  <!-- wp:paragraph -->
  <p>There are no database changes in this release.</p>
  <!-- /wp:paragraph -->
<% } %>
... (1 lines truncated)
</file>

<file path="tools/release-posts/templates/hooks.ejs">
<!-- wp:heading -->
<h2 id="actions-and-filters">Actions and Filters</h2>
<!-- /wp:heading -->

<% if (changes.hooks.size) { %>
  <!-- wp:table -->
  <figure class="wp-block-table">
    <table>
      <tbody>
        <tr>
          <th><strong>Filter</strong></th>
          <th><strong>Description</strong></th>
          <th><strong>GitHub Link</strong></th>
        </tr>
        <% changes.hooks.forEach(({ name, description, ghLink }) => { %>
          <tr>
            <td><%= name %></td>
            <td><%= description %></td>
            <td><a target="_blank" href="<%= ghLink %>">Link</a></td>
          </tr>
        <% }) %>
        <!-- end each hook change-->
      </tbody>
    </table>
  </figure>
  <!-- /wp:table -->
<% } else  { %>
  <!-- wp:paragraph -->
  <p>This release doesn\'t add any actions or filters.</p>
  <!-- /wp:paragraph -->
... (2 lines truncated)
</file>

<file path="tools/release-posts/templates/oauth.ejs">
<html>
  <head>
    <title>Authentication Success</title>
  </head>

  <body>Authentication successful, please return to the console to complete the process.</body>
</html>
</file>

<file path="tools/release-posts/templates/rc-release.ejs">
<!-- wp:paragraph -->
<p>Release Candidate <%= rcNumber %> for the <%=
	finalReleaseDate.toLocaleDateString('en-US', {month: 'long', day:
	'numeric'}) %> release of WooCommerce is now available for testing! You can
	either
	<a
		href="https://downloads.wordpress.org/plugin/woocommerce.<%= version.version %>.zip"
		target="_blank"
		rel="noreferrer noopener"
		>download it directly from WordPress.org</a
	>
	or install our
	<a
		rel="noreferrer noopener"
		href="https://woocommerce.wordpress.com/2018/07/30/woocommerce-beta-tester-2-0-0/"
		target="_blank"
		>WooCommerce Beta Tester Plugin</a
	>.
</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">What's New?</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Since the release of
	<a href="<%= lastReleasePostUrl %>"><%= prettyPreviousVersion %></a>, the
	following changes have been made:
</p>
... (86 lines truncated)
</file>

<file path="tools/release-posts/templates/release.ejs">
<!-- wp:heading -->
<h1><%= title %></h1>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>We are pleased to announce the release of WooCommerce <%= displayVersion %>. This release should be backwards compatible with the previous version.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This release contains:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul>
  <% for ( const packageName in contributors ) { %>    
    <% const {org, repo, contributors: packageContributors, totalCommits, baseRef, headRef} = contributors[packageName] %>
    <% if ( packageContributors ) { %>
      <li>
        <a target="_blank" href="https://github.com/<%= org %>/<%= repo %>/compare/<%= baseRef %>...<%= headRef %>">
          <%= totalCommits %> commits from <%= packageContributors.length %> contributors
        </a> 
        in <%= packageName %>.
      </li>
    <% } %>
  <% } %>
</ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>
... (34 lines truncated)
</file>

<file path="tools/release-posts/templates/templates.ejs">
<!-- wp:heading -->
<h2 id="template-changes">Template Changes</h2>
<!-- /wp:heading -->

<% if (changes.templates.size) { %>
  <!-- wp:table -->
  <figure class="wp-block-table">
    <table>
      <thead>
        <th>
          <strong>Template</strong>
        </th>
        <th>
          <strong>GitHub Link</strong>
        </th>
      </thead>
      <tbody>

        <!-- for each template change (template / description) -->
        <% changes.templates.forEach((change) => { %>
          <tr>
            <td><%= change.filePath %></td>
            <td>
              <% change.pullRequests.forEach( ( pullRequest ) => { %>
                <a href="https://github.com/woocommerce/woocommerce/pull/<%= pullRequest %>">#<%= pullRequest %></a>
              <% }) %>
            </td>
          </tr>
        <% }) %>
      </tbody>
... (9 lines truncated)
</file>

<file path="tools/release-posts/index.ts">
import dotenv from 'dotenv';
⋮----
import { program } from './program';
</file>

<file path="tools/release-posts/package.json">
{
	"name": "release-posts",
	"version": "0.0.1",
	"description": "Automate release post generation for WordPress plugins",
	"main": " ",
	"scripts": {
		"lint": "tsc --noEmit",
		"release-post": "node -r ts-node/register ./commands/release-post/index.ts"
	},
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"engines": {
		"node": "^24.15.0"
	},
	"devDependencies": {
		"@tsconfig/node16": "^1.0.4",
		"@types/ejs": "^3.1.5",
		"@types/express": "^4.17.21",
		"@types/lodash.shuffle": "^4.2.9",
		"@types/node": "^24.1.0",
		"@types/node-fetch": "^2.6.9",
		"@types/semver": "^7.5.6",
		"typescript": "5.7.x"
	},
	"dependencies": {
		"@commander-js/extra-typings": "^0.1.0",
		"@octokit/rest": "^19.0.13",
		"@woocommerce/monorepo-utils": "workspace:*",
		"code-analyzer": "workspace:*",
		"commander": "9.4.0",
... (24 lines truncated)
</file>

<file path="tools/release-posts/program.ts">
import { Command } from '@commander-js/extra-typings';
</file>

<file path="tools/release-posts/README.md">
# Release Post Generator CLI tool

This is a cli tool designed to generate draft release posts for WooCommerce.
Posts generated via the tool will be draft posted to <https://developer.woocommerce.com>.

You can also generate an HTML representation of the post if you
don't have access to a WordPress.com auth token.

## Setup

1. Make sure `pnpm i` has been run in the monorepo.
2. Make sure you have added a `.env` file with the env variables set. WCCOM_TOKEN is optional if you're using `--outputOnly`, but
   the `GITHUB_ACCESS_TOKEN` is required. If you need help generating a token see [the docs](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token). To silence all CLI output, set `LOGGER_LEVEL` to `"silent"`.
3. Note that the env file should live at the same path that you're running the command from.
4. Run the tool via the npm script, e.g. `pnpm release-post release "6.8.0" --outputOnly`
5. For more help on individual options, run the help `pnpm release-post <command> --help`. e.g. `pnpm release-post rc --help`

## Publishing Draft Posts

This tool will publish draft posts to `https://developer.woocommerce.com` for you if you omit the `--outputOnly` flag. There is some minimal first time setup for this though:

1. Create an app on WordPress.com [here](https://developer.wordpress.com/apps/).
2. Recommended settings:
   - Name can be anything
   - Description can be left blank
   - Website URL just put `http://localhost`
   - Redirect URLs, by default you should add: `http://localhost:3000/oauth`
   - JavaScript Origins put `http://localhost`
   - Type - choose "Web"
3. Once your app is created you can go back to the
... (20 lines truncated)
</file>

<file path="tools/release-posts/tsconfig.json">
{
	"extends": "@tsconfig/node16/tsconfig.json",
	"compilerOptions": {
		"module": "Node16",
		"moduleResolution": "Node16",
		"typeRoots": [
			"./typings",
			"./node_modules/@types"
		]
	},
	"ts-node": {
		"transpileOnly": true,
		"files": true
	}
}
</file>

<file path="tools/storybook/.storybook/main.mjs">
// Add WooCommerce Blocks Storybook for build process.
⋮----
// Introductory documentation
⋮----
// WooCommerce Admin / @woocommerce/components components
⋮----
// WooCommerce Admin / @woocommerce/experimental components
⋮----
// WooCommerce Admin / @woocommerce/onboarding components
⋮----
refs: ( config,
⋮----
// WooCommerce Blocks gets automatically on port 6006 run when you run pnpm --filter=@woocommerce/storybook watch:build
⋮----
previewHead: ( head )
⋮----
previewBody: ( body )
</file>

<file path="tools/storybook/.storybook/manager.js">

</file>

<file path="tools/storybook/.storybook/preview-head.html">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Outlined&ver=1601945340" rel="stylesheet" />
<link href="wordpress/css/common.min.css" rel="stylesheet" />
<link href="wordpress/css/forms.min.css" rel="stylesheet" />
<link href="wordpress/css/admin-menu.min.css" rel="stylesheet" />
<link href="wordpress/css/dashboard.min.css" rel="stylesheet" />
<link href="wordpress/css/list-tables.min.css" rel="stylesheet" />
<link href="wordpress/css/edit.min.css" rel="stylesheet" />
<link href="wordpress/css/revisions.min.css" rel="stylesheet" />
<link href="wordpress/css/media.min.css" rel="stylesheet" />
<link href="wordpress/css/themes.min.css" rel="stylesheet" />
<link href="wordpress/css/about.min.css" rel="stylesheet" />
<link href="wordpress/css/nav-menus.min.css" rel="stylesheet" />
<link href="wordpress/css/widgets.min.css" rel="stylesheet" />
<link href="wordpress/css/site-icon.min.css" rel="stylesheet" />
<link href="wordpress/css/l10n.min.css" rel="stylesheet" />
<link href="wordpress/css/site-health.min.css" rel="stylesheet" />
<link href="wordpress/css/components.css" rel="stylesheet" />
<link href="wordpress/css/edit-site.css" rel="stylesheet" />
</file>

<file path="tools/storybook/.storybook/preview.js">

</file>

<file path="tools/storybook/stories/docs/introduction.mdx">
# Introduction

## Welcome!

The WooCommerce project uses Storybook to view and work with the UI components developed in WooCommerce packages.

On this interactive site you can browse individual components, their controls, options, and settings in isolation. You can also modify controls and arguments and see the changes right away.

The components displayed on this site can be used in your code to extend WooCommerce.
Import them from the components root directory like in below example:

```jsx
import { Rating } from '@woocommerce/components';

export default function MyProductRating() {
	return <Rating rating={ 4.5 } size={ 18 } totalStars={ 5 } />;
}
```

## How this site works

The site shows the individual components in the sidebar and the Canvas on the right. Select the component you’d like to explore, and you’ll see the display on the **Canvas** tab. If the component also has controls/arguments, you can modify them on the **Controls** tab on the lower half of the screen.

To view the documentation for each component use the **Docs** menu item in the top toolbar.

To use it in your local development environment run the following command in the top level WooCommerce directory:

```bash
pnpm --filter=@woocommerce/storybook watch:build
```
... (6 lines truncated)
</file>

<file path="tools/storybook/.babelrc.json">
{
  "sourceType": "unambiguous",
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "chrome": 100,
          "safari": 15,
          "firefox": 91
        }
      }
    ],
    "@babel/preset-typescript",
    "@babel/preset-react"
  ],
  "plugins": []
}
</file>

<file path="tools/storybook/import-wp-css-storybook.sh">
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
STORYBOOK_WORDPRESS_DIR="$DIR/../storybook/wordpress";
STORY_BOOK_CSS_PATH="$DIR/../storybook/wordpress/css";
TMP_DIR="$DIR/../storybook/wordpress/tmp";
ARCHIVE_CSS_PATH="wordpress/wp-admin/css";
ARCHIVE_IMG_PATH="wordpress/wp-admin/images";
ARCHIVE_EDIT_SITE_PATH="wordpress/wp-includes/css/dist/edit-site/style.css";
mkdir -p "$STORY_BOOK_CSS_PATH";
mkdir -p "$TMP_DIR";
function download_and_extract_css {
    curl -o "$STORYBOOK_WORDPRESS_DIR/wordpress-latest.zip" https://wordpress.org/nightly-builds/wordpress-latest.zip;
    unzip -qq "$STORYBOOK_WORDPRESS_DIR/wordpress-latest.zip" "$ARCHIVE_CSS_PATH/*" "$ARCHIVE_IMG_PATH/*" "$ARCHIVE_EDIT_SITE_PATH" -d "$TMP_DIR";
    rsync -a "$TMP_DIR/$ARCHIVE_CSS_PATH" "$STORYBOOK_WORDPRESS_DIR";
    rsync -a "$TMP_DIR/$ARCHIVE_IMG_PATH" "$STORYBOOK_WORDPRESS_DIR";
    rsync -a "$TMP_DIR/$ARCHIVE_EDIT_SITE_PATH" "$STORYBOOK_WORDPRESS_DIR/css/edit-site.css";
    rm -r "$TMP_DIR";
	rm -r "$STORYBOOK_WORDPRESS_DIR/wordpress-latest.zip";
}
if [ -z "$(find "$STORY_BOOK_CSS_PATH" -iname '*.css')" ] || [ "$1" == "-f" ]
then
    download_and_extract_css;
else
    echo "WordPress CSS already imported, pass -f to force an update";
fi
</file>

<file path="tools/storybook/package.json">
{
	"name": "@woocommerce/storybook",
	"title": "WooCommerce Storybook",
	"description": "Storybook implementation for WooCommerce",
	"homepage": "https://woocommerce.github.io/woocommerce/",
	"private": true,
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"scripts": {
		"build": "pnpm --filter='@woocommerce/block-library' build:storybook && pnpm build:storybook",
		"build:storybook": "./import-wp-css-storybook.sh && STORYBOOK=true BABEL_ENV=storybook storybook build -c ./.storybook --quiet && pnpm run copy-blocks-storybook-iframe",
		"watch:build": "pnpm watch:build:storybook",
		"watch:build:storybook": "./import-wp-css-storybook.sh && STORYBOOK=true BABEL_ENV=storybook storybook dev -c ./.storybook -p 6007 --ci",
		"copy-blocks-storybook-iframe": "cp ../../plugins/woocommerce/client/blocks/storybook/dist/iframe.html ./storybook-static/assets/woocommerce-blocks",
		"storybook-rtl": "USE_RTL_STYLE=true pnpm watch:build:storybook",
		"preinstall": "npx only-allow pnpm"
	},
	"engines": {
		"node": "^24.15.0"
	},
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"devDependencies": {
		"@babel/preset-env": "catalog:tooling",
		"@babel/preset-react": "catalog:tooling",
... (19 lines truncated)
</file>

<file path="tools/storybook/setting.mock.js">
export function getSetting()
</file>

<file path="tools/storybook/tsconfig.json">
{
	"compilerOptions": {
		// Target latest version of ECMAScript.
		"target": "esnext",
		// Search under node_modules for non-relative imports.
		"moduleResolution": "bundler",
		// Process & infer types from .js files.
		"allowJs": true,
		"jsx": "preserve",
		// Don't emit; allow Babel to transform files.
		"noEmit": true,
		// Enable strictest settings like strictNullChecks & noImplicitAny.
		"strict": true,
		// Import non-ES modules as default imports.
		"esModuleInterop": true,
		"skipLibCheck": false,
		"module": "esnext",
		"typeRoots": [
			"./typings",
			"./node_modules/@types",
			"packages/**/node_modules/@types"
		],
		"baseUrl": "./",
		"paths": {
			"@woocommerce/*": [ "packages/*/src" ],
			"~/*": [ "client/*" ]
		}
	},
	"exclude": [ "node_modules", "build", "build-module", "dist", "vendor" ]
}
... (1 lines truncated)
</file>

<file path="tools/storybook/webpack.config.js">
module.exports = ( storybookConfig ) =>
</file>

<file path="tools/.gitkeep">

</file>

<file path="tools/README.md">
# Monorepo Infrastructure & Tools

This document outlines the monorepo's infrastructure and the rationale behind the decisions we've made.

## Task Orchestration

Each project within the monorepo follows a small, consistent script naming scheme so we can run related tasks together with [pnpm's script-pattern execution](https://pnpm.io/cli/run#running-multiple-scripts):

```json
{
	"scripts": {
		"build": "pnpm build:project",
		"build:project": "pnpm --stream '/^build:project:.*$/'",
		"lint": "pnpm --if-present '/^lint:lang:.*$/'",
		"lint:fix": "pnpm --if-present '/^lint:fix:lang:.*$/'",
		"watch:build": "pnpm watch:build:project",
		"watch:build:project": "pnpm --stream '/^watch:build:project:.*$/'"
	}
}
```

`build` aliases `build:project`; `watch:build` aliases `watch:build:project`. New work is added under the regex naming scheme — for example, `build:project:bundle` might be a script that runs `webpack`. pnpm runs every regex match concurrently, so no extra orchestrator (`concurrently`, `--parallel`) is needed.

`--if-present` is only used when the regex may match nothing for a given project (e.g. linting groups where some packages have no rules). If a project has the scripts, drop `--if-present`; if it doesn't, drop the wrapper script entirely.

`--parallel` is never used here — it tells pnpm to run the script across the entire workspace rather than the current project, which is not what these wrappers want.

### Cross-project orchestration

When one project needs to build another, prefer an explicit `--filter` to the dependency over `--filter="$npm_package_name..."` topological cascade. The cascade implicitly rebuilds every transitive dependency; explicit filters keep the call site honest about what runs.
... (15 lines truncated)
</file>

<file path=".codecov.yml">
codecov:
    notify:
        require_ci_to_pass: yes
ignore:
    - '**/tests'
    - '**/test'
    - 'tools/**'
    - 'packages/js/create-woo-extension'
    - 'packages/js/eslint-plugin'
    - 'packages/js/internal-build'
    - 'packages/js/internal-js-tests'
    - '**/*.test.*'
coverage:
    precision: 1
    round: nearest
    range: '50...80'
    status:
        project:
            default:
                target: auto
        patch:
            default:
                target: auto
parsers:
    gcov:
        branch_detection:
            conditional: yes
            loop: yes
            method: no
            macro: no
... (7 lines truncated)
</file>

<file path=".coderabbit.yml">
reviews:
    assess_linked_issues: false
    collapse_walkthrough: true
    high_level_summary: false
    review_status: false
    suggested_labels: false
    suggested_reviewers: false
    poem: false
    path_instructions:
    - path: '**/*.{php,js,ts,jsx,tsx}'
      instructions: |
        Don't trust that extension developers will follow the best practices, make sure the code:
        - Guards against unexpected inputs.
        - Sanitizes and validates any potentially dangerous inputs.
        - Is backwards compatible.
        - Is readable and intuitive.
        - Has unit or E2E tests where applicable.
        Treat any change to a public or externally exposed class, interface, function, or method signature as high-risk,
        regardless of whether it lives in the `Internal` namespace — third-party code implements and consumes some of
        these contracts in practice. Flag such changes and ask the author to state the backwards-compatibility impact in
        the PR description. Call out explicitly when a method is added to an interface that external code can implement:
        this is a backwards-incompatible change because existing implementers fatal on load (e.g. WooCommerce 10.9.0 was
        reverted on WP Cloud after a required method was added to `FeedInterface`). Suggest a non-breaking alternative
        such as adding the method to a concrete class, introducing a new interface, or providing a default via an
        abstract base class. For renames or removals of existing public symbols, follow the deprecate-don't-rename
        policy: keep the original symbol with an `@deprecated` notice pointing to the replacement, rather than changing
        it in place.
        When making any changes to code that deletes or modifies orders/products/customer data, make sure that there are
        sufficient checks in place to prevent accidental data loss. As an example, if deleting a draft order, check that
        the order status is indeed `draft` or `checkout-draft`. Also think about whether race conditions could occur and
... (2 lines truncated)
</file>

<file path=".gitattributes">
*       text=auto

# Force LF In Configuration Files
*.md    text    eol=lf
*.json  text    eol=lf
*.yml   text    eol=lf

# Force LF In Code Files
*.php   text    eol=lf
*.js    text    eol=lf
*.jsx   text    eol=lf
*.ts    text    eol=lf
*.tsx   text    eol=lf
*.css   text    eol=lf
*.scss  text    eol=lf
*.flf   text    eol=lf
</file>

<file path=".markdownlint.json">
{
	"default": true,
	"MD003": { "style": "atx" },
	"MD007": { "indent": 4 },
	"MD013": { "line_length": 9999 },
	"MD024": { "siblings_only": true },
	"MD033": {
		"allowed_elements": [
			"h1",
			"h2",
			"h3",
			"br",
			"summary",
			"details",
			"video"
		]
	},
	"MD060": false,
	"no-hard-tabs": false,
	"whitespace": false
}
</file>

<file path=".npmrc">
; Keep pnpm 9 users auto-upgrading to the repo-pinned pnpm version.
manage-package-manager-versions=true

; pnpm 10 defaults removed from here:
;   auto-install-peers=true
;   strict-peer-dependencies=false
;
; All other pnpm settings live in pnpm-workspace.yaml, including the dependency
; resolution ones that used to sit in the "pnpm" field of package.json.
</file>

<file path=".nvmrc">
v24
</file>

<file path=".pnpmfile.cjs">
/**
 * External dependencies.
 */
⋮----
// A cache for package files so that we don't keep loading them unnecessarily.
⋮----
/**
 * Loads a package file or pull it from the cache.
 *
 * @param {string} packagePath The path to the package directory.
 * @return {Object} The package file.
 */
function loadPackageFile( packagePath )
⋮----
// Resolve the absolute path for consistency when loading and updating.
⋮----
/**
 * Loads a tsconfig.json, or null if missing or not plain JSON.
 *
 * Returning null on a parse failure keeps the hook from clobbering JSONC
 * tsconfigs that include structural comments. Affected packages must be
 * converted to plain JSON to participate in the references sync.
 *
 * @param {string} tsconfigPath Absolute path to the tsconfig.json file.
 * @return {Object|null} Parsed config, or null if missing or unparseable.
 */
function loadTsconfig( tsconfigPath )
⋮----
/**
 * Writes a tsconfig.json with the project's standard tab indentation.
... (70 lines truncated)
</file>

<file path=".prettierrc.js">

</file>

<file path=".stylelintrc">
{
  "extends": "@wordpress/stylelint-config",
}
</file>

<file path=".syncpackrc">
{
	"indent": "\t",
	"semverGroups": [
		{
			"range": "^"
		}
	],
	"customTypes": {
		"engines": {
			"path": "engines",
			"strategy": "versionsByName"
		}
	},
	"versionGroups": [
		{
			"label": "Banned dependencies: classnames(->clsx), concurrently(->pnpm), cross-env(->wsl),@automattic/webpack-rtl-plugin(->internal-build)",
			"dependencies": [
				"classnames",
				"concurrently",
				"cross-env",
				"@automattic/webpack-rtl-plugin"
			],
			"packages": [
				"**"
			],
			"isBanned": true
		},
		{
			"dependencies": [
				"@types/node"
... (688 lines truncated)
</file>

<file path="AGENTS.md">
# WooCommerce Monorepo - AI Agents Documentation

## Project Overview

WooCommerce is a WordPress e-commerce plugin organized as a monorepo with:

- **Backend**: PHP in `plugins/woocommerce/` (PSR-4, WordPress standards)
- **Admin Client**: React/TypeScript in `plugins/woocommerce/client/admin/`
- **Payment Settings**: Specialized React/TypeScript module in `plugins/woocommerce/client/admin/client/settings-payments/`

## Navigation Guide

### Which Documentation to Use?

**Use this doc when:**

- Getting oriented in the project
- Understanding overall architecture
- Finding the right documentation or skill

## Available Skills

The `.ai/skills/` directory contains procedural HOW-TO instructions:

- **`woocommerce-backend-dev`** - Backend PHP conventions and unit tests. **Invoke before writing any PHP test files.**
- **`woocommerce-dev-cycle`** - Testing and linting workflows (PHP, JS, markdown)
- **`woocommerce-local-env`** - Local environment setup, wp-env commands, and WooCommerce build watchers
- **`woocommerce-copy-guidelines`** - UI text standards (sentence case rules)
- **`woocommerce-code-review`** - Code review standards and critical violations to flag
- **`woocommerce-markdown`** - Markdown writing and editing guidelines
... (296 lines truncated)
</file>

<file path="changelog.txt">
== Changelog ==

= 11.1.0 2026-09-03 =

**WooCommerce**

* Fix - Activity Panel counts endpoint now respects an explicitly-empty actionable order statuses setting instead of falling back to the defaults, so a cleared setting reports zero orders to fulfill. [#66483](https://github.com/woocommerce/woocommerce/pull/66483)
* Fix - Add aria-label to Product Gallery Thumbnails [#67303](https://github.com/woocommerce/woocommerce/pull/67303)
* Fix - Add a visible validation message for the checkout terms and conditions checkbox. [#66449](https://github.com/woocommerce/woocommerce/pull/66449)
* Fix - Add explicit sale date fields to product Quick Edit and save schedules consistently with the full product editor. [#66931](https://github.com/woocommerce/woocommerce/pull/66931)
* Fix - Align the Core Breadcrumbs block output with WooCommerce Store Breadcrumbs on shop, product, account, archive, and custom taxonomy pages. [#66382](https://github.com/woocommerce/woocommerce/pull/66382)
* Fix - Align the Payments settings partner recommendations with the partnership tracking sheet: add Mayotte, add PayPal to Guyana, add Airwallex to Malaysia and South Korea, make MONEI the preferred provider in Andorra, and place Paytrail before GoCardless in Finland. [#67395](https://github.com/woocommerce/woocommerce/pull/67395)
* Fix - Allow customers to save account details when an unchanged display name is already an email address. [#66645](https://github.com/woocommerce/woocommerce/pull/66645)
* Fix - Allow null parent names in REST API order line items. [#66636](https://github.com/woocommerce/woocommerce/pull/66636)
* Fix - Allow Product Gallery variation events to use numeric string IDs. [#67768](https://github.com/woocommerce/woocommerce/pull/67768)
* Fix - Allow REST order updates to accept round-tripped line item meta display values with complex data. [#65513](https://github.com/woocommerce/woocommerce/pull/65513)
* Fix - Allow Shop Managers to save Local Pickup settings by adding a dedicated /wc/v3/pickup-locations REST route guarded by the manage_woocommerce capability, instead of posting to /wp/v2/settings which requires manage_options. [#65286](https://github.com/woocommerce/woocommerce/pull/65286)
* Fix - Analytics: initialize the Date type selector in Analytics settings with the effective date_paid default instead of rendering blank when the option was never saved. [#67423](https://github.com/woocommerce/woocommerce/pull/67423)
* Fix - Apply block support styles to legacy Product Reviews block wrappers. [#67754](https://github.com/woocommerce/woocommerce/pull/67754)
* Fix - Apply shipping tax to manual orders that contain shipping but no products. [#66639](https://github.com/woocommerce/woocommerce/pull/66639)
* Fix - Apply the stepper quantity-selector styles only to quantity containers that hold a visible quantity input, so a form containing both visible and hidden quantity fields no longer renders a stepper box around a hidden one. [#67153](https://github.com/woocommerce/woocommerce/pull/67153)
* Fix - Blueprint: match the restricted site options list regardless of the casing, padding or accents used in an imported key, so a variant spelling can no longer overwrite a restricted option such as wp_user_roles. [#67348](https://github.com/woocommerce/woocommerce/pull/67348)
* Fix - Cap quantity-form v4 refund amounts to the line's remaining refundable amount so sequential partial refunds can always refund the remaining items instead of failing on rounding drift. [#66884](https://github.com/woocommerce/woocommerce/pull/66884)
* Fix - Cart Link block: set the cart icon width to match the Mini-Cart icon size (1.5em) so it no longer renders oversized. [#65875](https://github.com/woocommerce/woocommerce/pull/65875)
* Fix - Change CSV batch exporter default fopen mode from a+ to a for S3 stream wrapper compatibility and add error logging when opening, writing to, or closing the export file fails. [#66295](https://github.com/woocommerce/woocommerce/pull/66295)
* Fix - Clarify the on-hold order email for payment flows that require another step. [#66914](https://github.com/woocommerce/woocommerce/pull/66914)
* Fix - Clear cached payment provider lists when the payment providers service cache is cleared. [#66909](https://github.com/woocommerce/woocommerce/pull/66909)
* Fix - Complete the WPDS token migration for the Settings UI shell while preserving compatibility-specific dimensions. [#67150](https://github.com/woocommerce/woocommerce/pull/67150)
* Fix - Correct the Macanese pataca currency symbol to MOP$. [#66716](https://github.com/woocommerce/woocommerce/pull/66716)
* Fix - Correct the Zambian kwacha currency symbol from ZK to K. This changes the public symbol returned by currency APIs and the symbol recognized when saving flat-rate shipping costs. [#66722](https://github.com/woocommerce/woocommerce/pull/66722)
... (16442 lines truncated)
</file>

<file path="CLAUDE.md">
@AGENTS.md
</file>

<file path="CODE_OF_CONDUCT.md">
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

... (17 lines truncated)
</file>

<file path="CODEOWNERS">
# Monorepo CI.
/.github/ @woocommerce/monorepo

# Monorepo tooling folders.
/packages/js/e2e-utils-playwright/ @woocommerce/monorepo

# Files in root of repository
/changelog.txt @woocommerce/monorepo
/pnpm-lock.yaml @woocommerce/monorepo

# Docs resources, which gets published to https://developer.woocommerce.com
/docs/ @woocommerce/developer-advocacy

# Interactivity API - public stores
/plugins/woocommerce/client/blocks/assets/js/base/stores/ @woocommerce/billow
/plugins/woocommerce/src/Blocks/Utils/BlocksSharedState.php @woocommerce/billow

# Core cart and checkout related files
/plugins/woocommerce/includes/class-wc-cart*.php @woocommerce/rubik
/plugins/woocommerce/includes/class-wc-checkout*.php @woocommerce/rubik
/plugins/woocommerce/includes/wc-cart-functions.php @woocommerce/rubik
/plugins/woocommerce/includes/class-wc-session-handler.php @woocommerce/rubik

# Store API and internal REST routes
/plugins/woocommerce/src/StoreApi/ @woocommerce/rubik
/plugins/woocommerce/src/Internal/RestApi/ @woocommerce/rubik

# Cart Checkout Blocks
/plugins/woocommerce/client/blocks/assets/js/blocks/cart @woocommerce/rubik
/plugins/woocommerce/client/blocks/assets/js/blocks/cart-checkout-shared @woocommerce/rubik
... (43 lines truncated)
</file>

<file path="CONTRIBUTING.md">
# Contributing to WooCommerce

This is a quick reference for common commands used during development. For broader contribution guidelines, see the [Contributing to WooCommerce](https://developer.woocommerce.com/docs/contribution/contributing/) docs. For detailed development notes, see [DEVELOPMENT.md](DEVELOPMENT.md).

## Tooling

- [Node.js](https://nodejs.org/) (PNPM installs and uses the pinned version automatically; a version manager such as [NVM](https://github.com/nvm-sh/nvm#installing-and-updating) is optional)
- [PNPM](https://pnpm.io/installation)
- [PHP](https://www.php.net/manual/en/install.php)
- [Composer](https://getcomposer.org/doc/00-intro.md)
- [Docker](https://docs.docker.com/get-docker/) (for running tests and local environments)

A POSIX-compliant OS (Linux, macOS) is assumed. On Windows, use [WSL](https://learn.microsoft.com/en-us/windows/wsl/install).

## Initial install

```sh
# Install JS and PHP dependencies.
# PNPM automatically uses the pinned Node version for the scripts it runs.
pnpm install
```

## Monorepo filtering

This is a PNPM workspaces monorepo. Use `--filter` to target individual projects:

```sh
# Build WooCommerce Core + deps
pnpm --filter='@woocommerce/plugin-woocommerce' build
# Lint a specific package
... (123 lines truncated)
</file>

<file path="DEVELOPMENT.md">
# Development

This document aims to provide as much context as possible to aid in the development of plugins, packages, and tools in the monorepo.

## Getting Started

Please refer to [the Getting Started section of the `README.md`](README.md#getting-started) for a general-purpose guide on getting started. The rest of this document will assume that you've installed all of the prerequisites and setup described there.

### Plugin, Package, and Tool Filtering

In order to run commands on individual projects you will need to utilize [PNPM's --filter flag](https://pnpm.io/filtering). This flag supports `"name"` option in `package.json`, paths, and globs.

### Examples

Here are some examples of the ways you can use `pnpm` commands:

```bash
# Lint and build all plugins, packages, and tools.
pnpm lint && pnpm build

# Build WooCommerce Core and all of its dependencies
pnpm --filter='@woocommerce/plugin-woocommerce' build

# Lint the @woocommerce/components package
pnpm --filter='@woocommerce/components' lint

# Test all of the @woocommerce scoped packages
pnpm --filter='@woocommerce/*' test

# Build all of the JavaScript packages
... (62 lines truncated)
</file>

<file path="eslint.config.mjs">
/**
 * Internal dependencies
 */
</file>

<file path="license.txt">
WooCommerce - eCommerce for WordPress

Copyright 2015 - 2026 by the contributors

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

This program incorporates work covered by the following copyright and
permission notices:

  Jigoshop is Copyright (c) 2011 Jigowatt Ltd.
  http://jigowatt.com - http://jigoshop.com

  Jigoshop is released under the GPL

and

  WooCommerce - eCommerce for WordPress

... (346 lines truncated)
</file>

<file path="package.json">
{
	"name": "woocommerce-monorepo",
	"title": "WooCommerce Monorepo",
	"description": "Monorepo for the WooCommerce ecosystem",
	"homepage": "https://woocommerce.com/",
	"packageManager": "pnpm@10.33.0",
	"engines": {
		"node": "^24.15.0"
	},
	"private": true,
	"repository": {
		"type": "git",
		"url": "https://github.com/woocommerce/woocommerce.git"
	},
	"author": "Automattic",
	"license": "GPL-2.0-or-later",
	"bugs": {
		"url": "https://github.com/woocommerce/woocommerce/issues"
	},
	"scripts": {
		"build": "pnpm -r --workspace-concurrency=Infinity --stream '/^build:project:.*$/'",
		"test": "pnpm -r test",
		"lint": "pnpm -r lint",
		"cherry-pick": "node ./tools/cherry-pick/bin/run",
		"clean": "rimraf -g '**/node_modules' 'packages/*/*/vendor' 'plugins/*/vendor' && pnpm store prune",
		"clean:build": "rimraf -g '**/node_modules/.cache' '**/*.tsbuildinfo' 'packages/js/*/build' 'packages/js/*/build-*' 'packages/js/*/dist' 'plugins/*/build' 'plugins/woocommerce/client/*/build' && git clean --force -d -X --quiet ./plugins/woocommerce/assets",
		"preinstall": "npx only-allow pnpm",
		"postinstall": "husky",
		"run-canonical-extensions-tests": "bash bin/run-canonical-extensions-tests.sh",
		"sync-dependencies": "pnpm exec syncpack fix",
... (51 lines truncated)
</file>

<file path="phpcs.xml">
<?xml version="1.0"?>
<ruleset name="WordPress Coding Standards">
	<description>WooCommerce dev PHP_CodeSniffer ruleset.</description>
	<file>.</file>
	<exclude-pattern>tests/cli/</exclude-pattern>
	<exclude-pattern>includes/libraries/</exclude-pattern>
	<exclude-pattern>includes/legacy/</exclude-pattern>
	<exclude-pattern>includes/api/legacy/</exclude-pattern>
	<exclude-pattern>includes/api/v1/</exclude-pattern>
	<exclude-pattern>includes/class-wc-geo-ip.php</exclude-pattern>
	<exclude-pattern>includes/wc-deprecated-functions.php</exclude-pattern>
	<exclude-pattern>*/node_modules/*</exclude-pattern>
	<exclude-pattern>*/vendor/*</exclude-pattern>
	<exclude-pattern>lib/</exclude-pattern>
	<arg value="ps" />
	<arg name="basepath" value="./" />
	<arg name="parallel" value="8" />
	<config name="minimum_supported_wp_version" value="5.2" />
	<config name="testVersion" value="7.4-" />
	<rule ref="WooCommerce-Core" />
	<rule ref="WooCommerce.Functions.InternalInjectionMethod">
		<include-pattern>src/</include-pattern>
		<include-pattern>tests/php/src/</include-pattern>
		<properties>
			<property name="injectionMethod" value="init"/>
		</properties>
	</rule>
	<rule ref="WordPress.WP.I18n">
		<properties>
			<property name="text_domain" type="array" value="woocommerce" />
		</properties>
	</rule>
	<rule ref="PHPCompatibility">
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents">
		<exclude-pattern>tests/src</exclude-pattern>
	</rule>
	<rule ref="WordPress.Files.FileName.InvalidClassFileName">
		<exclude-pattern>includes/**/abstract-*.php</exclude-pattern>
		<exclude-pattern>tests/</exclude-pattern>
		<exclude-pattern>src/</exclude-pattern>
		<exclude-pattern>tests/php/src/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Classes.ClassFileName">
		<include-pattern>src/</include-pattern>
		<include-pattern>tests/php/src/</include-pattern>
	</rule>
	<rule ref="Squiz.Classes.ValidClassName">
		<include-pattern>src/</include-pattern>
		<include-pattern>tests/php/src/</include-pattern>
	</rule>
	<rule ref="Generic.Commenting">
		<exclude-pattern>tests/</exclude-pattern>
	</rule>
	<rule ref="PEAR.Functions.FunctionCallSignature.EmptyLine">
		<exclude-pattern>tests/e2e-tests/</exclude-pattern>
	</rule>
	<rule ref="WordPress.Files.FileName.NotHyphenatedLowercase">
		<exclude-pattern>i18n/</exclude-pattern>
		<exclude-pattern>src/</exclude-pattern>
		<exclude-pattern>tests/php</exclude-pattern>
		<exclude-pattern>tests/Tools/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FileComment.MissingPackageTag">
		<exclude-pattern>src/</exclude-pattern>
		<exclude-pattern>tests/php/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FileComment.Missing">
		<exclude-pattern>src/</exclude-pattern>
		<exclude-pattern>tests/php/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FunctionCommentThrowTag.Missing">
		<exclude-pattern>tests/php/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Commenting.FileComment.Missing">
		<exclude-pattern>tests/php/</exclude-pattern>
	</rule>
	<rule ref="Generic.Arrays.DisallowShortArraySyntax.Found">
		<exclude-pattern>src/Internal/Admin/</exclude-pattern>
		<exclude-pattern>src/Admin/</exclude-pattern>
		<exclude-pattern>src/Blocks/</exclude-pattern>
		<exclude-pattern>src/StoreApi/</exclude-pattern>
	</rule>
	<rule ref="WooCommerce.Functions.InternalInjectionMethod.MissingFinal">
		<exclude-pattern>src/Internal/Admin/</exclude-pattern>
		<exclude-pattern>src/Admin/</exclude-pattern>
		<exclude-pattern>src/Blocks/</exclude-pattern>
		<exclude-pattern>src/StoreApi/</exclude-pattern>
	</rule>
	<rule ref="WooCommerce.Functions.InternalInjectionMethod.MissingInternalTag">
		<exclude-pattern>src/Internal/Admin/</exclude-pattern>
		<exclude-pattern>src/Admin/</exclude-pattern>
		<exclude-pattern>src/Blocks/</exclude-pattern>
		<exclude-pattern>src/StoreApi/</exclude-pattern>
	</rule>
	<rule ref="WordPress.Security.NonceVerification.Recommended">
		<exclude-pattern>src/Internal/Admin/</exclude-pattern>
		<exclude-pattern>src/Admin/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Classes.ClassFileName.NoMatch">
		<exclude-pattern>src/Internal/Admin/</exclude-pattern>
		<exclude-pattern>src/Admin/</exclude-pattern>
	</rule>
	<rule ref="Squiz.Classes.ValidClassName.NotCamelCaps">
		<exclude-pattern>src/Internal/Admin/</exclude-pattern>
		<exclude-pattern>src/Admin/</exclude-pattern>
	</rule>
</ruleset>
</file>

<file path="pnpm-workspace.yaml">
useNodeVersion: 24.15.0
catalogs:
    wp-min:
        '@types/wordpress__block-editor': 15.0.6
        '@types/wordpress__block-library': 2.6.3
        '@types/wordpress__blocks': 12.5.18
        '@types/wordpress__edit-post': 8.4.2
        '@types/wordpress__viewport': 5.5.3
        '@wordpress/a11y': 4.33.1
        '@wordpress/api-fetch': 7.33.1
        '@wordpress/blob': 4.33.1
        '@wordpress/block-editor': 15.6.9
        '@wordpress/block-library': 9.33.10
        '@wordpress/blocks': 15.6.3
        '@wordpress/commands': 1.33.5
        '@wordpress/components': 30.6.5
        '@wordpress/compose': 7.33.1
        '@wordpress/core-data': 7.33.9
        '@wordpress/create-block': 4.76.1
        '@wordpress/data': 10.33.1
        '@wordpress/data-controls': 4.33.1
        '@wordpress/date': 5.33.1
        '@wordpress/deprecated': 4.33.1
        '@wordpress/dom': 4.33.1
        '@wordpress/dom-ready': 4.33.1
        '@wordpress/e2e-test-utils-playwright': 1.33.2
        '@wordpress/edit-post': 8.33.11
        '@wordpress/editor': 14.33.11
        '@wordpress/element': 6.33.1
        '@wordpress/format-library': 5.33.9
... (118 lines truncated)
</file>

<file path="README.md">
# WooCommerce Monorepo

![WooCommerce](https://woocommerce.com/wp-content/themes/woo/images/logo-woo@2x.png)

Welcome to the WooCommerce monorepo on GitHub. Here you can find all of the plugins, packages, and tools used in the development of the core WooCommerce plugin as well as WooCommerce extensions. You can browse the source, look at open issues, contribute code, and keep track of ongoing development.

We recommend all developers follow the [WooCommerce development blog](https://developer.woocommerce.com/blog/) to stay up to date with everything happening in the project. You can also [follow @DevelopWoo](https://x.com/DevelopWoo) on X (formerly Twitter) for the latest development updates.

## Getting Started

To get up and running within the WooCommerce Monorepo, you will need to make sure that you have installed all of the prerequisites.

### Prerequisites

-   [Node.js](https://nodejs.org/): Required to run PNPM and the monorepo's build and test scripts. You do not need to match a specific Node version by hand. PNPM reads the version pinned in [`pnpm-workspace.yaml`](pnpm-workspace.yaml) (`useNodeVersion`, mirrored in [`.nvmrc`](.nvmrc)) and automatically installs and uses it for every script it runs. A Node version manager such as [NVM](https://github.com/nvm-sh/nvm#installing-and-updating) is optional, but still handy for installing Node itself.
-   [PNPM](https://pnpm.io/installation): Our repository utilizes PNPM to manage project dependencies and run various scripts involved in building and testing projects.
-   [PHP 7.4+](https://www.php.net/manual/en/install.php): WooCommerce Core currently requires PHP version 7.4 or higher. It is also needed to run Composer and various project build scripts. See [troubleshooting](DEVELOPMENT.md#troubleshooting) for troubleshooting problems installing PHP.
-   [Composer](https://getcomposer.org/doc/00-intro.md): We use Composer to manage all of the dependencies for PHP packages and plugins.

Note: A POSIX-compliant operating system (e.g., Linux, macOS) is assumed. If you're working on a Windows machine, the recommended approach is to use [WSL](https://learn.microsoft.com/en-us/windows/wsl/install) (available since Windows 10).

Once you've installed all prerequisites, the following will prepare all of the build outputs necessary for development:

```bash
# Install the PHP and Composer dependencies for all of the plugins, packages, and tools.
# PNPM automatically uses the pinned Node version for every script it runs.
pnpm install --frozen-lockfile
# Build all of the plugins, packages, and tools in the monorepo
pnpm build
```
... (36 lines truncated)
</file>

<file path="renovate.json">
{
	"extends": [
		"config:base"
	],
	"packageRules": [
		{
			"packageNames": ["automattic/jetpack-autoloader"],
			"rangeStrategy": "bump"
		},
		{
			"depTypeList": ["devDependencies"],
			"extends": ["schedule:monthly"]
		}
	],
	"ignoreDeps": [
		"woocommerce/action-scheduler",
		"woocommerce/woocommerce-admin",
		"woocommerce/woocommerce-blocks",
		"woocommerce/woocommerce-rest-api"
	]
}
</file>

<file path="SECURITY.md">
# Security Policy

Full details of the Automattic Security Policy can be found on [automattic.com/security](https://automattic.com/security/).

## Supported Versions

Generally, *only the latest version of WooCommerce has continued support*. If a critical vulnerability is found in the current version of WooCommerce, we may opt to backport any patches to previous versions. 

## Reporting a Vulnerability

[WooCommerce](https://wordpress.org/plugins/woocommerce) is an open-source plugin for WordPress. Our HackerOne program covers the plugin software, as well as a variety of related projects and infrastructure.

**For responsible disclosure of security issues and to be eligible for our bug bounty program, please submit your report based on instructions found on [automattic.com/security](https://automattic.com/security).**

Our most critical targets are:

* WooCommerce core (this repository)
* WooCommerce [Blocks](https://wordpress.org/plugins/woo-gutenberg-products-block/) and [Admin](https://wordpress.org/plugins/woocommerce-admin/) packages and plugins
* WooCommerce.com -- the primary marketplace and marketing site, and all of it subdomains, e.g. [developer.woocommerce.com](https://developer.woocommerce.com/)
* WordPress.com -- hosted WooCommerce for Business and eCommerce offering on WordPress.com.

For more targets, see the `In Scope` section on [HackerOne](https://hackerone.com/automattic).

Please note that the **WordPress software is a separate entity** from Automattic. Please report vulnerabilities for WordPress through [the WordPress Foundation's HackerOne page](https://hackerone.com/wordpress).

## Guidelines

We're committed to working with security researchers to resolve the vulnerabilities they discover. You can help us by following these guidelines:

*   Follow [HackerOne's disclosure guidelines](https://www.hackerone.com/disclosure-guidelines).
... (9 lines truncated)
</file>

<file path="tsconfig.base.json">
{
	"compilerOptions": {
		"allowJs": true,
		"checkJs": true,
		"allowSyntheticDefaultImports": true,
		"jsx": "preserve",
		"target": "esnext",
		"module": "commonjs",
		"declaration": true,
		"declarationMap": true,
		"emitDeclarationOnly": false,
		"isolatedModules": true,

		/* Strict Type-Checking Options */
		"strict": true,

		/* Additional Checks */
		"noUnusedLocals": true,
		"noUnusedParameters": true,
		"noImplicitReturns": true,
		"noFallthroughCasesInSwitch": true,

		/* Module Resolution Options */
		"moduleResolution": "node",

		/* This needs to be false so our types are possible to consume without setting this */
		"esModuleInterop": false,
		"resolveJsonModule": true
	},

... (29 lines truncated)
</file>

</files>
