Skip to content

Instantly share code, notes, and snippets.

@devinsays
Last active February 17, 2024 22:58
Show Gist options
  • Save devinsays/9e6030dec131366d2eadca4174f82d57 to your computer and use it in GitHub Desktop.
Save devinsays/9e6030dec131366d2eadca4174f82d57 to your computer and use it in GitHub Desktop.
WP CLI script for generating coupon copies
<?php
/**
* Generate coupon copies from an existing coupon.
* Replaces UNQCODE with a unique generated coupon code.
*
* For more information about this script:
* https://devpress.com/wp-cli-script-to-duplicate-woocommerce-coupons/
*
* wp eval-file coupon-generator.php
*/
// Quick explainer of script.
WP_CLI::log( "\nThis script generates copies of an existing coupon code." );
WP_CLI::log( "If 'UNQCODE' is in the coupon code, it will be replaced with a unique code.\n" );
$code = devpress_ask( 'Coupon code to duplicate:' );
// Get the coupon ID to copy.
$coupon_id = wc_get_coupon_id_by_code( $code );
if ( ! $coupon_id ) {
WP_CLI::error( 'Coupon code not found.' );
exit;
}
WP_CLI::success( "Coupon ID $coupon_id found." );
// Get number of coupons to generate.
WP_CLI::log( '' );
$count = (int) devpress_ask( 'How coupons would you like to generate:' );
if ( ! $count || $count < 1 ) {
WP_CLI::error( 'Must enter a number value 1 or higher.' );
exit;
}
WP_CLI::log( '' );
if ( $count > 100 ) {
WP_CLI::log( '' );
WP_CLI::confirm( "Are you sure you want to generate $count coupons?" );
}
// Log file to write to.
$log_file = $code . '-generated-' . current_time( 'timestamp' ) . '.csv';
// Output for CLI table.
$output = [];
for ( $i = 1; $i <= $count; $i++ ) {
$duplicate = devpress_generate_duplicate_coupon( $coupon_id );
if ( ! $duplicate ) {
WP_CLI::error( "Coupon $i of $count failed to generate." );
exit;
}
WP_CLI::success( "$i/$count: {$duplicate->get_code()}" );
$url = get_site_url() . '/' . $duplicate->get_meta( '_wc_url_coupons_unique_url' );
$output[] = [
'code' => $duplicate->get_code(),
'url' => $url,
];
devpress_write_file(
$log_file,
[ $duplicate->get_code(), $url ]
);
}
// Output table of all generated coupons.
WP_CLI::log( '' );
WP_CLI\Utils\format_items( 'table', $output, [ 'code', 'url' ] );
WP_CLI::log( '' );
WP_CLI::success( "$count coupons generated." );
WP_CLI::log( "Log file: $log_file" );
WP_CLI::log( '' );
/**
* Generates a duplicate coupon.
*
* Based on `product_duplicate` in:
* woocommerce/includes/admin/class-wc-admin-duplicate-product.php
*
* @param int $id Original coupon ID.
* @return WC_Coupon $duplicate New coupon object.
*/
function devpress_generate_duplicate_coupon( $id ) {
$original = new WC_Coupon( $id );
$duplicate = clone $original;
// Reset ID and date properties.
$duplicate->set_id( 0 );
$duplicate->set_date_created( null );
// Updates the coupon code.
$code = $original->get_code();
$generated_key = devpress_generate_unique_coupon_key( $code );
$new_code = $generated_key;
if ( stripos( $code, 'UNQCODE' ) !== false ) {
$new_code = str_ireplace( 'UNQCODE', $generated_key, $code );
}
$duplicate->set_code( $new_code );
// Replace URL.
$url_meta_key = '_wc_url_coupons_unique_url';
$url = $original->get_meta( $url_meta_key );
if ( stripos( $url, 'UNQCODE' ) !== false ) {
// Assume code in the URL is the same pattern.
$new_url = str_ireplace( 'UNQCODE', $generated_key, $url );
$duplicate->update_meta_data( $url_meta_key, $new_url );
}
$duplicate->save();
// Update the active coupons option, hook into \WC_URL_Coupons.
if ( class_exists( 'WC_URL_Coupons' ) ) {
$options = [
'coupon_id' => $duplicate->get_id(),
'unique_url' => $duplicate->get_meta( $url_meta_key ),
'url_prefix' => '',
'redirect_page' => $duplicate->get_meta( '_wc_url_coupons_redirect_page' ),
'redirect_page_type' => $duplicate->get_meta( '_wc_url_coupons_redirect_page_type' ),
'product_ids' => $duplicate->get_meta( '_wc_url_coupons_product_ids' ),
'defer_apply' => $duplicate->get_meta( '_wc_url_coupons_defer_apply' ),
];
$coupons_admin = \WC_URL_Coupons::instance()->get_admin_instance();
$coupons_admin->update_coupons( $options );
}
return $duplicate;
}
/**
* Generates a unique coupon code.
*
* @param string $code Existing coupon code.
* @return string $generated_key
*/
function devpress_generate_unique_coupon_key( $code ) {
// Loops until a unique coupon code is generated.
while ( true ) {
$generated_key = devpress_generate_coupon_key();
$new_code = $generated_key;
if ( stripos( $code, 'UNQCODE' ) !== false ) {
$new_code = str_ireplace( 'UNQCODE', $generated_key, $code );
}
// Check if code already exists before returning.
$coupon_id = wc_get_coupon_id_by_code( $new_code );
if ( ! $coupon_id ) {
return $generated_key;
}
}
}
/**
* Generates a random key string for unique coupons.
*
* Doesn't use ambiguous characters like: 0 o i l 1.
*
* @param int $length
* @return string
*/
function devpress_generate_coupon_key( $length = 7 ) {
$chars = 'abcdefghjkmnpqrstuvwxyz23456789';
$coupon_key = '';
$chars_length = strlen( $chars );
for ( $i = 0; $i < $length; $i++ ) {
$coupon_key .= substr( $chars, wp_rand( 0, $chars_length - 1 ), 1 );
}
return $coupon_key;
}
/**
* Ask a question and returns the user's input.
*
* @param string $question
* @param bool $case_sensitive
*
* @return string
*/
function devpress_ask( $question, $case_sensitive = false ) {
fwrite( STDOUT, trim( $question ) . ' ' );
$answer = trim( fgets( STDIN ) );
$answer = $case_sensitive ? $answer : strtolower( $answer );
return $answer;
}
/**
* Writes output to a csv file.
*
* @param string $file_name
* @param array $output
*/
function devpress_write_file( $file_name, $output ) {
$file_resource = fopen( $file_name, 'a' );
fputcsv( $file_resource, $output );
fclose( $file_resource );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment