alerts/class-alert-type-ifttt.php

Summary

Maintainability
B
4 hrs
Test Coverage
F
14%
<?php
/**
 * If This Then That (IFTTT) Alert type.
 *
 * A user must create a IFTTT Maker account,
 * and get their Maker Key, found here:
 *
 * @link https://ifttt.com/maker
 * This will be used in the Stream Alert form.
 *
 * Next, they create a new recipe, using the
 * "Maker" > "Receive a web request" trigger.
 * @link https://ifttt.com/myrecipes/personal/new
 *
 * Here, they will enter a label for the event name.
 * This will be also need to be entered into the Stream Alert form.
 *
 * Finally, the Maker Key and Event Name need to be entered into
 * the Alert metabox.
 *
 * This class uses the above data to send at POST request to IFTTT,
 * which then hooks into whichever service the user has determined
 * in their Recipe.
 *
 * Notes:
 *
 * In their IFTTT recipe, the Task Content field "quicktags" are
 * defined as such in the unfiltered state of this Alert Type:
 *
 * {{EventName}} - The name the user assigned to this event.
 * {{Value1}} - The Record Summary
 * {{Value2}} - The User that triggered the alert
 * {{Value3}} - The date/time on which the alert was triggered.
 *
 * There are several filters in self::notify_ifttt() that
 * allow for complete customization of these values.
 *
 * More info:
 * @link https://ifttt.com/channels/maker/triggers/1636368624-receive-a-web-request
 *
 * @package WP_Stream
 */

namespace WP_Stream;

/**
 * Class Alert_Type_IFTTT
 *
 * @package WP_Stream
 */
class Alert_Type_IFTTT extends Alert_Type {

    /**
     * Alert type name
     *
     * @var string
     */
    public $name = 'IFTTT';

    /**
     * Alert type slug
     *
     * @var string
     */
    public $slug = 'ifttt';

    /**
     * Class Constructor
     *
     * @param Plugin $plugin Plugin object.
     */
    public function __construct( $plugin ) {
        parent::__construct( $plugin );
        $this->plugin = $plugin;
        if ( ! is_admin() ) {
            return;
        }
        add_filter(
            'wp_stream_alerts_save_meta',
            array(
                $this,
                'add_alert_meta',
            ),
            10,
            2
        );
    }

    /**
     * Record that the Alert was triggered by a Record.
     *
     * In self::post_class() this value is checked so we can determine
     * if the class should be added to the Record's display.
     *
     * @param int|string $record_id Record that triggered alert.
     * @param array      $recordarr Record details.
     * @param object     $alert Alert options.
     * @return void
     */
    public function alert( $record_id, $recordarr, $alert ) {
        $recordarr['ID'] = $record_id;
        $this->notify_ifttt( $alert, $recordarr );
    }

    /**
     * Displays a settings form for the alert type
     *
     * @param Alert $alert Alert object for the currently displayed alert.
     * @return void
     */
    public function display_fields( $alert ) {
        $alert_meta = array();
        if ( is_object( $alert ) ) {
            $alert_meta = $alert->alert_meta;
        }
        $options = wp_parse_args(
            $alert_meta,
            array(
                'maker_key'  => '',
                'event_name' => '',
            )
        );

        $form = new Form_Generator();

        echo '<span class="wp_stream_alert_type_description">';
        echo esc_html__( 'Trigger an IFTTT Maker recipe.', 'stream' );
        echo wp_kses_post( sprintf( ' (<a href="%1$s" target="_blank">%2$s</span></a>)', 'https://youtu.be/XFWtkHXv9h0', __( 'Tutorial', 'stream' ) ) );
        echo '</span>';
        echo '<label for="wp_stream_ifttt_maker_key"><span class="title">' . esc_html__( 'Maker Key', 'stream' ) . '</span>';
        echo '<span class="input-text-wrap">';
        echo $form->render_field(
            'text',
            array(
                'name'  => 'wp_stream_ifttt_maker_key',
                'title' => esc_attr( __( 'Maker Key', 'stream' ) ),
                'value' => $options['maker_key'],
            )
        ); // Xss ok.
        echo '</span>';
        printf(
            '<span class="input-text-wrap"><a href="%1$s" target="_blank">%2$s %3$s</a></span>',
            esc_url( 'https://ifttt.com/maker' ),
            esc_html__( 'Open IFTTT Maker Channel', 'stream' ),
            '<span class="dashicons dashicons-external"></span>'
        );
        echo '</label>';

        echo '<label for="wp_stream_ifttt_event_name"><span class="title">' . esc_html__( 'Event Name', 'stream' ) . '</span>';
        echo '<span class="input-text-wrap">';
        echo $form->render_field(
            'text',
            array(
                'name'  => 'wp_stream_ifttt_event_name',
                'title' => esc_attr( __( 'Event Name', 'stream' ) ),
                'value' => $options['event_name'],
            )
        );  // Xss ok.
        echo '</span>';
        printf(
            '<span class="input-text-wrap"><a href="%1$s" target="_blank">%2$s %3$s</a></span>',
            esc_url( 'https://ifttt.com/myrecipes/personal' ),
            esc_html__( 'Open IFTTT Recipes', 'stream' ),
            '<span class="dashicons dashicons-external"></span>'
        );
        echo '</label>';
    }

    /**
     * Validates and saves form settings for later use.
     *
     * @param Alert $alert Alert object for the currently displayed alert.
     * @return void
     */
    public function save_fields( $alert ) {
        check_admin_referer( 'save_alert', 'wp_stream_alerts_nonce' );
        $alert->alert_meta['maker_key'] = '';

        if ( ! empty( $_POST['wp_stream_ifttt_maker_key'] ) ) {
            $alert->alert_meta['maker_key'] = sanitize_text_field( wp_unslash( $_POST['wp_stream_ifttt_maker_key'] ) );
        }
        if ( ! empty( $_POST['wp_stream_ifttt_event_name'] ) ) {
            $alert->alert_meta['event_name'] = sanitize_text_field( wp_unslash( $_POST['wp_stream_ifttt_event_name'] ) );
        }
    }

    /**
     * Send a POST request to IFTTT.
     *
     * This method sends Record data to IFTTT for processing.
     *
     * There are several filters here (documented below) that
     * allow for customization of the data sent.
     *
     * Note that IFTTT only allows for three specifically-named
     * array keys of data.  (also documented below)
     *
     * @param object $alert The Alert object.
     * @param array  $recordarr Array of Record data.
     *
     * @return bool
     */
    public function notify_ifttt( $alert, $recordarr ) {
        if ( empty( $alert->alert_meta['maker_key'] ) || empty( $alert->alert_meta['event_name'] ) || empty( $recordarr ) ) {
            return false;
        }

        $record_data = wp_parse_args(
            $recordarr,
            array(
                /* translators: %s: the Event Name of the Alert (e.g. "Update a post") */
                'summary' => sprintf( __( 'The event %s was triggered' ), $alert->alert_meta['event_name'] ),
                'user_id' => get_current_user_id(),
                'created' => current_time( 'Y-m-d H:i:s' ),
                // Blog's local time.
            )
        );

        $user_id = $recordarr['user_id'];
        $user    = get_user_by( 'id', $user_id );

        /**
         * Filter User data field
         *
         * Defaults to 'user_login'.
         *
         * @param object $alert The Alert.
         * @param array  $recordarray The Record's data.
         * @return string
         */
        $user_field = apply_filters( 'wp_stream_alert_ifttt_user_data_value', 'user_login', $alert, $recordarr );
        $user_value = ! empty( $user->$user_field ) ? $user->$user_field : $user->user_login;

        $created = $recordarr['created'];
        /**
         * Filter the date format string
         *
         * Defaults to 'Y-m-d H:i:s'.
         *
         * @param object $alert The Alert.
         * @param array  $recordarray The Record's data.
         * @return string
         */
        $date_format = apply_filters( 'wp_stream_alert_ifttt_date_format', 'Y-m-d H:i:s', $alert, $recordarr );
        $date        = gmdate( $date_format, strtotime( $created ) );

        $url = 'https://maker.ifttt.com/trigger/' . $alert->alert_meta['event_name'] . '/with/key/' . $alert->alert_meta['maker_key'];

        /*
         * The array key labels for the request body are required by
         * IFTTT; their names cannot be changed.
         *
         * The filter defaults are set up to send:
         * value1 = Record Summary
         *
         * value2 = User login name
         * (see the wp_stream_alert_ifttt_user_data_value filter above)
         *
         * value3 = Record Date
         * (see the wp_stream_alert_ifttt_date_format filter above)
         *
         * The filters below allow complete customization of these data values.
         */
        $args = array(
            'headers' => array(
                'Content-Type' => 'application/json',
            ),
            'body'    => wp_json_encode(
                array(
                    /**
                     * Filter the first IFTTT alert value
                     *
                     * @param string $summary The Record's summary.
                     * @param object $alert The Alert.
                     * @param array  $recordarr Array of Record data.
                     * @return mixed
                     */
                    'value1' => apply_filters( 'wp_stream_alert_ifttt_value_one', $record_data['summary'], $alert, $recordarr ),

                    /**
                     * Filter the second IFTTT alert value
                     *
                     * @param string $user_value The user meta value requested above.
                     * @param int    $user_id The user ID who fired the Alert.
                     * @param object $alert The Alert.
                     * @param array  $recordarr Array of Record data.
                     * @return mixed
                     */
                    'value2' => apply_filters( 'wp_stream_alert_ifttt_value_two', $user_value, $user_id, $alert, $recordarr ),

                    /**
                     * Filter the third IFTTT alert value
                     *
                     * @param string $date The Record's date.
                     * @param object $alert The Alert.
                     * @param array  $recordarr Array of Record data.
                     * @return mixed
                     */
                    'value3' => apply_filters( 'wp_stream_alert_ifttt_value_three', $date, $alert, $recordarr ),
                )
            ),
        );

        $response = wp_remote_post( $url, $args );
        if ( ! is_array( $response ) ) {
            return false;
        }

        return true;
    }

    /**
     * Add alert meta if this is a highlight alert
     *
     * @param array  $alert_meta The metadata to be inserted for this alert.
     * @param string $alert_type The type of alert being added or updated.
     *
     * @return mixed
     */
    public function add_alert_meta( $alert_meta, $alert_type ) {
        if ( $this->slug === $alert_type ) {
            $maker_key = wp_stream_filter_input( INPUT_POST, 'wp_stream_ifttt_maker_key' );
            if ( ! empty( $maker_key ) ) {
                $alert_meta['maker_key'] = $maker_key;
            }
            $event_name = wp_stream_filter_input( INPUT_POST, 'wp_stream_ifttt_event_name' );
            if ( ! empty( $event_name ) ) {
                $alert_meta['event_name'] = $event_name;
            }
        }

        return $alert_meta;
    }
}