5
votes

hi and thanks for stopping by. i am currently writing a plugin for wordpress. i need a button inside a certain page, that triggers an email-notification. i figured it would be good to use the woocommerce email functionality, since it is a customer email and i'd like to use the woocommerce-email-templates, too.

in my plugin i include my class extension via

function add_wc_custom_email( $email_classes ) {
    require( 'includes/class-wc-custom-email.php' );
    $email_classes['WC_Custom_Email'] = new WC_Custom_Email();

    return $email_classes;
}
add_filter( 'woocommerce_email_classes', 'add_wc_custom_email' );
//if i write a print_r(something) inside this function, just to alert if this filters hits, i don't see a result, so i think the error is here.. the filter gets hit under woocommerce->settings->emails but not, if you simply load a page in the backend 

in the file class-wc-custom-email.php i have my class extension

class WC_Custom_Email extends WC_Email {
    public function __construct() {
        …
    }
    public function mail( $var1, $var2, $var3 ) {
        …
    }
}

my ajax looks like this

( function( $ ) {
    $('#button1').on( "click", function() {
        $.post(
            ajaxurl,
            {
                'action' : 'jnz_email_custom',
                'page_id': '<?php the_ID(); ?>',
            },
            function ( response ) {
                console.log( "triggered", response )
            }
        );
    });
})(jQuery);

the ajax handler looks like this

add_action('wp_ajax_jnz_email_custom', 'jnz_email_custom');
function jnz_email_custom() {
    $message = email_custom( $_POST['page_id'] );
    $response = array(
        'what'   => 'email_custom_triggered',
        'action' => 'email custom triggered',
        'id'     => $_POST['page_id'],
        'data'   => $message,
    );
    $xmlResponse = new WP_Ajax_Response( $response );
    $xmlResponse->send();
}

the function that i trigger with ajax

function email_custom( $page_id = 2728 ) {
    $field = get_field( 'something', $page_id )[0];
    //get_field() is a function by plugin 'Advanced Custom Fields' and works fine

    function somethingSomething( $field ) {
        …
        return $results;
    }

    foreach ( $results as $result ) :
        $email = new WC_Custom_Email();
        $email->mail( $result['details']['name'], $result['details']['email'], $result['something'] );
    endforeach;

    return json_encode( $results, JSON_UNESCAPED_UNICODE );
    //this is the $xmlResponse i get from the ajax call and looks fine (but only works, if i uncomment the 'new WC_Custom_Email()' stuff. otherwise i see the "Fatal Error" thingy)
}

the response is: Fatal error: Class 'WC_Custom_Email' not found in …

all the functions work fine, if i return the $results i see all i want and get no errors.

same is, when i change it to new WC_Email(). so my guess is, that the woocommerce functionality isn't loaded into my admin->edit_page_xy screen. so the big question is: how would i load the woocommerce functionality (or only the email-functionality) into my plugin..??

hope this is somewhat clear and makes any sense. i only know little php and am completely new to oop.

1
Presumably it means that your ajax callback is being fired before WooCommerce's files are loaded. I would start with this tutorial on how to add a custom email.helgatheviking
yeah, i followed this tut :) but the page is fully loaded, i am in the edit screen and i think that, since woocommerce isn't required there, its functionality isn't even loaded.. no?honk31
Ok, then you should post the rest of your WC_Custom_Email class. Where's the trigger? Why do you need to override the mail() method? What's your AJAX look like? And your AJAX callback? Please edit your question in lieu of trying to post code in the comments.helgatheviking
@helgatheviking please have another look, i edited the question. i guess the class itself isn't neccessary here, since i'm not even getting that far..honk31
See monster answer below. :)helgatheviking

1 Answers

8
votes

Ok, so this was a bit of a beast.

I've written a demo plugin with the following structure:

kia-ajax-email.php
- includes
  -- class-wc-test-ajax-email.php
-- js
   -- script.js
-- templates
   -- emails
      -- test.php
      -- plain
         -- test.php

The main plugin file kia-ajax-email.php

This file is responsible for enqueuing the script, adding your custom email class, creating a button on the single product page, and registering an action as one that triggers a WooCommerce email:

<?php
/**
 * Plugin Name: Test Ajax Email
 * Plugin URI: http://stackoverflow.com/q/35018177/383847
 * Description: Demo plugin for sending email via ajax
 * Author: helgatheviking
 * Author URI: http://www.kathyisawesome.com
 * Version: 0.1
 *
 * License: GNU General Public License v3.0
 * License URI: http://www.gnu.org/licenses/gpl-3.0.html
 *
 */

if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly


/**
 *  get plugin path
 *
 * @since 0.1
 */
function kia_ajax_email_plugin_path(){
    return untrailingslashit( plugin_dir_path( __FILE__ ) ); 
}

/**
 *  Add a custom email to the list of emails WooCommerce should load
 *
 * @since 0.1
 * @param array $email_classes available email classes
 * @return array filtered available email classes
 */
function kia_add_custom_email( $email_classes ) {

    // include our custom email class
    require_once( 'includes/class-wc-test-ajax-email.php' );

    // add the email class to the list of email classes that WooCommerce loads
    $email_classes['WC_Test_Ajax_Email'] = new WC_Test_Ajax_Email();

    return $email_classes;

}
add_filter( 'woocommerce_email_classes', 'kia_add_custom_email' );


/**
 *  Enqueue the scripts with apprpriate vars
 *
 * @since 0.1
 */
function kia_ajax_email_js(){
    wp_enqueue_script( 'kia_ajax_email', plugins_url( 'js/script.js', __FILE__ ), array('jquery'), '1.0.0', true );
    wp_localize_script( 'kia_ajax_email', 'kia_ajax_email', array( 
                'ajax_url'                  => WC()->ajax_url(),
                'wc_ajax_url'               => WC_AJAX::get_endpoint( "test_email" ) ) );
}
add_action( 'wp_enqueue_scripts', 'kia_ajax_email_js', 20 );


/**
 *  AJAX callback
 *
 * @since 0.1
 */
function kia_ajax_email_callback() {
    $mailer = WC()->mailer();

    do_action( 'kia_trigger_ajax_email' );

    die('ajax finished'); // this is required to terminate immediately and return a proper response
}
add_action( 'wc_ajax_test_email', 'kia_ajax_email_callback' );


/**
 *  Register action as one that sends emails
 *
 * @since 0.1
 */
function kia_ajax_email_action( $actions ){
    $actions[] = 'kia_trigger_ajax_email';
    return $actions;
}
add_action( 'woocommerce_email_actions', 'kia_ajax_email_action' );


/**
 *  Add a dummy button to product page
 *
 * @since 0.1
 */
function kia_ajax_email_button(){
    echo '<button class="email-trigger">' . __( 'Email Trigger', 'kia-ajax-email' ). '</button>';
}
add_action('woocommerce_before_single_product_summary', 'kia_ajax_email_button');

The email class includes/class-wc-test-ajax-email.php

<?php

if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

/**
 * A custom Expedited Order WooCommerce Email class
 *
 * @since 0.1
 * @extends \WC_Email
 */
class WC_Test_Ajax_Email extends WC_Email {


    /**
     * Set email defaults
     *
     * @since 0.1
     */
    public function __construct() {

        // set ID, this simply needs to be a unique name
        $this->id = 'wc_text_ajax_email';

        // this is the title in WooCommerce Email settings
        $this->title = 'Test Ajax';

        // this is the description in WooCommerce email settings
        $this->description = 'Text emails are sent when ajax button is clicked';

        // these are the default heading and subject lines that can be overridden using the settings
        $this->heading = 'Test Ajax';
        $this->subject = 'Test Ajax';

        // these define the locations of the templates that this email should use, we'll just use the new order template since this email is similar
        $this->template_html  = 'emails/test.php';
        $this->template_plain = 'emails/plain/test.php';

        // Trigger on new paid orders
        add_action( 'kia_trigger_ajax_email', array( $this, 'trigger' ) );

        // Call parent constructor to load any other defaults not explicity defined here
        parent::__construct();

        // this sets the recipient to the settings defined below in init_form_fields()
        $this->recipient = $this->get_option( 'recipient' );

        // if none was entered, just use the WP admin email as a fallback
        if ( ! $this->recipient )
            $this->recipient = get_option( 'admin_email' );
    }


    /**
     * Determine if the email should actually be sent and setup email merge variables
     *
     * @since 0.1
     * @param int $order_id
     */
    public function trigger() {

        if ( ! $this->is_enabled() || ! $this->get_recipient() )
            return;

        // woohoo, send the email!
        $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
    }


    /**
     * get_content_html function.
     *
     * @since 0.1
     * @return string
     */
    public function get_content_html() {
        return wc_get_template_html( $this->template_html, array(
            'email_heading' => $this->get_heading(),
            'sent_to_admin' => false,
            'plain_text'    => false,
            'email'         => $this
        ),
        '',
        kia_ajax_email_plugin_path() . "/templates/" );
    }


    /**
     * get_content_plain function.
     *
     * @since 0.1
     * @return string
     */
    public function get_content_plain() {
        return wc_get_template_html( $this->template_plain, array(
            'email_heading' => $this->get_heading(),
            'sent_to_admin' => false,
            'plain_text'    => false,
            'email'         => $this
        ),
        '',
        kia_ajax_email_plugin_path() . "/templates/" );
    }


    /**
     * Initialize Settings Form Fields
     *
     * @since 2.0
     */
    public function init_form_fields() {

        $this->form_fields = array(
            'enabled'    => array(
                'title'   => 'Enable/Disable',
                'type'    => 'checkbox',
                'label'   => 'Enable this email notification',
                'default' => 'yes'
            ),
            'recipient'  => array(
                'title'       => 'Recipient(s)',
                'type'        => 'text',
                'description' => sprintf( 'Enter recipients (comma separated) for this email. Defaults to <code>%s</code>.', esc_attr( get_option( 'admin_email' ) ) ),
                'placeholder' => '',
                'default'     => ''
            ),
            'subject'    => array(
                'title'       => 'Subject',
                'type'        => 'text',
                'description' => sprintf( 'This controls the email subject line. Leave blank to use the default subject: <code>%s</code>.', $this->subject ),
                'placeholder' => '',
                'default'     => ''
            ),
            'heading'    => array(
                'title'       => 'Email Heading',
                'type'        => 'text',
                'description' => sprintf( __( 'This controls the main heading contained within the email notification. Leave blank to use the default heading: <code>%s</code>.' ), $this->heading ),
                'placeholder' => '',
                'default'     => ''
            ),
            'email_type' => array(
                'title'       => 'Email type',
                'type'        => 'select',
                'description' => 'Choose which format of email to send.',
                'default'     => 'html',
                'class'       => 'email_type',
                'options'     => array(
                    'plain'     => __( 'Plain text', 'woocommerce' ),
                    'html'      => __( 'HTML', 'woocommerce' ),
                    'multipart' => __( 'Multipart', 'woocommerce' ),
                )
            )
        );
    }


} // end \WC_Test_Ajax_Email class

the script js/script.js

jQuery(document).ready(function($) {

  $(".email-trigger").on("click", function(e) {

    e.preventDefault();

    $.ajax({
        url: kia_ajax_email.wc_ajax_url.toString(),
        type: 'POST',
        data: {
          'whatever': 1234
        },
      })
      .done(function(data) {
        if (console && console.log) {
          console.log(data);
        }
      });
  });

});

The email templates. first templates/emails/test.php and templates/emails/plain/test.php

<?php
/**
 * Test email
 *
 * This template can be overridden by copying it to yourtheme/woocommerce/emails/test.php.
 *
 * HOWEVER, on occasion WooCommerce will need to update template files and you (the theme developer).
 * will need to copy the new files to your theme to maintain compatibility. We try to do this.
 * as little as possible, but it does happen. When this occurs the version of the template file will.
 * be bumped and the readme will list any important changes.
 *
 * @see         http://docs.woothemes.com/document/template-structure/
 * @author      WooThemes
 * @package     WooCommerce/Templates/Emails
 * @version     2.5.0
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * @hooked WC_Emails::email_header() Output the email header
 */
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>

<p><?php _e( 'A test email is being sent', 'kia-ajax-email' ); ?></p>


<?php
/**
 * @hooked WC_Emails::email_footer() Output the email footer
 */
do_action( 'woocommerce_email_footer', $email );

and templates/emails/plain/test.php

<?php
/**
 * Test email
 *
 * This template can be overridden by copying it to yourtheme/woocommerce/emails/plain/test.php.
 *
 * HOWEVER, on occasion WooCommerce will need to update template files and you (the theme developer).
 * will need to copy the new files to your theme to maintain compatibility. We try to do this.
 * as little as possible, but it does happen. When this occurs the version of the template file will.
 * be bumped and the readme will list any important changes.
 *
 * @see         http://docs.woothemes.com/document/template-structure/
 * @author      WooThemes
 * @package     WooCommerce/Templates/Emails
 * @version     2.5.0
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}


echo "= " . $email_heading . " =\n\n";

echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n";


_e( 'A test email is being sent', 'kia-ajax-email' );

echo "\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n";

echo apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text' ) );

Going forward

This sends an email when a button is clicked. You will need to modify where that button goes, and because it is kind of slow (or seems so on my local setup) I would definitely recommend some kind of spinner/notification that the action is happening. You'll also need to customize what data is sent via ajax and how that ends up in the templates. This is just a proof of concept.