WC_SKU_Generator

Class WC_SKU_Generator Sets up the plugin and all of its admin methods.

Defined (1)

The class is defined in the following location(s).

/woocommerce-product-sku-generator.php  
  1. class WC_SKU_Generator { 
  2.  
  3.  
  4. const VERSION = '2.3.1'; 
  5.  
  6. /** @var WC_SKU_Generator single instance of this plugin */ 
  7. protected static $instance; 
  8.  
  9.  
  10. /** 
  11. * WC_SKU_Generator constructor. 
  12. * @since 2.0.0 
  13. */ 
  14. public function __construct() { 
  15.  
  16. // load translations 
  17. add_action( 'init', array( $this, 'load_translation' ) ); 
  18.  
  19. if ( is_admin() && ! is_ajax() ) { 
  20.  
  21. // add settings 
  22. add_filter( 'woocommerce_products_general_settings', array( $this, 'add_settings' ) ); 
  23. add_action( 'admin_print_scripts', array( $this, 'admin_js' ) ); 
  24.  
  25. // add plugin links 
  26. add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'add_plugin_links' ) ); 
  27.  
  28. // save the generated SKUs during product edit / bulk edit 
  29. add_action( 'woocommerce_product_bulk_edit_save', array( $this, 'maybe_save_sku' ) ); 
  30. add_action( 'woocommerce_process_product_meta', array( $this, 'maybe_save_sku' ), 100, 2 ); 
  31.  
  32. // disable SKU fields when being generated by the plugin 
  33. add_action( 'init', array( $this, 'maybe_disable_skus' ) ); 
  34.  
  35. // run every time 
  36. $this->install(); 
  37.  
  38.  
  39. /** Helper methods ***************************************/ 
  40.  
  41.  
  42. /** 
  43. * Main Sku Generator Instance, ensures only one instance is/can be loaded. 
  44. * @since 2.0.0 
  45. * @see wc_sku_generator() 
  46. * @return WC_SKU_Generator 
  47. */ 
  48. public static function instance() { 
  49. if ( is_null( self::$instance ) ) { 
  50. self::$instance = new self(); 
  51. return self::$instance; 
  52.  
  53.  
  54. /** 
  55. * Cloning instances is forbidden due to singleton pattern. 
  56. * @since 2.2.0 
  57. */ 
  58. public function __clone() { 
  59. /** translators: Placeholders: %s - plugin name */ 
  60. _doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'You cannot clone instances of %s.', 'woocommerce-product-sku-generator' ), 'WooCommerce Product SKU Generator' ), '2.2.0' ); 
  61.  
  62.  
  63. /** 
  64. * Unserializing instances is forbidden due to singleton pattern. 
  65. * @since 2.2.0 
  66. */ 
  67. public function __wakeup() { 
  68. /** translators: Placeholders: %s - plugin name */ 
  69. _doing_it_wrong( __FUNCTION__, sprintf( esc_html__( 'You cannot unserialize instances of %s.', 'woocommerce-product-sku-generator' ), 'WooCommerce Product SKU Generator' ), '2.2.0' ); 
  70.  
  71.  
  72. /** 
  73. * Adds plugin page links to the Plugins menu. 
  74. * @since 2.0.0 
  75. * @param array $links all plugin links 
  76. * @return array $links all plugin links + our custom links (i.e., "Settings") 
  77. */ 
  78. public function add_plugin_links( $links ) { 
  79.  
  80. $plugin_links = array( 
  81. '<a href="' . admin_url( 'admin.php?page=wc-settings&tab=products' ) . '">' . __( 'Configure', 'woocommerce-product-sku-generator' ) . '</a>',  
  82. '<a href="https://wordpress.org/plugins/woocommerce-product-sku-generator/faq/">' . __( 'FAQ', 'woocommerce-product-sku-generator' ) . '</a>',  
  83. '<a href="https://wordpress.org/support/plugin/woocommerce-product-sku-generator">' . __( 'Support', 'woocommerce-product-sku-generator' ) . '</a>',  
  84. ); 
  85.  
  86. return array_merge( $plugin_links, $links ); 
  87.  
  88.  
  89. /** 
  90. * Load Translations. 
  91. * @since 1.2.1 
  92. */ 
  93. public function load_translation() { 
  94. // localization 
  95. load_plugin_textdomain( 'woocommerce-product-sku-generator', false, dirname( plugin_basename( __FILE__ ) ) . '/i18n/languages' ); 
  96.  
  97.  
  98. /** 
  99. * Checks if WooCommerce is active. 
  100. * @since 2.2.0 
  101. * @return bool true if WooCommerce is active, false otherwise 
  102. */ 
  103. public static function is_woocommerce_active() { 
  104.  
  105. $active_plugins = (array) get_option( 'active_plugins', array() ); 
  106.  
  107. if ( is_multisite() ) { 
  108. $active_plugins = array_merge( $active_plugins, get_site_option( 'active_sitewide_plugins', array() ) ); 
  109.  
  110. return in_array( 'woocommerce/woocommerce.php', $active_plugins ) || array_key_exists( 'woocommerce/woocommerce.php', $active_plugins ); 
  111.  
  112.  
  113. /** 
  114. * Renders a notice when WooCommerce version is outdated. 
  115. * @since 2.2.0 
  116. */ 
  117. public static function render_outdated_wc_version_notice() { 
  118.  
  119. $message = sprintf( 
  120. /** translators: %1$s and %2$s are <strong> tags. %3$s and %4$s are <a> tags */ 
  121. esc_html__( '%1$sWooCommerce Product SKU Generator is inactive.%2$s This plugin requires WooCommerce 2.5 or newer. Please %3$supdate WooCommerce to version 2.5 or newer%4$s', 'woocommerce-product-sku-generator' ),  
  122. '<strong>',  
  123. '</strong>',  
  124. '<a href="' . admin_url( 'plugins.php' ) . '">',  
  125. ' »</a>' 
  126. ); 
  127.  
  128. printf( '<div class="error"><p>%s</p></div>', $message ); 
  129.  
  130.  
  131. /** Plugin methods ***************************************/ 
  132.  
  133.  
  134. /** 
  135. * Generate and save a simple / parent product SKU from the product slug or ID. 
  136. * @since 2.0.0 
  137. * @param \WC_Product $product WC_Product object 
  138. * @return string $parent_sku the generated string to use for the SKU 
  139. */ 
  140. protected function generate_product_sku( $product ) { 
  141.  
  142. switch( get_option( 'wc_sku_generator_simple' ) ) { 
  143.  
  144. case 'slugs': 
  145. $product_sku = urldecode( get_post( $product->get_id() )->post_name ); 
  146. break; 
  147.  
  148. case 'ids': 
  149. $product_sku = $product->get_id(); 
  150. break; 
  151.  
  152. // use the original product SKU if we're not generating it 
  153. default: 
  154. $product_sku = $product->get_sku(); 
  155.  
  156. /** 
  157. * Filters the generated SKU for simple or parent products. 
  158. * @since 2.0.0 
  159. * @param string $product_sku the generated SKU 
  160. * @param \WC_Product $product the product object 
  161. */ 
  162. return apply_filters( 'wc_sku_generator_sku', $product_sku, $product ); 
  163.  
  164.  
  165. /** 
  166. * Generate and save a product variation SKU using the product slug or ID. 
  167. * @since 2.0.0 
  168. * @param array $variation product variation data 
  169. * @return string $variation_sku the generated string to append for the variation's SKU 
  170. */ 
  171. protected function generate_variation_sku( $variation ) { 
  172.  
  173. if ( 'slugs' === get_option( 'wc_sku_generator_variation' ) ) { 
  174.  
  175. // replace spaces in attributes depending on settings 
  176. switch ( get_option( 'wc_sku_generator_attribute_spaces' ) ) { 
  177.  
  178. case 'underscore': 
  179. $variation['attributes'] = str_replace( ' ', '_', $variation['attributes'] ); 
  180. break; 
  181.  
  182. case 'dash': 
  183. $variation['attributes'] = str_replace( ' ', '-', $variation['attributes'] ); 
  184. break; 
  185.  
  186. case 'none': 
  187. $variation['attributes'] = str_replace( ' ', '', $variation['attributes'] ); 
  188. break; 
  189.  
  190.  
  191. /** 
  192. * Attributes in SKUs _could_ be sorted inconsistently in rare cases. 
  193. * Return true here to ensure they're always sorted consistently. 
  194. * @since 2.0.0 
  195. * @param bool $sort_atts true to force attribute sorting 
  196. * @see https://github.com/skyverge/woocommerce-product-sku-generator/pull/2 
  197. */ 
  198. if ( apply_filters( 'wc_sku_generator_force_attribute_sorting', false ) ) { 
  199. ksort( $variation['attributes'] ); 
  200.  
  201. /** 
  202. * Filters the separator used between variation attributes. 
  203. * @since 2.0.0 
  204. * @param string $separator the separator character 
  205. */ 
  206. $separator = apply_filters( 'wc_sku_generator_attribute_separator', $this->get_sku_separator() ); 
  207.  
  208. $variation_sku = implode( $variation['attributes'], $separator ); 
  209. $variation_sku = str_replace( 'attribute_', '', $variation_sku ); 
  210.  
  211. if ( 'ids' === get_option( 'wc_sku_generator_variation') ) { 
  212.  
  213. $variation_sku = $variation['variation_id']; 
  214.  
  215. /** 
  216. * Filters the generated variation portion of the SKU. 
  217. * @since 2.0.0 
  218. * @param string $variation_sku the generated variation portion of the SKU 
  219. * @param array $variation product variation data 
  220. */ 
  221. return apply_filters( 'wc_sku_generator_variation_sku', $variation_sku, $variation ); 
  222.  
  223.  
  224. /** 
  225. * Update the product with the generated SKU. 
  226. * @since 2.0.0 
  227. * @param \WC_Product|int $product WC_Product object or product ID 
  228. */ 
  229. public function maybe_save_sku( $product ) { 
  230.  
  231. // Checks to ensure we have a product and gets one if we have an ID 
  232. if ( is_numeric( $product ) ) { 
  233. $product = wc_get_product( absint( $product ) ); 
  234.  
  235. // Generate the SKU for simple / external / variable parent products 
  236. $product_sku = $this->generate_product_sku( $product ); 
  237.  
  238. // Only generate / save variation SKUs when we should 
  239. if ( $product->is_type( 'variable' ) && 'never' !== get_option( 'wc_sku_generator_variation' ) ) { 
  240.  
  241. $variations = $this->get_all_variations( $product->get_id() ); 
  242.  
  243. foreach ( $variations as $variation_id ) { 
  244.  
  245. $product_variation = wc_get_product( $variation_id ); 
  246. $variation = $product->get_available_variation( $product_variation ); 
  247.  
  248. $variation_sku = $this->generate_variation_sku( $variation ); 
  249. $sku = $product_sku . $this->get_sku_separator() . $variation_sku; 
  250.  
  251. /** 
  252. * Filters the entire generated SKU for a variable product. 
  253. * @since 2.0.0 
  254. * @param string $sku the complete generated SKU 
  255. * @param string $product_sku the portion of the SKU for the parent product 
  256. * @param string $variation_sku the portion of the SKU for the variation 
  257. */ 
  258. $sku = apply_filters( 'wc_sku_generator_variation_sku_format', $sku, $product_sku, $variation_sku ); 
  259.  
  260. update_post_meta( $variation_id, '_sku', $sku ); 
  261.  
  262. // Save the SKU for simple / external / parent products if we should 
  263. if ( 'never' !== get_option( 'wc_sku_generator_simple' ) ) { 
  264. update_post_meta( $product->get_id(), '_sku', $product_sku ); 
  265.  
  266.  
  267. /** 
  268. * Disable SKUs if they're being generated by the plugin. 
  269. * TODO: update the get_post_meta call to use a product CRUD method when WC 3.0 is required {BR 2017-03-21} 
  270. * @since 1.0.2 
  271. */ 
  272. public function maybe_disable_skus() { 
  273.  
  274. if ( 'never' !== get_option( 'wc_sku_generator_simple' ) ) { 
  275.  
  276. // temporarily disable SKUs 
  277. function wc_sku_generator_disable_parent_sku_input() { 
  278. add_filter( 'wc_product_sku_enabled', '__return_false' ); 
  279. add_action( 'woocommerce_product_write_panel_tabs', 'wc_sku_generator_disable_parent_sku_input' ); 
  280.  
  281. // Create a custom SKU label for Product Data 
  282. function wc_sku_generator_create_sku_label() { 
  283. global $thepostid; 
  284.  
  285. ?><p class="form-field"><label><?php esc_html_e( 'SKU', 'woocommerce-product-sku-generator' ); ?></label><span><?php echo esc_html( get_post_meta( $thepostid, '_sku', true ) ); ?></span></p><?php 
  286.  
  287. add_filter( 'wc_product_sku_enabled', '__return_true' ); 
  288. add_action( 'woocommerce_product_options_sku', 'wc_sku_generator_create_sku_label' ); 
  289.  
  290.  
  291. // TODO {BR 2015-08-10}: maybe disable variations SKU fields if being generated? 
  292. // likely needs purely js solution 
  293.  
  294.  
  295. /** 
  296. * Add SKU generator to Settings > Products page at the end of the 'Product Data' section. 
  297. * @since 1.0.0 
  298. * @param array $settings the WooCommerce product settings 
  299. * @return array $updated_settings updated array with our settings added 
  300. */ 
  301. public function add_settings( $settings ) { 
  302.  
  303. $updated_settings = array(); 
  304.  
  305. foreach ( $settings as $setting ) { 
  306.  
  307. $updated_settings[] = $setting; 
  308.  
  309. if ( isset( $setting['id'] ) && 'product_measurement_options' === $setting['id'] && 'sectionend' === $setting['type'] ) { 
  310.  
  311. $updated_settings = array_merge( $updated_settings, $this->get_settings() ); 
  312.  
  313. return $updated_settings; 
  314.  
  315.  
  316. /** 
  317. * Create SKU Generator settings. 
  318. * @since 1.2.0 
  319. * @return array $wc_sku_generator_settings plugin settings 
  320. */ 
  321. protected function get_settings() { 
  322.  
  323. $wc_sku_generator_settings = array( 
  324.  
  325. array( 
  326. 'title' => __( 'Product SKUs', 'woocommerce-product-sku-generator' ),  
  327. 'type' => 'title',  
  328. 'id' => 'product_sku_options' 
  329. ),  
  330.  
  331. array( 
  332. 'title' => __( 'Generate Simple / Parent SKUs:', 'woocommerce-product-sku-generator' ),  
  333. 'desc' => '<br />' . __( 'Generating simple / parent SKUs disables the SKU field while editing products.', 'woocommerce-product-sku-generator' ),  
  334. 'id' => 'wc_sku_generator_simple',  
  335. 'type' => 'select',  
  336. 'options' => array( 
  337. 'never' => __( 'Never (let me set them)', 'woocommerce-product-sku-generator' ),  
  338. 'slugs' => __( 'Using the product slug (name)', 'woocommerce-product-sku-generator' ),  
  339. 'ids' => __( 'Using the product ID', 'woocommerce-product-sku-generator' ),  
  340. ),  
  341. 'default' => 'slugs',  
  342. 'class' => 'wc-enhanced-select chosen_select',  
  343. 'css' => 'min-width:300px;',  
  344. 'desc_tip' => __( 'Determine how SKUs for simple, external, or parent products will be generated.', 'woocommerce-product-sku-generator' ),  
  345. ),  
  346.  
  347. array( 
  348. 'title' => __( 'Generate Variation SKUs:', 'woocommerce-product-sku-generator' ),  
  349. 'desc' => __( 'Determine how SKUs for product variations will be generated.', 'woocommerce-product-sku-generator' ),  
  350. 'id' => 'wc_sku_generator_variation',  
  351. 'type' => 'select',  
  352. 'options' => array( 
  353. 'never' => __( 'Never (let me set them)', 'woocommerce-product-sku-generator' ),  
  354. 'slugs' => __( 'Using the attribute slugs (names)', 'woocommerce-product-sku-generator' ),  
  355. 'ids' => __( 'Using the variation ID', 'woocommerce-product-sku-generator' ),  
  356. ),  
  357. 'default' => 'slugs',  
  358. 'class' => 'wc-enhanced-select chosen_select',  
  359. 'css' => 'min-width:300px;',  
  360. 'desc_tip' => true,  
  361. ),  
  362.  
  363. array( 
  364. 'title' => __( 'Replace spaces in attributes?', 'woocommerce-product-sku-generator' ),  
  365. /** translators: placeholders are <strong> tags */ 
  366. 'desc' => '<br />' . sprintf( __( '%1$sWill update existing variation SKUs when product is saved if they contain spaces%2$s.', 'woocommerce-product-sku-generator' ), '<strong>', '</strong>' ),  
  367. 'id' => 'wc_sku_generator_attribute_spaces',  
  368. 'type' => 'select',  
  369. 'options' => array( 
  370. 'no' => __( 'Do not replace spaces in attribute names.', 'woocommerce-product-sku-generator' ),  
  371. 'underscore' => __( 'Replace spaces with underscores', 'woocommerce-product-sku-generator' ),  
  372. 'dash' => __( 'Replace spaces with dashes / hyphens', 'woocommerce-product-sku-generator' ),  
  373. 'none' => __( 'Remove spaces from attribute names', 'woocommerce-product-sku-generator' ),  
  374. ),  
  375. 'default' => 'no',  
  376. 'class' => 'wc-enhanced-select chosen_select',  
  377. 'css' => 'min-width:300px;',  
  378. 'desc_tip' => __( 'Replace spaces in attribute names when used in a SKU.', 'woocommerce-product-sku-generator' ),  
  379. ),  
  380.  
  381. array( 
  382. 'type' => 'sectionend',  
  383. 'id' => 'product_sku_options' 
  384. ),  
  385.  
  386. ); 
  387.  
  388. return $wc_sku_generator_settings; 
  389.  
  390.  
  391. /** 
  392. * Manually get all variations for a product because WC core functions only 
  393. * give us "published" variations, and out of stock ones are "private". *_* 
  394. * @since 2.3.0 
  395. * @param int $product_id the ID for the parent product 
  396. * @return array IDs of all variations for the product 
  397. */ 
  398. protected function get_all_variations( $product_id ) { 
  399.  
  400. /** 
  401. * Filters variation query args to get variations for a variable product. 
  402. * @since 2.3.0 
  403. * @param array $args get_posts args 
  404. */ 
  405. $args = apply_filters( 'wc_sku_generator_variation_query_args', array( 
  406. 'post_parent' => $product_id,  
  407. 'post_type' => 'product_variation',  
  408. 'orderby' => 'menu_order',  
  409. 'order' => 'ASC',  
  410. 'fields' => 'ids',  
  411. 'post_status' => array( 'publish', 'private' ),  
  412. 'numberposts' => -1,  
  413. ) ); 
  414.  
  415. return get_posts( $args ); 
  416.  
  417.  
  418. /** 
  419. * Get the separator to use between parent / variation SKUs, along with variation attributes. 
  420. * @since 2.3.0 
  421. * @return string $separator the separator character 
  422. */ 
  423. private function get_sku_separator() { 
  424.  
  425. /** 
  426. * Filters the separator used between parent / variation SKUs or between variation attributes 
  427. * @since 2.3.0 
  428. * @param string $separator the separator character 
  429. */ 
  430. return apply_filters( 'wc_sku_generator_sku_separator', '-' ); 
  431.  
  432.  
  433. /** 
  434. * Hides the "replace spaces in attributes" setting if slugs are not used for variation SKUs. 
  435. * @since 2.1.0 
  436. */ 
  437. public function admin_js() { 
  438. global $current_section; 
  439.  
  440. $current_page = isset( $_GET['page'] ) ? $_GET['page'] : ''; 
  441. $current_tab = isset( $_GET['tab'] ) ? $_GET['tab'] : ''; 
  442.  
  443. if ( 'wc-settings' === $current_page && 'products' === $current_tab && empty( $current_section ) ) { 
  444. wc_enqueue_js( 
  445. "jQuery(document).ready(function() { 
  446.  
  447. jQuery( 'select#wc_sku_generator_variation' ).change( function() { 
  448. if ( jQuery( this ).val() === 'slugs' ) { 
  449. jQuery( this ).closest('tr').next('tr').show(); 
  450. } else { 
  451. jQuery( this ).closest('tr').next('tr').hide(); 
  452. }).change(); 
  453.  
  454. });" 
  455. ); 
  456.  
  457.  
  458. /** Lifecycle methods ***************************************/ 
  459.  
  460.  
  461. /** 
  462. * Run every time. Used since the activation hook is not executed when updating a plugin. 
  463. * @since 2.0.0 
  464. */ 
  465. private function install() { 
  466.  
  467. // get current version to check for upgrade 
  468. $installed_version = get_option( 'wc_sku_generator_version' ); 
  469.  
  470. // force upgrade to 2.0.0, prior versions did not have version option set 
  471. if ( ! $installed_version ) { 
  472. $this->upgrade( '1.2.2' ); 
  473.  
  474. // upgrade if installed version lower than plugin version 
  475. if ( -1 === version_compare( $installed_version, self::VERSION ) ) { 
  476. $this->upgrade( $installed_version ); 
  477.  
  478. // install defaults for settings 
  479. foreach( $this->get_settings() as $setting ) { 
  480.  
  481. if ( isset( $setting['default'] ) && ! get_option( $setting['id'] ) ) { 
  482. update_option( $setting['id'], $setting['default'] ); 
  483.  
  484.  
  485. /** 
  486. * Perform any version-related changes. 
  487. * @since 2.0.0 
  488. * @param int $installed_version the currently installed version of the plugin 
  489. */ 
  490. private function upgrade( $installed_version ) { 
  491.  
  492. // upgrade from 1.2.2 to 2.0.0 
  493. if ( '1.2.2' === $installed_version ) { 
  494.  
  495. switch ( get_option( 'wc_sku_generator_select' ) ) { 
  496.  
  497. case 'all': 
  498. update_option( 'wc_sku_generator_simple', 'slugs' ); 
  499. update_option( 'wc_sku_generator_variation', 'slugs' ); 
  500. break; 
  501.  
  502. case 'simple': 
  503. update_option( 'wc_sku_generator_simple', 'slugs' ); 
  504. update_option( 'wc_sku_generator_variation', 'never' ); 
  505. break; 
  506.  
  507. case 'variations': 
  508. update_option( 'wc_sku_generator_simple', 'never' ); 
  509. update_option( 'wc_sku_generator_variation', 'slugs' ); 
  510. break; 
  511.  
  512.  
  513. // Delete the old option now that we've upgraded 
  514. delete_option( 'wc_sku_generator_select' ); 
  515.  
  516. // Upgrade to version 2.2.0, this setting was only available in 2.1.0 
  517. if ( '2.1.0' === $installed_version ) { 
  518.  
  519. if ( 'yes' === get_option( 'wc_sku_generator_attribute_spaces' ) ) { 
  520. update_option( 'wc_sku_generator_attribute_spaces', 'underscore' ); 
  521.  
  522. // update the installed version option 
  523. update_option( 'wc_sku_generator_version', self::VERSION ); 
  524.  
  525.