@@ -539,6 +539,10 @@ public function load_background_sync_process() {
539
539
'wp_ajax_ajax_fb_background_check_queue ' ,
540
540
[ $ this , 'ajax_fb_background_check_queue ' ]
541
541
);
542
+ add_action (
543
+ 'wp_ajax_fb_dismiss_unmapped_attributes_banner ' ,
544
+ [ $ this , 'ajax_dismiss_unmapped_attributes_banner ' ]
545
+ );
542
546
}
543
547
544
548
/**
@@ -1734,9 +1738,88 @@ public function display_batch_api_completed( $post ) {
1734
1738
$ this ->get_product_catalog_id () .
1735
1739
'/products/" target="_blank">View product on Meta catalog</a> '
1736
1740
);
1741
+
1742
+ // Display unmapped attributes banner if there are any
1743
+ $ this ->display_unmapped_attributes_banner ( $ fb_product ->woo_product );
1744
+ }
1745
+ }
1746
+
1747
+ /**
1748
+ * Displays a banner for unmapped attributes encouraging users to use the attribute mapper.
1749
+ *
1750
+ * @param \WC_Product $product The product object
1751
+ * @return void
1752
+ */
1753
+ public function display_unmapped_attributes_banner ( \WC_Product $ product ) {
1754
+ // Check if this feature should be shown
1755
+ if ( ! $ this ->should_show_unmapped_attributes_banner () ) {
1756
+ return ;
1757
+ }
1758
+
1759
+ // Get unmapped attributes using the ProductAttributeMapper
1760
+ if ( ! class_exists ( '\WooCommerce\Facebook\ProductAttributeMapper ' ) ) {
1761
+ return ;
1737
1762
}
1763
+
1764
+ $ unmapped_attributes = \WooCommerce \Facebook \ProductAttributeMapper::get_unmapped_attributes ( $ product );
1765
+
1766
+ // Only show if there are unmapped attributes
1767
+ if ( empty ( $ unmapped_attributes ) ) {
1768
+ return ;
1769
+ }
1770
+
1771
+ $ count = count ( $ unmapped_attributes );
1772
+ $ attribute_names = array_column ( $ unmapped_attributes , 'name ' );
1773
+ $ attribute_list = implode ( ', ' , array_slice ( $ attribute_names , 0 , 3 ) );
1774
+ if ( $ count > 3 ) {
1775
+ $ attribute_list .= sprintf ( __ ( ' and %d more ' , 'facebook-for-woocommerce ' ), $ count - 3 );
1776
+ }
1777
+
1778
+ // Build the mapper URL
1779
+ $ mapper_url = add_query_arg (
1780
+ array (
1781
+ 'page ' => 'wc-facebook ' ,
1782
+ 'tab ' => 'product-attributes '
1783
+ ),
1784
+ admin_url ( 'admin.php ' )
1785
+ );
1786
+
1787
+ $ message = sprintf (
1788
+ /* translators: %1$s - attribute list, %2$d - count, %3$s - link start, %4$s - link end */
1789
+ _n (
1790
+ '%3$sAttribute "%1$s" is not mapped to Meta.%4$s Use the %3$sattribute mapper%4$s to map this attribute and improve your product visibility in Meta ads. ' ,
1791
+ '%3$s%2$d attributes (%1$s) are not mapped to Meta.%4$s Use the %3$sattribute mapper%4$s to map these attributes and improve your product visibility in Meta ads. ' ,
1792
+ $ count ,
1793
+ 'facebook-for-woocommerce '
1794
+ ),
1795
+ $ attribute_list ,
1796
+ $ count ,
1797
+ '<a href=" ' . esc_url ( $ mapper_url ) . '" target="_blank"> ' ,
1798
+ '</a> '
1799
+ );
1800
+
1801
+ // Store the message with a specific prefix to identify it
1802
+ $ banner_message = self ::FB_ADMIN_MESSAGE_PREPEND . $ message ;
1803
+ set_transient (
1804
+ 'facebook_plugin_unmapped_attributes_info ' ,
1805
+ $ banner_message ,
1806
+ self ::FB_MESSAGE_DISPLAY_TIME
1807
+ );
1738
1808
}
1739
1809
1810
+ /**
1811
+ * Determines if the unmapped attributes banner should be shown.
1812
+ *
1813
+ * @return bool
1814
+ */
1815
+ private function should_show_unmapped_attributes_banner () {
1816
+ // Only show to users who can manage WooCommerce
1817
+ if ( ! current_user_can ( 'manage_woocommerce ' ) ) {
1818
+ return false ;
1819
+ }
1820
+
1821
+ return true ;
1822
+ }
1740
1823
1741
1824
/**
1742
1825
* Checks the feed upload status (FBE v1.0).
@@ -2161,6 +2244,27 @@ public function ajax_delete_fb_product() {
2161
2244
wp_die ();
2162
2245
}
2163
2246
2247
+ /**
2248
+ * AJAX handler for dismissing the unmapped attributes banner.
2249
+ *
2250
+ * @return void
2251
+ */
2252
+ public function ajax_dismiss_unmapped_attributes_banner () {
2253
+ // Check permissions
2254
+ if ( ! current_user_can ( 'manage_woocommerce ' ) ) {
2255
+ wp_die ( -1 , 403 );
2256
+ }
2257
+
2258
+ // Check nonce
2259
+ check_ajax_referer ( 'fb_dismiss_unmapped_attributes_banner ' );
2260
+
2261
+ // Clear the transient (but don't set permanent user meta)
2262
+ // This way the banner will show again next time there are unmapped attributes
2263
+ delete_transient ( 'facebook_plugin_unmapped_attributes_info ' );
2264
+
2265
+ wp_die ();
2266
+ }
2267
+
2164
2268
/**
2165
2269
* Special function to run all visible products through on_product_publish
2166
2270
*
@@ -2841,6 +2945,39 @@ public function maybe_display_facebook_api_messages() {
2841
2945
echo $ this ->get_message_html ( $ sticky_msg , 'info ' );
2842
2946
// transient must be deleted elsewhere, or wait for timeout
2843
2947
}
2948
+
2949
+ // Display unmapped attributes banner
2950
+ $ unmapped_attributes_msg = get_transient ( 'facebook_plugin_unmapped_attributes_info ' );
2951
+ if ( $ unmapped_attributes_msg && $ this ->should_show_unmapped_attributes_banner () ) {
2952
+ // Add a dismiss button to the message
2953
+ $ dismiss_message = $ unmapped_attributes_msg . ' <button type="button" class="notice-dismiss" onclick="fbDismissUnmappedAttributesBanner(event)" title=" ' . esc_attr__ ( 'Dismiss this notice. ' , 'facebook-for-woocommerce ' ) . '"><span class="screen-reader-text"> ' . esc_html__ ( 'Dismiss this notice. ' , 'facebook-for-woocommerce ' ) . '</span></button> ' ;
2954
+
2955
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2956
+ echo $ this ->get_message_html ( $ dismiss_message , 'info ' );
2957
+
2958
+ // Include JavaScript for dismiss functionality
2959
+ ?>
2960
+ <script type="text/javascript">
2961
+ function fbDismissUnmappedAttributesBanner(event) {
2962
+ // Make AJAX request to dismiss the banner
2963
+ var xhr = new XMLHttpRequest();
2964
+ xhr.open('POST', '<?php echo esc_url ( admin_url ( 'admin-ajax.php ' ) ); ?> ', true);
2965
+ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2966
+ xhr.onload = function() {
2967
+ if (xhr.status === 200) {
2968
+ // Hide the notice immediately
2969
+ var notice = event.target.closest('.notice');
2970
+ if (notice) {
2971
+ notice.style.display = 'none';
2972
+ }
2973
+ }
2974
+ };
2975
+ xhr.send('action=fb_dismiss_unmapped_attributes_banner&_wpnonce=<?php echo esc_attr ( wp_create_nonce ( 'fb_dismiss_unmapped_attributes_banner ' ) ); ?> ');
2976
+ }
2977
+ </script>
2978
+ <?php
2979
+ delete_transient ( 'facebook_plugin_unmapped_attributes_info ' );
2980
+ }
2844
2981
}
2845
2982
2846
2983
/**
0 commit comments