Plugin Directory

Changeset 1461017


Ignore:
Timestamp:
07/26/2016 07:55:02 PM (10 years ago)
Author:
cycles
Message:

1.5

July 26th, 2016

  • New: Invite users via email to view designs
  • New: Receive notifications for new comments
  • New: Receive notifications for approvals
  • Enhanced: Design list includes approval status and comment count
  • Fixed: Date/Time changed from UTC to "local time" as defined by your WordPress settings
  • Tested: 4.5.3
Location:
design-feedback
Files:
5 added
11 edited

Legend:

Unmodified
Added
Removed
  • design-feedback/trunk/README.txt

    r1318125 r1461017  
    33Tags: design, feedback, mockup, client, wireframe, approvals, design review, comment, webdesign, freelancer, studio, agency, graphic designers, graphics, image, logo, mood boards, infographics, project, cycles, approval, sign-off
    44Requires at least: 4.0
    5 Tested up to: 4.4
    6 Stable tag: 1.4.1
     5Tested up to: 4.5.3
     6Stable tag: 1.5
    77License: GPLv2 or later
    88
     
    1111== Description ==
    1212
    13 [Cycles](http://getCycles.io/) allows you to share any design (mockups, wireframes, sitemaps) without the complexity of email attachments or third-party services.  Clients and colleagues view your work in their browser and post feedback directly on your designs.  When they're ready, they approve designs so the project can move to the next phase.
    14 
    15 * **Simple, Secure Sharing** - Upload any design (mockups, moodboards, wireframes, etc) and share with your clients. They'll only need the URL (and optional password) to view and make comments.  No attachments or accounts required.
    16 
    17 * **Design Feedback** - Clients view mockups in their browser, and click directly on the design to comment. Feedback remains organized, eliminating back and forth emails and miscommunication.
    18 
    19 * **On-The-Record Approvals** - When you've made requested changes, your client approves the design by agreeing to terms and providing a digital signature.  The time, date, and name of the approver are recorded.
     13[Cycles](https://getCycles.io/) allows you to share any design (mockups, wireframes, sitemaps) with clients and colleagues, who view your work in their browser and post feedback directly on your designs.
     14
     15Cycles is a simple plugin to:
     16
     17* **Share designs with anyone** - Upload any design (mockups, moodboards, wireframes, etc) and share with your clients. They'll only need the URL (and optional password) to view and make comments.  No attachments or accounts required.
     18
     19* **Collect design feedback** - Clients view mockups in their browser, and click directly on the design to comment. Feedback remains organized, eliminating back and forth emails and miscommunication.
     20
     21* **Record approvals/sign off** - When you've made requested changes, your client approves the design by agreeing to terms and providing a digital signature.  The time, date, and name of the approver are recorded.
     22
     23* **Keep project members informed** - When you publish a design, let Cycles send an email invitation with access details and instructions, and configure instant email notifications for new comments and approvals.
     24
     25* **Import design feedback into 3rd party services** - Connect your designs to Trello, Basecamp, Asana, Slack, Help Scout, or any 3rd party service with project based email addresses, to bring Cycles feedback and approvals into your team's project management workflow.
    2026
    2127[youtube https://www.youtube.com/watch?v=1nhIQH9IHVE]
    2228
    23 > ####No longer making mockups?  Join our Web Developer Beta
     29> ####No longer making mockups?  Our Web Developer Beta is now active
    2430> Many of the "designers" we speak with are moving **from** creating mockups in Photoshop and Illustrator **to** starting projects with themes and designing straight in the browser.
    2531>
    26 > So, we're working on a version of Cycles that **collects feedback and approvals on WordPress web pages and sites**.
     32> We've launched a beta version of Cycles that **collects feedback and approvals on any web page**, launching Summer 2016.
    2733>
    2834> If that sounds useful to you, please join our beta!
    29 > Get more info at [https://getCycles.io](https://getcycles.io/#beta).
     35> Get more info at [https://getCycles.io](https://getcycles.io/) and read about our [beta announcement](https://blog.getcycles.io/cycles-beta-begins-for-visual-feedback-and-approvals-6e027af53067).
    3036
    3137#### Features
    3238
    33 **NEW: Approvals & Digital Signatures**
     39**NEW: Email Invites & Notifications**
     40Send your client an invitation to review your newly published design, directly from Cycles.  Then, when someone makes a comment or provides their approval, get notified at the email address(es) of your choosing. Note: As Cycles relies on the `wp_mail()` WordPress function, this feature requires your web server/host to have email correctly configured, or the use of a plugin like [Postman-SMTP](https://wordpress.org/plugins/postman-smtp).
     41
     42**NEW: 3rd party integration**
     43Enter project-specific email addresses in the notification section to send new comments and approvals directly to many 3rd party services like Trello, Basecamp, Asana, Slack, and Help Scout.
     44
     45**Approvals & Digital Signatures**
    3446When a client is ready to “sign off,” they approve designs by agreeing to terms and providing their digital signature for the system to record.
    3547
    36 **NEW: Custom Design URL _and_ Slug**
     48**Custom Design URL _and_ Slug**
    3749Make sharing easier with custom, client friendly and easy to pronounce URLs. Now including the path/slug.
    3850
     
    4658Organize designs in the WordPress media library for quick sorting and searching.
    4759
    48 
    4960**Password Protection**
    5061Set optional passwords to keep designs private and secure from unwanted visitors.
     
    5768
    5869#### Follow Cycles
    59 [Blog](http://getCycles.io/blog/) | [Twitter](http://twitter.com/getCycles)
     70[Blog](https://blog.getCycles.io/) | [Twitter](https://twitter.com/getCycles)
    6071
    6172== Installation ==
     
    70812. Clients approve designs with their digital signature
    71823. Password protect your designs to protect client privacy
    72 4. View feedback and approvals directly on the design or in aggregate
     834. View feedback and approvals directly on the design or in aggregate, plus email invites and comment/approval notifications
    7384
    7485== Frequently Asked Questions ==
     
    104115== Change Log ==
    105116
     117= 1.5 =
     118July 26th, 2016
     119* New: Invite users via email to view designs
     120* New: Receive notifications for new comments
     121* New: Receive notifications for approvals
     122* Enhanced: Design list includes approval status and comment count
     123* Fixed: Date/Time changed from UTC to "local time" as defined by your WordPress settings
     124* Tested: 4.5.3
     125
    106126= 1.4.1 =
    107127December 29th, 2015
    108 
    109128* Enhanced: Clients can view approval details on designs by hovering over the approval button
    110129* Enhanced: Approval confirmation dialog look and feel
     
    117136= 1.4 =
    118137November 30th, 2015
    119 
    120138* New: Enable approvals on your design so your clients complete the feedback process and move to the next phase.
    121139* New: Custom slug (in Cycles > Settings) for fully customizable URLs
     
    123141= 1.3.2 =
    124142November 10th, 2015
    125 
    126143* Enhanced: Now load all external scripts via HTTPS
    127144* Fixed: Issue with saving comments containing special characters
     
    130147= 1.3 =
    131148November 8th, 2015
    132 
    133149* Enhanced: Feedback name is pre-populated for faster commenting
    134150* Enhanced: Better open/close click behavior when viewing comments
     
    144160
    145161Mockup Presentation
    146 
    147162* New: Redesigned loading and design presentation and layout, so your mockups look their best
    148163* New: Help section for frequently asked questions
     
    151166
    152167Feedback Rewrite
    153 
    154168* New: Feedback code rewrite and redesign, so leaving feedback is faster and more intuitive
    155169* New: View state for feedback
     
    158172
    159173Other
    160 
    161174* Tested: Compatible with WordPress 4.3.1
    162175
     
    187200== Upgrade Notice ==
    188201
    189 = 1.4.1 =
    190 Bug fixes and minor enhancements
     202= 1.5 =
     203Email notifications and usability enhancements
  • design-feedback/trunk/addons/approvals/index.php

    r1318107 r1461017  
    140140            <span>Approved</span>
    141141            <div class="cycles-feedback-info">
    142                 Approved on <br /><?php echo stripslashes(date('F j, Y',strtotime($meta['approved_at']))); ?> <br /> by <?php echo stripslashes($meta['approved_by'])?>
     142                Approved on <br /><?php echo date(get_option( 'date_format' ),(strtotime($meta['approved_at'])  + (get_option( 'gmt_offset' ) * HOUR_IN_SECONDS)) ); ?> <?php echo date(get_option( 'time_format' ),(strtotime($meta['approved_at'])  + (get_option( 'gmt_offset' ) * HOUR_IN_SECONDS)) ); ?> <br /> by <?php echo stripslashes($meta['approved_by'])?>
    143143            </div>
    144144        </div>   
     
    256256            if ( $approved['by'] ) {
    257257                $datetime = strtotime( esc_html( $approved['at'] ) );
    258                 $date = date( get_option( 'date_format' ), $datetime );
    259                 $time = date( get_option( 'time_format' ), $datetime );
     258                $date = date(get_option( 'date_format' ),($datetime  + (get_option( 'gmt_offset' ) * HOUR_IN_SECONDS)) );
     259                $time = date(get_option( 'time_format' ),($datetime  + (get_option( 'gmt_offset' ) * HOUR_IN_SECONDS)) );
     260               
    260261                printf('<div id="cycles_approval_details">Approved on %s at %s by %s</div>'
    261262                    , esc_html( $date )
  • design-feedback/trunk/addons/settings/index.php

    r1297129 r1461017  
    66    const SLUG = 'settings_addon';
    77    const VERSION = '0.1';
    8    
     8
    99    private $addon_dir_path;
    1010    private $addon_url;
    1111    private $classes_directory_url;
    12    
     12
    1313    public $tabs = array(
    14         'general'=>'General'
     14        'general'=>'General',
     15        'emails'=>'Emails',
    1516    );
    1617
     
    2223        $this->classes_directory_url = $this->addon_dir_path . 'classes/';
    2324
    24         $loader = new Design_Feedback_Loader;
     25        /*$loader = new Design_Feedback_Loader;
    2526
    2627        $loader->add_action( 'admin_menu', $this, 'add_plugin_settings_page' );
     
    2829        $loader->add_action( 'init', $this, 'override_slug',11 );
    2930        $loader->add_filter( 'plugin_action_links_' . plugin_basename(DESIGNFEEDBACK_BASEFILE), $this, 'admin_links' );
    30         $loader->run();
    31 
     31        $loader->run();*/
     32
     33        add_action( 'admin_menu', array(&$this, 'add_plugin_settings_page') );
     34        add_action( 'admin_init', array(&$this, 'register_addon_options') );
     35        add_action( 'init', array(&$this, 'override_slug'),11 );
     36        add_filter( 'plugin_action_links_' . plugin_basename(DESIGNFEEDBACK_BASEFILE), array(&$this, 'admin_links') );
     37
     38        add_action("cycles_settings_set_tabs",array(&$this,'cycles_settings_set_tabs'));
     39        add_action("cycles_settings_generate_tabs_head",array(&$this,'generate_tabs_header'));
     40        add_action("cycles_settings_generate_tabs_data",array(&$this,'generate_tabs_data'));
    3241    }
    3342
     
    3645        return $links;
    3746    }
    38    
     47
    3948    public function add_plugin_settings_page() {
    4049        add_submenu_page( 'edit.php?post_type=designfeedback', 'Settings', 'Settings', 'manage_options', 'cycles_settings', array(&$this,'settings_page' ));
     
    4251
    4352    public function settings_page() {
    44         if ( isset ( $_GET['tab'] ) && !empty($_GET['tab'])) {
    45             $this->settings_tabs($_GET['tab']);
    46         } else {
    47             $this->settings_tabs();
    48         };
    49     }
    50 
    51     public function settings_tabs($current = 'license') {
    52        
     53        do_action("cycles_settings_set_tabs",array($this->tabs));
     54        do_action("cycles_settings_generate_tabs_head");
     55        do_action("cycles_settings_generate_tabs_data");
     56
     57    }
     58
     59    public function cycles_settings_set_tabs($array) {
     60        $tabs = $this->tabs;
     61
     62    }
     63    public function generate_tabs_header() {
     64        $current = isset ( $_GET['tab'] ) ? $_GET['tab'] : "general";
     65        ob_start();
    5366        echo '<div id="icon-themes" class="icon32"><br></div>';
    5467        echo '<h2 class="nav-tab-wrapper">';
     
    5972        }
    6073        echo '</h2>';
    61 
     74        $header = ob_get_contents();
     75        ob_end_clean();
     76
     77        echo $header;
     78    }
     79
     80    public function generate_tabs_data() {
     81
     82        $current = isset ( $_GET['tab'] ) ? $_GET['tab'] : "";
     83        ob_start();
    6284        switch($current) {
    6385            case 'general':
    6486                $this->general_tab();
    6587                break;
     88            case 'emails':
     89                $this->emails_tab();
     90                break;
    6691            default:
    6792                $this->general_tab();
    6893                break;
    6994        }
     95        $data = ob_get_contents();
     96        ob_end_clean();
     97
     98        echo $data;
     99
     100
    70101    }
    71102
     
    76107        ?>
    77108        <div class="wrap">
    78         <h2><?php _e('Custom Slug'); ?></h2>
    79         <form method="post" action="options.php">
    80 
    81             <?php settings_fields('cycles_settings'); ?>
    82             <?php wp_nonce_field( 'cycles_license_nonce', 'cycles_license_nonce' ); ?>
    83             <table class="form-table">
    84                 <tbody>
    85                     <tr valign="top">
     109            <h2><?php _e('Custom Slug'); ?></h2>
     110            <form method="post" action="options.php">
     111
     112                <?php settings_fields('cycles_settings'); ?>
     113                <?php wp_nonce_field( 'cycles_license_nonce', 'cycles_license_nonce' ); ?>
     114                <table class="form-table">
     115                    <tbody>
     116                        <tr valign="top">
     117                            <th scope="row" valign="top">
     118                                <label class="description" for="cycles_plugin_slug"><?php _e('Custom Slug'); ?></label>
     119                            </th>
     120                            <td>
     121                                <?php echo get_site_url(); ?>/
     122                                <input id="cycles_plugin_slug" name="cycles_plugin_slug" type="text" class="regular-text" value="<?php esc_attr_e( $slug ); ?>" />
     123
     124                            </td>
     125                        </tr>
     126                        <!--<tr valign="top">
    86127                        <th scope="row" valign="top">
    87                             <label class="description" for="cycles_plugin_slug"><?php _e('Custom Slug'); ?></label>
     128                        <label class="description" for="cycles_plugin_approval_terms"><?php _e('Custom Approval Terms'); ?></label>
    88129                        </th>
    89130                        <td>
    90                             <?php echo get_site_url(); ?>/
    91                             <input id="cycles_plugin_slug" name="cycles_plugin_slug" type="text" class="regular-text" value="<?php esc_attr_e( $slug ); ?>" />
     131                        <textarea id="cycles_plugin_approval_terms" name="cycles_plugin_approval_terms" type="text" class="regular-text" cols="80" rows="10"><?php esc_attr_e( $cycles_plugin_approval_terms ); ?></textarea>
    92132
    93133                        </td>
    94                     </tr>
    95                     <!--<tr valign="top">
    96                         <th scope="row" valign="top">
    97                             <label class="description" for="cycles_plugin_approval_terms"><?php _e('Custom Approval Terms'); ?></label>
    98                         </th>
    99                         <td>
    100                             <textarea id="cycles_plugin_approval_terms" name="cycles_plugin_approval_terms" type="text" class="regular-text" cols="80" rows="10"><?php esc_attr_e( $cycles_plugin_approval_terms ); ?></textarea>
    101 
    102                         </td>
    103                     </tr> -->
    104                 </tbody>
    105             </table>
    106             <?php submit_button(); ?>
    107 
    108         </form>
     134                        </tr> -->
     135                    </tbody>
     136                </table>
     137                <?php submit_button(); ?>
     138
     139            </form>
     140        </div>
    109141        <?php
    110142    }
    111143
     144    public function emails_tab() {
     145        $name = get_option('cycles_plugin_email_from_name','Cycles Admin');
     146        $address = get_option('cycles_plugin_email_from_address');
     147        $error = false;
     148       
     149        if($_POST && isset($_POST['send-test-email']) && $_POST['send-test-email'] == 1) {
     150            $error['class'] = "error";
     151            if(isset($_POST['cycles_plugin_email_test_address']) && filter_var($_POST['cycles_plugin_email_test_address'], FILTER_VALIDATE_EMAIL)) {
     152                $body = $this->test_email_body();
     153                $to = $_POST['cycles_plugin_email_test_address'];
     154               
     155                $subject  = "Cycles Test Email";
     156                $headers  = "MIME-Version: 1.0" . "\r\n";
     157                $headers .= "Content-type: text/html; charset=".get_bloginfo('charset')."" . "\r\n";
     158                $headers .= "From: ".$name." <".$address.">" . "\r\n";
     159               
     160                if(!empty($address) && !empty($name)) {
     161                    $mail = wp_mail($to,$subject,$body,$headers);
     162                    if($mail) {
     163                        $error['msg'] = "Successfully sent test email";
     164                        $error['class'] = "success";
     165                    } else {
     166                        $extrainfo = "";
     167                        global $phpmailer;
     168                        if (  ( $phpmailer instanceof PHPMailer ) ) {
     169                            $extrainfo = $phpmailer->ErrorInfo;
     170                        }
     171                        $error['msg'] = "Internal error, email could not be sent. ".$extrainfo ;
     172                    }
     173                } else {
     174                    $error['msg'] = '"From Name" and "From Address" fields are required.';
     175                }
     176            } else {
     177                $error['msg'] = "Invalid Email Address";
     178            }
     179        }
     180        ?>
     181        <div class="wrap">
     182            <h2><?php _e('Email Settings'); ?></h2>
     183            <?php
     184                if($_POST && $error !== "false") {
     185                   ?>
     186                   <div class="notice notice-<?php echo $error['class'] ?>"><p><?php echo $error['msg']?></p></div>
     187                   <?php
     188                }
     189                ?>
     190            <form method="post" action="options.php" autocomplete="false">
     191               
     192                <?php settings_fields('cycles_settings_email'); ?>
     193                <?php wp_nonce_field( 'cycles_license_nonce', 'cycles_license_nonce' ); ?>
     194                <table class="form-table">
     195                    <tbody>
     196                        <tr valign="top">
     197                            <th scope="row" valign="top">
     198                                <label class="description" for="cycles_plugin_email_from_name"><?php _e('From Name:'); ?></label>
     199                            </th>
     200                            <td>
     201                                <input id="cycles_plugin_email_from_name" name="cycles_plugin_email_from_name" type="text" class="regular-text" value="<?php esc_attr_e( $name ); ?>" />
     202
     203                            </td>
     204                        </tr>
     205                        <tr valign="top">
     206                            <th scope="row" valign="top">
     207                                <label class="description" for="cycles_plugin_email_from_address"><?php _e('From Address:'); ?></label>
     208                            </th>
     209                            <td>
     210                                <input id="cycles_plugin_email_from_address" name="cycles_plugin_email_from_address" type="email" class="regular-text" value="<?php esc_attr_e( $address ); ?>" />
     211
     212                            </td>
     213                        </tr>
     214                    </tbody>
     215                </table>
     216                <button type="submit" name="submit" class="button button-primary">Save Changes</button>&nbsp;&nbsp;&nbsp;
     217                <button type="button" id="send_test_email_trigger" class="button button-secondary">Send Test Email</button>
     218
     219            </form>
     220        </div>
     221       
     222        <script type="text/javascript">
     223        jQuery(document).ready(function($) {
     224            $("#send_test_email_trigger").on("click",function() {
     225                var wrap = $("#send_test_email_wrap");
     226                if(wrap.hasClass("active")) {
     227                    wrap.slideUp(400,function() {$(this).removeClass("active")});
     228                } else {
     229                    wrap.slideDown(400,function() {$(this).addClass("active")});
     230                }
     231            })
     232        });
     233        </script>
     234
     235        <div class="wrap" id="send_test_email_wrap" <?php if($_POST && $error !== "false" && $error['class'] == "error") {} else { echo "style='display:none'";} ?>>
     236            <h2><?php _e('Send Test Email'); ?></h2>
     237            <form method="post" action="">
     238                <input type="hidden" name="send-test-email" value="1">
     239                <table class="form-table">
     240                    <tbody>
     241                        <tr valign="top">
     242                            <th scope="row" valign="top">
     243                                <label class="description" for="cycles_plugin_email_test_address"><?php _e('Email Address:'); ?></label>
     244                            </th>
     245                            <td>
     246                                <input id="cycles_plugin_email_test_address" name="cycles_plugin_email_test_address" type="text" class="regular-text" value="" />
     247                                <div class="note">(the test email will be sent to this address)</div>
     248                            </td>
     249                        </tr>
     250
     251                    </tbody>
     252                </table>
     253                <button type="submit" name="submit" class="button button-primary">Send Test Email</button>
     254               
     255            </form>
     256        </div>
     257        <?php
     258    }
     259   
     260    public function test_email_body() {
     261        ob_start();
     262        ?>
     263        <p>This is a email sending test for Cycles Plugin for Wordpress. Success!</p>
     264        <?php
     265        $body = ob_get_contents();
     266        ob_end_clean();
     267       
     268        return $body;
     269    }
    112270
    113271
     
    117275        register_setting('cycles_settings', 'cycles_plugin_slug', array(&$this,'sanitize_slug') );
    118276        register_setting('cycles_settings', 'cycles_plugin_approval_terms');
    119     }
    120 
     277        register_setting('cycles_settings_email', 'cycles_plugin_email_from_name');
     278        register_setting('cycles_settings_email', 'cycles_plugin_email_from_address', array(&$this,"sanitize_email"));
     279    }
     280
     281    public function sanitize_email($email) {
     282        if(filter_var($email, FILTER_VALIDATE_EMAIL)) {
     283            return $email;
     284        } else {
     285            return "";
     286        }
     287    }
    121288    public function sanitize_slug($new) {
    122289        $old = get_option( 'cycles_plugin_slug' );
  • design-feedback/trunk/admin/class-design-feedback-admin.php

    r1297113 r1461017  
    5050         */
    5151
    52                 wp_enqueue_style( 'thickbox' );
     52        wp_enqueue_style( 'thickbox' );
    5353        wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/design-feedback-admin.css', array(), $this->version, 'all' );
    5454    }
     
    143143        $callback_args = array();
    144144        add_meta_box( $id, $title, $callback, $page, $context, $priority, $callback_args );
    145     }
     145       
     146        // invite to approve meta box
     147        add_meta_box( 'design-feedback-meta-box-email-invite', 'Email Invitation to review design', array( $this, 'render_meta_box_email_invite' ), 'designfeedback', 'side', 'default', array() );
     148       
     149        // email notifications meta box
     150        /*add_meta_box( 'design-feedback-meta-box-email-notifications', 'Email Notifications', array( $this, 'render_meta_box_email_notifications' ), 'designfeedback', 'side', 'default', array() );*/
     151    }
     152   
     153    public function render_meta_box_email_invite() {
     154        wp_enqueue_script( 'thickbox' );
     155        ?>
     156        <p>Send an email to the following:</p>
     157        <p>
     158            <input type="text" id="designfeedback-invite-add-email-address" name="designfeedback[_temp]" class="newemail form-input-tip" size="16" autocomplete="off"value="">
     159            <input type="button" class="button designfeedback-add-email-invite" value="Add">
     160        </p>
     161        <p class="note">Separate emails with commas</p>
     162        <div class="emailchecklist"></div>
     163        <div class="buttons">
     164            <a href="#" class="preview-email thickbox left">(preview)</a>
     165            <a href="#" class="send-email right button button-primary button-large">Send Email Invite</a>
     166        </div>
     167        <?php
     168    }
     169
     170    public function ajax_send_design_invite() {
     171
     172        check_ajax_referer( 'cycles-admin-nonce', 'nonce', true );
     173
     174        if ( isset( $_POST['emails'] ) && !empty($_POST['emails']) && isset($_POST['post_ID']) && !empty($_POST['post_ID']) ) {
     175            $post = get_post($_POST['post_ID']);
     176            if($post) {
     177                if(is_array($_POST['emails'])) {
     178                    foreach($_POST['emails'] as $email) {
     179                        $this->send_feedback_invite($_POST['post_ID'], $email);
     180                    }
     181                }
     182            }
     183        }
     184        die;
     185    }
     186   
     187    public function send_feedback_invite($post_id,$email) {
     188        $name = get_option('cycles_plugin_email_from_name','cycles');
     189        $from = get_option('cycles_plugin_email_from_address','');
     190        $post = get_post($post_id);
     191
     192        $body = $this->render_invite_body($post_id,$email);
     193        $to = $email;
     194
     195        $subject  = "[".$post->post_title."] is ready for review";
     196        $headers  = "MIME-Version: 1.0" . "\r\n";
     197        $headers .= "Content-type: text/html; charset=".get_bloginfo('charset')."" . "\r\n";
     198        $headers .= "From: ".$name." <".$from.">" . "\r\n";
     199        $mail = wp_mail($to,$subject,$body,$headers);
     200        return $mail;
     201    }
     202
     203    public function render_invite_body($post_id, $email) {
     204        $name = get_option('cycles_plugin_email_from_name','cycles');
     205        $from = get_option('cycles_plugin_email_from_address','');
     206        $post = get_post($post_id);
     207        if(file_exists(plugin_dir_path( __FILE__ )."emails/invite.html")) {
     208            $html = file_get_contents(plugin_dir_path( __FILE__ )."emails/invite.html");
     209            $html = str_replace("{designTitle}",$post->post_title,$html);
     210            $html = str_replace("{designURL}",get_permalink($post_id),$html);
     211            $html = str_replace("{designPassword}",(!empty($post->post_password) ? 'Password: '.$post->post_password : ''),$html);
     212            $html = str_replace("{cyclesEmailName}",$name,$html);
     213            $html = str_replace("{cyclesEmailAddress}",$from,$html);
     214        } else {
     215            die("The requested view file does not exist.");
     216        }
     217        return $html;
     218    }
     219
     220    public function ajax_render_invite_body() {
     221        check_ajax_referer( 'cycles-admin-nonce', 'nonce', true );
     222        if(isset($_GET['post_ID'])) {
     223            $post = get_post($_GET['post_ID']);
     224            $from = get_option('cycles_plugin_email_from_address','');
     225            $name = get_option('cycles_plugin_email_from_name','cycles');
     226           
     227            $html = "<p>From: \"".$name."\" &lt;".$from."&gt;<br>";
     228            $html .= "Subject: [".$post->post_title." ] is ready for review</p>";
     229            $html .= $this->render_invite_body($_GET['post_ID'],null);
     230            echo $html;
     231        }
     232
     233        die();
     234    }
     235
     236    public function send_comment_notification_email($args) {
     237        //        print_r($args);
     238        if(isset($args['post_ID']) && !empty($args['post_ID']) && isset($args['feedback_id']) && !empty($args['feedback_id'])) {
     239            $notifications = get_post_meta( $args['post_ID'], 'notification_on_comments', true );
     240            $notification_emails = get_post_meta( $args['post_ID'], 'notification_emails', true );
     241            if(!empty($notifications) && $notifications == 1) {
     242                if(!empty($notification_emails) && is_array($notification_emails) && count($notification_emails) > 0) {
     243                    foreach($notification_emails as $email) {
     244                        // trigger send email
     245                        $this->do_comment_notification_email($email, $args['post_ID'],$args['feedback_id']);
     246                    }
     247                }
     248            }
     249        }
     250    }
     251
     252    public function do_comment_notification_email($email, $post_id,$feedback_id) {
     253        global $wpdb;
     254        $html = "";
     255        $post = get_post($post_id);
     256        $query = "SELECT * FROM ".$wpdb->prefix . 'feedbacks'." WHERE id = '".$feedback_id."'";
     257        $feedback = $wpdb->get_row( $query );
     258
     259        if($post && $feedback) {
     260            $name = get_option('cycles_plugin_email_from_name','cycles');
     261            $from = get_option('cycles_plugin_email_from_address','');
     262            $post = get_post($post_id);
     263
     264            $body = $this->render_comment_notification_email_body($post_id,$feedback_id);
     265            $to = $email;
     266
     267            $subject  = "[".$post->post_title."] ".$feedback->name." left a new comment";
     268            $headers  = "MIME-Version: 1.0" . "\r\n";
     269            $headers .= "Content-type: text/html; charset=".get_bloginfo('charset')."" . "\r\n";
     270            $headers .= "From: ".$name." <".$from.">" . "\r\n";
     271            $mail = wp_mail($to,$subject,$body,$headers);
     272            return $mail;
     273        }
     274
     275    }
     276
     277    public function render_comment_notification_email_body($post_id,$feedback_id) {
     278        global $wpdb;
     279        $html = "";
     280        $post = get_post($post_id);
     281        if($feedback_id === false) {
     282            // dummy data
     283            $feedback = new stdClass();
     284            $feedback->id = 1;
     285            $feedback->name = "Comment Author";
     286            $feedback->time = date("j m");
     287            $feedback->feedback = "This is my comment.";
     288        } else {
     289        $query = "SELECT * FROM ".$wpdb->prefix . 'feedbacks'." WHERE id = '".$feedback_id."'";
     290        $feedback = $wpdb->get_row( $query );
     291        }
     292       
     293
     294        if($post && $feedback) {
     295            $name = get_option('cycles_plugin_email_from_name','cycles');
     296            $from = get_option('cycles_plugin_email_from_address','');
     297
     298            $post = get_post($post_id);
     299            if(file_exists(plugin_dir_path( __FILE__ )."emails/notification.html")) {
     300                $html = file_get_contents(plugin_dir_path( __FILE__ )."emails/notification.html");
     301                $html = str_replace("{designTitle}",$post->post_title,$html);
     302                $html = str_replace("{designURL}",get_permalink($post_id),$html);
     303                $html = str_replace("{designPassword}",(!empty($post->post_password) ? 'Password: '.$post->post_password : ''),$html);
     304                $html = str_replace("{cyclesEmailName}",$name,$html);
     305                $html = str_replace("{cyclesEmailAddress}",$from,$html);
     306                $html = str_replace("{feedbackID}",$feedback->id,$html);
     307                $html = str_replace("{feedbackName}",$feedback->name,$html);
     308                $html = str_replace("{feedbackTime}",$feedback->time,$html);
     309                $html = str_replace("{feedbackMessage}",$feedback->feedback,$html);
     310            } else {
     311                die("The requested view file does not exist.");
     312            }
     313        }
     314
     315        return $html;
     316        }
     317
     318    public function ajax_render_notification_preview() {
     319        if(isset($_GET['type'])) {
     320            $post = get_post($_GET['post_ID']);
     321            $name = get_option('cycles_plugin_email_from_name','cycles');
     322            $from = get_option('cycles_plugin_email_from_address','');
     323            if($_GET['type'] == "comments") {
     324                $html = "<p>From: \"".$name."\" &lt;".$from."&gt;<br>";
     325                $html .= "Subject: [".$post->post_title."] Comment Author left a new comment</p>";
     326               
     327                $html .= $this->render_comment_notification_email_body($_GET['post_ID'],false);
     328                echo $html;
     329            } else {
     330                $html = "";
     331
     332                $html = "<p>From: \"".$name."\" &lt;".$from."&gt;<br>";
     333                $html .= "Subject: [".$post->post_title."] Approval Name approved the design</p>";
     334               
     335                $html .= $this->render_approved_notification_email_body($_GET['post_ID'],true);
     336
     337               
     338                echo $html;
     339            }
     340        }
     341
     342        die;
     343    }
     344
     345    public function send_approved_notification_email($args) {
     346        //        print_r($args);
     347        if(isset($args['post_ID']) && !empty($args['post_ID'])) {
     348            $notifications = get_post_meta( $args['post_ID'], 'notification_on_approved', true );
     349            $notification_emails = get_post_meta( $args['post_ID'], 'notification_emails', true );
     350            if(!empty($notifications) && $notifications == 1) {
     351                if(!empty($notification_emails) && is_array($notification_emails) && count($notification_emails) > 0) {
     352                    foreach($notification_emails as $email) {
     353                        // trigger send email
     354                        $this->do_approved_notification_email($email, $args['post_ID']);
     355                    }
     356                }
     357            }
     358        }
     359    }
     360
     361    public function do_approved_notification_email($email, $post_id) {
     362        global $wpdb;
     363        $html = "";
     364        $post = get_post($post_id);
     365        $approved = get_post_meta( $post_id, 'approved' ,true);
     366        $approved_by = get_post_meta( $post_id, 'approved_by' ,true);
     367        $approved_date = get_post_meta( $post_id, 'approved_at' ,true);
     368
     369        if($post) {
     370            $name = get_option('cycles_plugin_email_from_name','cycles');
     371            $from = get_option('cycles_plugin_email_from_address','');
     372            $post = get_post($post_id);
     373
     374            $body = $this->render_approved_notification_email_body($post_id);
     375            $to = $email;
     376
     377            $subject  = "[".$post->post_title."] ".$approved_by." approved the design";
     378            $headers  = "MIME-Version: 1.0" . "\r\n";
     379            $headers .= "Content-type: text/html; charset=".get_bloginfo('charset')."" . "\r\n";
     380            $headers .= "From: ".$name." <".$from.">" . "\r\n";
     381            $mail = wp_mail($to,$subject,$body,$headers);
     382            return $mail;
     383        }
     384    }
     385
     386    public function render_approved_notification_email_body($post_id,$dummy = false) {
     387        $html = "";
     388        $post = get_post($post_id);
     389        $approved = get_post_meta( $post_id, 'approved',true );
     390        if($dummy) {
     391            $approved_by = "Approval Name";
     392            $approved_date = date(get_option( 'date_format' ),(strtotime(date("Y-m-d H:i:s"))  + (get_option( 'gmt_offset' ) * HOUR_IN_SECONDS) ));
     393            $approved_date .= " ".date(get_option( 'time_format' ),(strtotime(date("Y-m-d H:i:s"))  + (get_option( 'gmt_offset' ) * HOUR_IN_SECONDS) ));
     394        } else {
     395            $approved_by = get_post_meta( $post_id, 'approved_by' ,true);
     396            $approved_date = get_post_meta( $post_id, 'approved_at' ,true);
     397            $approved_date = date(get_option( 'date_format' ),(strtotime($approved_date)  + (get_option( 'gmt_offset' ) * HOUR_IN_SECONDS) ));
     398            $approved_date .= " ".date(get_option( 'time_format' ),(strtotime($approved_date)  + (get_option( 'gmt_offset' ) * HOUR_IN_SECONDS) ));
     399        }
     400
     401        if($post) {
     402                $name = get_option('cycles_plugin_email_from_name','cycles');
     403                $from = get_option('cycles_plugin_email_from_address','');
     404               
     405            if(file_exists(plugin_dir_path( __FILE__ )."emails/approval.html")) {
     406                $html = file_get_contents(plugin_dir_path( __FILE__ )."emails/approval.html");
     407                $html = str_replace("{designTitle}",$post->post_title,$html);
     408                $html = str_replace("{designURL}",get_permalink($post_id),$html);
     409                $html = str_replace("{designPassword}",(!empty($post->post_password) ? 'Password: '.$post->post_password : ''),$html);
     410                $html = str_replace("{cyclesEmailName}",$name,$html);
     411                $html = str_replace("{cyclesEmailAddress}",$from,$html);
     412                $html = str_replace("{approvedBy}",$approved_by,$html);
     413                $html = str_replace("{approvedDate}",$approved_date,$html);
     414            } else {
     415                die("The requested view file does not exist.");
     416            }
     417        }
     418
     419        return $html;
     420    }
     421
     422   
     423
     424    public function ajax_save_notification_data() {
     425        if(isset($_POST['post_ID'])) {
     426            foreach ( array( 'notification_on_comments','notification_on_approved','notification_emails' ) as $key ) {
     427
     428                if($key == "notification_emails") {
     429                    delete_post_meta( $_POST['post_ID'], $key );
     430                    if(isset($_POST[$key])) {
     431                        update_post_meta($_POST['post_ID'], $key, $_POST[$key]);
     432                    }
     433                } else {
     434                    if ( isset( $_POST[ $key ] ) ) {
     435                        $value = $_POST[ $key ];
     436                        add_post_meta( $_POST['post_ID'], $key, $value, true );
     437                    }
     438                }
     439
     440            }
     441
     442        }
     443
     444    }
    146445
    147446    public function render_meta_box_image() {
    148447
    149448        wp_nonce_field( 'case_study_bg_submit', 'case_study_bg_nonce' );
     449       
     450        wp_enqueue_script( 'thickbox' );
     451       
     452        $post = get_post(get_the_ID());
    150453
    151454        foreach ( array( 'image_design', 'feedback_enabled' ) as $key ) {
    152455            $meta[ $key ] = get_post_meta( get_the_ID(), $key, true );
    153456        }
     457       
     458        $on_comments = get_post_meta( get_the_ID(), 'notification_on_comments', true );
     459        $on_approved = get_post_meta( get_the_ID(), 'notification_on_approved', true );
     460        $notification_emails = get_post_meta( get_the_ID(), 'notification_emails', true );
    154461
    155462        ?>
     
    170477            <p><label><input type="checkbox" name="feedback_enabled" id="feedback_enabled" value="1" <?php checked( $meta['feedback_enabled'] )?>> Allow feedback</label></p>
    171478            <?php do_action( 'cycles_before_closing_design_settings' ); ?>
     479           
     480            <?php
     481            if($post->post_status == "publish") :
     482            ?>
     483            <div id="design-feedback-meta-box-email-notifications">
     484                <hr>
     485                <h4>Notification Settings</h4>
     486                <p>Send an email notification:</p>
     487                <p><label><input type="checkbox" name="notification_on_comments" <?php checked( $on_comments )?> value="1" class="change-trigger"> When there is a new comment</label> <a href="#" class="preview-email" data-type="comments">(preview)</a></p>
     488                <p><label><input type="checkbox" name="notification_on_approved" <?php checked( $on_approved )?> value="1" class="change-trigger"> When the design is approved</label> <a href="#" class="preview-email"  data-type="approved">(preview)</a></p>
     489                <p>
     490                    <input type="text" id="designfeedback-notification-add-email-address" name="designfeedback[_temp]" class="newemail form-input-tip" size="16" autocomplete="off"value="">
     491                    <input type="button" class="button designfeedback-add-email-notification" value="Add">
     492                </p>
     493                <p class="note">Separate emails with commas</p>
     494                <div class="emailchecklist">
     495                    <?php
     496                    if($notification_emails && is_array($notification_emails) && count($notification_emails) > 0) {
     497                        foreach($notification_emails as $email) {
     498                            ?>
     499                            <input type="hidden" name="notification_emails[]" value="<?=$email?>">
     500                            <span><a href="javascript:void(0)" class="remove-email" data-email="<?=$email?>">X</a>&nbsp;<?=$email?></span>
     501                            <?php
     502                        }
     503                    }
     504                    ?>
     505                </div>
     506            </div>
     507            <?php endif; ?>
    172508        </div>
    173509       
     
    209545                add_post_meta( $post_ID, $key, $value, true );
    210546            }
     547            if($key == "feedback_enabled" && !isset( $_POST[ $key ] )) {
     548                delete_post_meta( $post_ID, $key );
     549            }
    211550        }
    212551
     
    281620                foreach ( $feedbacks as $feedback ) {
    282621                    $name = $feedback->name;
    283                     $feedback_time = date( 'g:i a M d', $feedback->time );
     622                        $feedback_time = date(get_option( 'date_format' ),($feedback->time  + (get_option( 'gmt_offset' ) * HOUR_IN_SECONDS)) );
     623                        $feedback_time .= " ".date(get_option( 'time_format' ),($feedback->time  + (get_option( 'gmt_offset' ) * HOUR_IN_SECONDS)) );
     624                       
    284625                    $feedback_feedback = nl2br( esc_html( trim( $feedback->feedback ) ) );
    285626                    ?>
     
    316657
    317658        unset( $columns['date'] );
     659        $columns['design_status'] = __( 'Status' );
    318660        $columns['feedbacks'] = '<img src = "' . plugin_dir_url( __FILE__ ) . 'images/comments-icon.gif"/>';
    319         $columns['date'] = 'Date';
     661        $columns['date'] = __( 'Date' );
    320662        return $columns;
    321663    }
     
    328670     */
    329671    public function define_designs_columns_content( $column, $post_id ) {
    330         if ( 'feedbacks' !== $column ) {
    331             return;
    332         } else {
    333             $handler = new Design_Feedback_Handler( $post_id );
    334             echo esc_html( $handler->get_feedbacks_counter() );
    335         }
     672        $handler = new Design_Feedback_Handler( $post_id );
     673        switch($column) {
     674            case "feedbacks":
     675                echo esc_html( $handler->get_feedbacks_counter() );
     676            break;
     677            case "design_status":
     678                echo $handler->get_feedback_status();
     679            break;
     680        }
     681       
    336682        return $column;
    337683    }
     
    347693    public function define_designs_sortable_columns( $columns ) {
    348694
    349         $columns['feedbacks'] = 'feedbacks';
     695//        $columns['feedbacks'] = 'feedbacks';
    350696        return $columns;
    351697    }
     
    391737            $text .= ob_get_clean();
    392738        }
    393         return $text;
     739        echo $text;
    394740    }
    395741
     
    448794        'design-feedback-meta-box-main',
    449795        );
     796       
     797        if($post->post_status == "publish") {
     798            array_push($allowed_meta_boxes,'design-feedback-meta-box-email-invite');
     799        }
    450800
    451801        // Loop through each page key of the '$wp_meta_boxes' global.
  • design-feedback/trunk/admin/css/design-feedback-admin.css

    r1297113 r1461017  
    141141    float:right;
    142142}
     143#design-feedback-meta-box-email-invite .emailchecklist {
     144        margin-left: 14px;
     145    font-size: 12px;
     146    overflow: auto;
     147}
     148#design-feedback-meta-box-email-invite .emailchecklist span {
     149        margin-right: 25px;
     150    font-size: 13px;
     151    line-height: 1.8em;
     152    cursor: default;
     153    max-width: 100%;
     154    text-overflow: ellipsis;
     155}
     156
     157#design-feedback-meta-box-email-invite .emailchecklist span a {
     158    margin: 1px 0 0 -17px;
     159    cursor: pointer;
     160    width: 20px;
     161    height: 20px;
     162    text-indent: 0;
     163    position: absolute;
     164}
     165#design-feedback-meta-box-email-invite .emailchecklist span a:before {
     166    background: 0 0;
     167    color: #b4b9be;
     168    content: "\f153";
     169    display: block;
     170    font: 400 16px/20px dashicons;
     171    speak: none;
     172    height: 20px;
     173    text-align: center;
     174    text-decoration:none;
     175    width: 20px;
     176    -webkit-font-smoothing: antialiased;
     177    -moz-osx-font-smoothing: grayscale;
     178}
     179#design-feedback-meta-box-email-invite .emailchecklist span a:hover:before {
     180    color: #c00;
     181}
     182#design-feedback-meta-box-email-invite .note {
     183    margin: 0 0 6px;
     184    color: #666;
     185    font-style: italic;
     186    display: block;
     187}
     188#design-feedback-meta-box-email-invite .emailchecklist span,
     189#design-feedback-meta-box-email-invite .emailchecklist span a {
     190    display: block;
     191    float: left;
     192    overflow: hidden;
     193    text-decoration:none;
     194}
     195
     196#design-feedback-meta-box-email-invite .buttons {
     197    padding:10px 0 0 0;
     198    margin:10px 0 0 0;
     199    border-top:1px solid #fafafa;
     200   
     201}
     202#design-feedback-meta-box-email-invite .buttons:after {
     203    content:" ";
     204    display:block;
     205    clear:both;
     206}
     207#design-feedback-meta-box-email-invite .buttons .left {
     208    float:left;
     209    line-height:28px;
     210    vertical-align: middle;
     211    text-align: left;
     212}
     213#design-feedback-meta-box-email-invite .buttons .right {
     214    float:right;
     215}
     216
     217
     218#design-feedback-meta-box-email-notifications {}
     219#design-feedback-meta-box-email-notifications .emailchecklist {
     220        margin-left: 14px;
     221    font-size: 12px;
     222    overflow: auto;
     223}
     224#design-feedback-meta-box-email-notifications .emailchecklist span {
     225        margin-right: 25px;
     226    font-size: 13px;
     227    line-height: 1.8em;
     228    cursor: default;
     229    max-width: 100%;
     230    text-overflow: ellipsis;
     231}
     232
     233#design-feedback-meta-box-email-notifications .emailchecklist span a {
     234    margin: 1px 0 0 -17px;
     235    cursor: pointer;
     236    width: 20px;
     237    height: 20px;
     238    text-indent: 0;
     239    position: absolute;
     240}
     241#design-feedback-meta-box-email-notifications .emailchecklist span a:before {
     242    background: 0 0;
     243    color: #b4b9be;
     244    content: "\f153";
     245    display: block;
     246    font: 400 16px/20px dashicons;
     247    speak: none;
     248    height: 20px;
     249    text-align: center;
     250    text-decoration:none;
     251    width: 20px;
     252    -webkit-font-smoothing: antialiased;
     253    -moz-osx-font-smoothing: grayscale;
     254}
     255#design-feedback-meta-box-email-notifications .emailchecklist span a:hover:before {
     256    color: #c00;
     257}
     258#design-feedback-meta-box-email-notifications .note {
     259    margin: 0 0 6px;
     260    color: #666;
     261    font-style: italic;
     262    display: block;
     263}
     264#design-feedback-meta-box-email-notifications .emailchecklist span,
     265#design-feedback-meta-box-email-notifications .emailchecklist span a {
     266    display: block;
     267    float: left;
     268    overflow: hidden;
     269    text-decoration:none;
     270}
     271
     272#design-feedback-meta-box-email-notifications .buttons {
     273    padding:10px 0 0 0;
     274    margin:10px 0 0 0;
     275    border-top:1px solid #fafafa;
     276   
     277}
     278#design-feedback-meta-box-email-notifications .buttons:after {
     279    content:" ";
     280    display:block;
     281    clear:both;
     282}
     283#design-feedback-meta-box-email-notifications .buttons .left {
     284    float:left;
     285    line-height:28px;
     286    vertical-align: middle;
     287    text-align: left;
     288}
     289#design-feedback-meta-box-email-notifications .buttons .right {
     290    float:right;
     291}
  • design-feedback/trunk/admin/js/design-feedback-admin.js

    r1297113 r1461017  
    3939
    4040    Cycles_Hook.call( 'cycles_admin_document_ready' );
     41   
     42    $("#design-feedback-meta-box-email-invite .designfeedback-add-email-invite").on("click",function(e) {
     43        e.preventDefault();
     44        var that = $(this);
     45        var input = $("#designfeedback-invite-add-email-address");
     46        var hidden = $('#design-feedback-meta-box-email-invite').find('input[name="emails[]"]');
     47        var list = $("#design-feedback-meta-box-email-invite .emailchecklist");
     48
     49        var added = [];
     50        hidden.each(function(i,el) {
     51            added.push($(el).val());
     52        });
     53
     54        if(input.val().length) {
     55            var value = input.val().replace(/\s+/g, '');
     56            if ( value.indexOf(',') > -1 ) {
     57                var emails = value.split(",");
     58                $.each(emails,function(i,email) {
     59                    if(cycles_validate_email(email)) {
     60                        if($.inArray(email,added) < 0) {
     61                            var hidden = $("<input>",{
     62                                type:"hidden",
     63                                name:"emails[]",
     64                                value: email
     65                            });
     66                            hidden.insertAfter(that);
     67                            var item = '<span><a href="javascript:void(0)" class="remove-email" data-email="'+email+'">X</a>&nbsp;'+email+'</span>';
     68                            list.append($(item));
     69                        }
     70                    } else {
     71                        alert("Invalid email: "+email);
     72                    }
     73                });
     74            } else {
     75                if(cycles_validate_email(value)) {
     76                    if($.inArray(value,added) < 0) {
     77                        var hidden = $("<input>",{
     78                            type:"hidden",
     79                            name:"emails[]",
     80                            value: value
     81                        });
     82                        hidden.insertAfter(that);
     83                        var item = '<span><a href="javascript:void(0)" class="remove-email" data-email="'+value+'">X</a>&nbsp;'+value+'</span>';
     84                        list.append($(item));
     85                    }
     86                } else {
     87                    alert("Invalid email: "+value);
     88                }
     89            }
     90            input.val("");
     91        }
     92    });
     93
     94    $("body").on("click","#design-feedback-meta-box-email-invite .remove-email",function(e) {
     95        e.preventDefault();
     96        var that = $(this);
     97        var email = that.attr("data-email");
     98        var input = $("#design-feedback-meta-box-email-invite").find('input[value="'+email+'"]');
     99        input.remove();
     100        that.parent("span").remove();
     101    });
     102
     103    $("#design-feedback-meta-box-email-invite .preview-email").on("click",function(e) {
     104        e.preventDefault();
     105        tb_show("Preview Email", ajaxurl+'?action=preview_design_invite' + '&post_ID=' + jQuery( '#post_ID' ).val() +'&nonce=' + cycles_admin_nonce );
     106        return false;
     107    });
     108
     109    $("#design-feedback-meta-box-email-invite .send-email").on("click",function(e) {
     110        e.preventDefault();
     111        var that = $(this);
     112        var wrap = $("#design-feedback-meta-box-email-invite");
     113        var postdata = wrap.find('input[type="hidden"]');
     114        var list = $("#design-feedback-meta-box-email-invite .emailchecklist");
     115
     116        that.data("default-html",that.html());
     117
     118        if (!that.hasClass("button-primary") || postdata.length < 1) {
     119            return;
     120        }
     121        that.removeClass("button-primary").attr("disabled",true);
     122
     123        jQuery.ajax({
     124            url: ajaxurl,
     125            type: "POST",
     126            data: 'action=send_design_invite&' + postdata.serialize() + '&post_ID=' + jQuery( '#post_ID' ).val() +'&nonce=' + cycles_admin_nonce,
     127            success: function(data){
     128                that.html("Email Sent")
     129                list.html("");
     130
     131                setTimeout(function() {
     132                    that.html(that.data("default-html")).addClass("button-primary").attr("disabled",false);
     133                    },2000)
     134            },
     135            error: function() {
     136                alert("Could not send email");
     137                that.html(that.data("default-html")).addClass("button-primary").attr("disabled",false);
     138            }
     139        } );
     140    });
     141
     142
     143    $("#design-feedback-meta-box-email-notifications .designfeedback-add-email-notification").on("click",function(e) {
     144        e.preventDefault();
     145        var that = $(this);
     146        var input = $("#designfeedback-notification-add-email-address");
     147        var hidden = $('#design-feedback-meta-box-email-notifications').find('input[name="notification_emails[]"]');
     148        var list = $("#design-feedback-meta-box-email-notifications .emailchecklist");
     149
     150        var added = [];
     151        hidden.each(function(i,el) {
     152            added.push($(el).val());
     153        });
     154
     155        if(input.val().length) {
     156            var value = input.val().replace(/\s+/g, '');
     157            if ( value.indexOf(',') > -1 ) {
     158                var emails = value.split(",");
     159                $.each(emails,function(i,email) {
     160                    if(cycles_validate_email(email)) {
     161                        if($.inArray(email,added) < 0) {
     162                            var hidden = $("<input>",{
     163                                type:"hidden",
     164                                name:"notification_emails[]",
     165                                value: email
     166                            });
     167                            hidden.insertAfter(that);
     168                            var item = '<span><a href="javascript:void(0)" class="remove-email" data-email="'+email+'">X</a>&nbsp;'+email+'</span>';
     169                            list.append($(item));
     170                        }
     171                    } else {
     172                        alert("Invalid email: "+email);
     173                    }
     174                });
     175            } else {
     176                if(cycles_validate_email(value)) {
     177                    if($.inArray(value,added) < 0) {
     178                        var hidden = $("<input>",{
     179                            type:"hidden",
     180                            name:"notification_emails[]",
     181                            value: value
     182                        });
     183                        hidden.insertAfter(that);
     184                        var item = '<span><a href="javascript:void(0)" class="remove-email" data-email="'+value+'">X</a>&nbsp;'+value+'</span>';
     185                        list.append($(item));
     186                    }
     187                } else {
     188                    alert("Invalid email: "+value);
     189                }
     190            }
     191            input.val("");
     192            cycles_save_email_notifications();
     193        }
     194    });
     195   
     196    $('#design-feedback-meta-box-email-notifications input[type="checkbox"]').on("click",function(e) {
     197        cycles_save_email_notifications();
     198    });
     199   
     200    $("body").on("click","#design-feedback-meta-box-email-notifications .remove-email",function(e) {
     201        e.preventDefault();
     202        var that = $(this);
     203        var email = that.attr("data-email");
     204        var input = $("#design-feedback-meta-box-email-notifications").find('input[value="'+email+'"]');
     205        input.remove();
     206        that.parent("span").remove();
     207        cycles_save_email_notifications();
     208    });
     209   
     210    $("#design-feedback-meta-box-email-notifications .preview-email").on("click",function(e) {
     211        e.preventDefault();
     212        var that = $(this);
     213        var type = that.attr("data-type");
     214        tb_show("Preview Email", ajaxurl+'?action=preview_notification_email&type='+ type + '&post_ID=' + jQuery( '#post_ID' ).val() +'&nonce=' + cycles_admin_nonce );
     215        return false;
     216    });
    41217} );
     218
     219function cycles_validate_email(email) {
     220    var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
     221    return re.test(email);
     222}
     223
     224function cycles_save_email_notifications() {
     225    var container = jQuery("#design-feedback-meta-box-email-notifications");
     226    if(container.length) {
     227        var data = container.find("input").serialize();
     228        jQuery.ajax({
     229            url: ajaxurl,
     230            type: "POST",
     231            data: 'action=save_notification_data&' + data + '&post_ID=' + jQuery( '#post_ID' ).val() + '&nonce=' + cycles_admin_nonce,
     232            success: function(data){
     233               
     234            }
     235        } );
     236    }
     237
     238}
    42239
    43240function cycles_load_image() {
  • design-feedback/trunk/cycles.php

    r1318107 r1461017  
    1616 * Plugin URI:        https://getCycles.io
    1717 * Description:       Instant design feedback and approvals from your clients, all in one place.
    18  * Version:           1.4.1
     18 * Version:           1.5
    1919 * Author:            Cycles
    2020 * Author URI:        https://getCycles.io
  • design-feedback/trunk/includes/class-design-feedback-handler.php

    r1297113 r1461017  
    5555        $query = "SELECT * FROM $table WHERE post_id = '$post_id'";
    5656
    57         $result = wp_cache_get( 'get_feedbacks_result' );
     57        $result = wp_cache_get( 'get_feedbacks_result-'.$this->post_id );
    5858        if ( false === $result ) {
    5959            $result = $wpdb->get_results( $query );
    60             wp_cache_set( 'get_feedbacks_result', $result );
     60            wp_cache_set( 'get_feedbacks_result-'.$this->post_id, $result );
    6161        }
    6262
     
    112112        }
    113113    }
     114   
     115    public function get_feedback_status() {
     116        $approved = get_post_meta( $this->post_id, 'approved', true );
     117        if($approved) {
     118            $date = get_post_meta( $this->post_id, 'approved_at', true );
     119            if($date) {
     120                $dateformat = get_option('date_format',true);
     121                $string = sprintf(__("Approved on %s"),date($dateformat,strtotime($date)));
     122                return $string;
     123            }
     124            return __("Approved");
     125        } else {
     126            return __("In Review");
     127        }
     128    }
    114129}
  • design-feedback/trunk/includes/class-design-feedback.php

    r1297113 r1461017  
    145145        $this->loader->add_action( 'wp_ajax_get_image', $plugin_admin, 'ajax_get_image' );
    146146        $this->loader->add_action( 'wp_ajax_remove_image', $plugin_admin, 'ajax_remove_image' );
     147        $this->loader->add_action( 'wp_ajax_send_design_invite', $plugin_admin, 'ajax_send_design_invite' );
     148        $this->loader->add_action( 'wp_ajax_preview_design_invite', $plugin_admin, 'ajax_render_invite_body' );
     149        $this->loader->add_action( 'wp_ajax_save_notification_data', $plugin_admin, 'ajax_save_notification_data' );
     150        $this->loader->add_action( 'wp_ajax_nopriv_save_notification_data', $plugin_admin, 'ajax_save_notification_data' );
     151        $this->loader->add_action( 'cycles_send_email_notification_for_comment', $plugin_admin, 'send_comment_notification_email' );
     152        $this->loader->add_action( 'cycles_send_email_notification_for_approved', $plugin_admin, 'send_approved_notification_email' );
     153        $this->loader->add_action( 'wp_ajax_preview_notification_email', $plugin_admin, 'ajax_render_notification_preview' );
    147154        $this->loader->add_action( 'save_post', $plugin_admin, 'save_image_metabox' );
    148155        $this->loader->add_action( 'add_meta_boxes', $plugin_admin, 'lock_meta_boxes', 999, 2 );
  • design-feedback/trunk/public/class-design-feedback-public.php

    r1318107 r1461017  
    105105            );
    106106            $feedbackId = $wpdb->insert_id;
     107           
     108            // send comment email notification
     109            do_action("cycles_send_email_notification_for_comment",array('post_ID'=>$postId, 'feedback_id' => $feedbackId));
    107110        }
    108111        $response = array(
     
    350353        add_post_meta( $post_ID, 'approved_at', date( 'Y-m-d H:i:s' ), true );
    351354        add_post_meta( $post_ID, 'approved_by', $signature, true );
     355       
     356        // send notification
     357        do_action("cycles_send_email_notification_for_approved",array('post_ID'=>$post_ID));
    352358
    353359        $response = array(
Note: See TracChangeset for help on using the changeset viewer.