' . esc_html__( 'Google Merchant feed settings. Leave fields empty to use WooCommerce data and automatic detection.', '3dl-product-feed-for-google' ) . '
'; }, 'tdl_gmc_page' ); add_settings_section( 'tdl_gmc_ids', __( 'Product identifiers', '3dl-product-feed-for-google' ), function () { echo '' . esc_html__( 'The plugin checks the built-in WooCommerce GTIN first, then common meta keys, and finally your custom keys.', '3dl-product-feed-for-google' ) . '
'; }, 'tdl_gmc_page' ); add_settings_section( 'tdl_gmc_filters', __( 'Item filters', '3dl-product-feed-for-google' ), function () { echo '' . esc_html__( 'An empty field means no restriction. These filters apply only to the Google feed.', '3dl-product-feed-for-google' ) . '
'; }, 'tdl_gmc_page' ); add_settings_field( 'tdl_gmc_brand_name', __( 'Default brand / manufacturer', '3dl-product-feed-for-google' ), [ __CLASS__, 'field_brand' ], 'tdl_gmc_page', 'tdl_gmc_general' ); add_settings_field( 'tdl_gmc_brand_use_site_name', __( 'Use store name as fallback', '3dl-product-feed-for-google' ), [ __CLASS__, 'field_site_brand' ], 'tdl_gmc_page', 'tdl_gmc_general' ); add_settings_field( 'tdl_gmc_feed_channel_description', __( 'Feed description', '3dl-product-feed-for-google' ), [ __CLASS__, 'field_description' ], 'tdl_gmc_page', 'tdl_gmc_general' ); add_settings_field( 'tdl_gmc_gtin_keys', __( 'Custom GTIN/EAN meta keys', '3dl-product-feed-for-google' ), [ __CLASS__, 'field_gtin' ], 'tdl_gmc_page', 'tdl_gmc_ids' ); add_settings_field( 'tdl_gmc_mpn_keys', __( 'Custom MPN meta keys', '3dl-product-feed-for-google' ), [ __CLASS__, 'field_mpn' ], 'tdl_gmc_page', 'tdl_gmc_ids' ); add_settings_field( 'tdl_gmc_use_sku_as_mpn', __( 'Use SKU as MPN', '3dl-product-feed-for-google' ), [ __CLASS__, 'field_sku_mpn' ], 'tdl_gmc_page', 'tdl_gmc_ids' ); add_settings_field( 'tdl_gmc_filter_flags', __( 'Basic exclusions', '3dl-product-feed-for-google' ), [ __CLASS__, 'field_filter_flags' ], 'tdl_gmc_page', 'tdl_gmc_filters' ); add_settings_field( 'tdl_gmc_filter_weights', __( 'Allowed weights / volumes', '3dl-product-feed-for-google' ), [ __CLASS__, 'field_weights' ], 'tdl_gmc_page', 'tdl_gmc_filters' ); add_settings_field( 'tdl_gmc_filter_cat_include', __( 'Include only categories', '3dl-product-feed-for-google' ), [ __CLASS__, 'field_cat_include' ], 'tdl_gmc_page', 'tdl_gmc_filters' ); add_settings_field( 'tdl_gmc_filter_cat_exclude', __( 'Exclude categories', '3dl-product-feed-for-google' ), [ __CLASS__, 'field_cat_exclude' ], 'tdl_gmc_page', 'tdl_gmc_filters' ); add_settings_field( 'tdl_gmc_filter_skus', __( 'Include only SKUs', '3dl-product-feed-for-google' ), [ __CLASS__, 'field_skus' ], 'tdl_gmc_page', 'tdl_gmc_filters' ); add_settings_field( 'tdl_gmc_filter_price', __( 'Price including tax – min / max', '3dl-product-feed-for-google' ), [ __CLASS__, 'field_price' ], 'tdl_gmc_page', 'tdl_gmc_filters' ); } private static function register_text( string $name ): void { register_setting( 'tdl_gmc_group', $name, [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => '' ] ); } private static function register_area( string $name ): void { register_setting( 'tdl_gmc_group', $name, [ 'type' => 'string', 'sanitize_callback' => static function ( $v ): string { return is_string( $v ) ? sanitize_textarea_field( $v ) : ''; }, 'default' => '' ] ); } private static function register_bool( string $name, bool $default ): void { register_setting( 'tdl_gmc_group', $name, [ 'type' => 'boolean', 'sanitize_callback' => static function ( $v ): bool { return ! empty( $v ); }, 'default' => $default ] ); } public static function field_brand(): void { echo ''; echo '' . esc_html__( 'Fallback for products without their own brand. The plugin can read WooCommerce Brands and common brand attributes.', '3dl-product-feed-for-google' ) . '
'; } public static function field_site_brand(): void { echo ''; echo ''; } public static function field_description(): void { echo ''; } public static function field_gtin(): void { echo ''; echo '' . esc_html__( 'Optional. Enter custom meta keys separated by commas or new lines.', '3dl-product-feed-for-google' ) . '
'; } public static function field_mpn(): void { echo ''; echo '' . esc_html__( 'Optional. Enter custom meta keys separated by commas or new lines.', '3dl-product-feed-for-google' ) . '
'; } public static function field_sku_mpn(): void { echo ''; echo ''; } public static function field_filter_flags(): void { echo ''; echo '' . esc_html__( 'One allowed selling quantity per line, for example 50g, 250g, 1kg or 500ml.', '3dl-product-feed-for-google' ) . '
'; } public static function field_cat_include(): void { echo ''; echo '' . esc_html__( 'Category slug or category ID, one per line.', '3dl-product-feed-for-google' ) . '
'; } public static function field_cat_exclude(): void { echo ''; echo '' . esc_html__( 'Category slug or category ID, one per line.', '3dl-product-feed-for-google' ) . '
'; } public static function field_skus(): void { echo ''; echo '' . esc_html__( 'One allowed SKU per line.', '3dl-product-feed-for-google' ) . '
'; } public static function field_price(): void { echo ' '; echo ''; } public static function menu(): void { add_menu_page( __( '3DL Google Feed', '3dl-product-feed-for-google' ), __( '3DL Google Feed', '3dl-product-feed-for-google' ), THREEDL_GMC_CAP, 'tdl-gmc-lite', [ __CLASS__, 'render' ], 'dashicons-media-spreadsheet', 56 ); } public static function render(): void { if ( ! current_user_can( THREEDL_GMC_CAP ) ) return; echo '' . wp_kses_post( sprintf( __( 'The PRO version adds Zboží.cz, Heureka.cz, Google custom labels and licensed automatic updates. Learn more at %s.', '3dl-product-feed-for-google' ), '3DragonLabs.com' ) ) . '
'; echo '' . esc_html( $message ) . '
' . esc_html__( 'How the feed works', '3dl-product-feed-for-google' ) . '
'; echo '' . esc_html__( 'These rules help prevent the feed from containing items that Google Merchant Center would reject immediately.', '3dl-product-feed-for-google' ) . '
'; echo 'Google: ' . esc_html( $url ) . '
' . esc_html__( 'Cache:', '3dl-product-feed-for-google' ) . ' ' . esc_html( $cache ) . '
'; echo '' . esc_html__( 'Regenerate feed & diagnostics', '3dl-product-feed-for-google' ) . ' '; echo '' . esc_html__( 'Clear feed cache', '3dl-product-feed-for-google' ) . '
'; } private static function render_diagnostics(): void { $stats = Feed_Cache::instance()->stats_info( 'xml' ); echo '' . esc_html__( 'No diagnostics are available yet. Regenerate the feed to calculate included and skipped items.', '3dl-product-feed-for-google' ) . '
'; return; } $candidates = isset( $stats['candidates'] ) ? (int) $stats['candidates'] : 0; $included = isset( $stats['included'] ) ? (int) $stats['included'] : 0; $skipped = isset( $stats['skipped'] ) ? (int) $stats['skipped'] : max( 0, $candidates - $included ); echo '' . esc_html( sprintf( __( 'Counts reflect the feed generated on %s.', '3dl-product-feed-for-google' ), wp_date( 'Y-m-d H:i:s', (int) $stats['generated_at'] ) ) ) . '
'; } $reasons = isset( $stats['reasons'] ) && is_array( $stats['reasons'] ) ? $stats['reasons'] : []; if ( ! $reasons ) return; $labels = self::diagnostic_labels(); arsort( $reasons ); echo '| ' . esc_html__( 'Reason', '3dl-product-feed-for-google' ) . ' | ' . esc_html__( 'Items', '3dl-product-feed-for-google' ) . ' |
|---|---|
| ' . esc_html( $label ) . ' | ' . esc_html( number_format_i18n( (int) $count ) ) . ' |