Changeset 1461017
- Timestamp:
- 07/26/2016 07:55:02 PM (10 years ago)
- Location:
- design-feedback
- Files:
-
- 5 added
- 11 edited
-
assets/screenshot-4.png (modified) (previous)
-
trunk/README.txt (modified) (13 diffs)
-
trunk/addons/approvals/index.php (modified) (2 diffs)
-
trunk/addons/settings/index.php (modified) (8 diffs)
-
trunk/admin/class-design-feedback-admin.php (modified) (10 diffs)
-
trunk/admin/css/design-feedback-admin.css (modified) (1 diff)
-
trunk/admin/emails (added)
-
trunk/admin/emails/approval.html (added)
-
trunk/admin/emails/index.php (added)
-
trunk/admin/emails/invite.html (added)
-
trunk/admin/emails/notification.html (added)
-
trunk/admin/js/design-feedback-admin.js (modified) (1 diff)
-
trunk/cycles.php (modified) (1 diff)
-
trunk/includes/class-design-feedback-handler.php (modified) (2 diffs)
-
trunk/includes/class-design-feedback.php (modified) (1 diff)
-
trunk/public/class-design-feedback-public.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
design-feedback/trunk/README.txt
r1318125 r1461017 3 3 Tags: 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 4 4 Requires at least: 4.0 5 Tested up to: 4. 46 Stable tag: 1. 4.15 Tested up to: 4.5.3 6 Stable tag: 1.5 7 7 License: GPLv2 or later 8 8 … … 11 11 == Description == 12 12 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 15 Cycles 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. 20 26 21 27 [youtube https://www.youtube.com/watch?v=1nhIQH9IHVE] 22 28 23 > ####No longer making mockups? Join our Web Developer Beta29 > ####No longer making mockups? Our Web Developer Beta is now active 24 30 > 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. 25 31 > 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. 27 33 > 28 34 > 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). 30 36 31 37 #### Features 32 38 33 **NEW: Approvals & Digital Signatures** 39 **NEW: Email Invites & Notifications** 40 Send 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** 43 Enter 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** 34 46 When a client is ready to “sign off,” they approve designs by agreeing to terms and providing their digital signature for the system to record. 35 47 36 ** NEW:Custom Design URL _and_ Slug**48 **Custom Design URL _and_ Slug** 37 49 Make sharing easier with custom, client friendly and easy to pronounce URLs. Now including the path/slug. 38 50 … … 46 58 Organize designs in the WordPress media library for quick sorting and searching. 47 59 48 49 60 **Password Protection** 50 61 Set optional passwords to keep designs private and secure from unwanted visitors. … … 57 68 58 69 #### Follow Cycles 59 [Blog](http ://getCycles.io/blog/) | [Twitter](http://twitter.com/getCycles)70 [Blog](https://blog.getCycles.io/) | [Twitter](https://twitter.com/getCycles) 60 71 61 72 == Installation == … … 70 81 2. Clients approve designs with their digital signature 71 82 3. Password protect your designs to protect client privacy 72 4. View feedback and approvals directly on the design or in aggregate 83 4. View feedback and approvals directly on the design or in aggregate, plus email invites and comment/approval notifications 73 84 74 85 == Frequently Asked Questions == … … 104 115 == Change Log == 105 116 117 = 1.5 = 118 July 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 106 126 = 1.4.1 = 107 127 December 29th, 2015 108 109 128 * Enhanced: Clients can view approval details on designs by hovering over the approval button 110 129 * Enhanced: Approval confirmation dialog look and feel … … 117 136 = 1.4 = 118 137 November 30th, 2015 119 120 138 * New: Enable approvals on your design so your clients complete the feedback process and move to the next phase. 121 139 * New: Custom slug (in Cycles > Settings) for fully customizable URLs … … 123 141 = 1.3.2 = 124 142 November 10th, 2015 125 126 143 * Enhanced: Now load all external scripts via HTTPS 127 144 * Fixed: Issue with saving comments containing special characters … … 130 147 = 1.3 = 131 148 November 8th, 2015 132 133 149 * Enhanced: Feedback name is pre-populated for faster commenting 134 150 * Enhanced: Better open/close click behavior when viewing comments … … 144 160 145 161 Mockup Presentation 146 147 162 * New: Redesigned loading and design presentation and layout, so your mockups look their best 148 163 * New: Help section for frequently asked questions … … 151 166 152 167 Feedback Rewrite 153 154 168 * New: Feedback code rewrite and redesign, so leaving feedback is faster and more intuitive 155 169 * New: View state for feedback … … 158 172 159 173 Other 160 161 174 * Tested: Compatible with WordPress 4.3.1 162 175 … … 187 200 == Upgrade Notice == 188 201 189 = 1. 4.1=190 Bug fixes and minorenhancements202 = 1.5 = 203 Email notifications and usability enhancements -
design-feedback/trunk/addons/approvals/index.php
r1318107 r1461017 140 140 <span>Approved</span> 141 141 <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'])?> 143 143 </div> 144 144 </div> … … 256 256 if ( $approved['by'] ) { 257 257 $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 260 261 printf('<div id="cycles_approval_details">Approved on %s at %s by %s</div>' 261 262 , esc_html( $date ) -
design-feedback/trunk/addons/settings/index.php
r1297129 r1461017 6 6 const SLUG = 'settings_addon'; 7 7 const VERSION = '0.1'; 8 8 9 9 private $addon_dir_path; 10 10 private $addon_url; 11 11 private $classes_directory_url; 12 12 13 13 public $tabs = array( 14 'general'=>'General' 14 'general'=>'General', 15 'emails'=>'Emails', 15 16 ); 16 17 … … 22 23 $this->classes_directory_url = $this->addon_dir_path . 'classes/'; 23 24 24 $loader = new Design_Feedback_Loader;25 /*$loader = new Design_Feedback_Loader; 25 26 26 27 $loader->add_action( 'admin_menu', $this, 'add_plugin_settings_page' ); … … 28 29 $loader->add_action( 'init', $this, 'override_slug',11 ); 29 30 $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')); 32 41 } 33 42 … … 36 45 return $links; 37 46 } 38 47 39 48 public function add_plugin_settings_page() { 40 49 add_submenu_page( 'edit.php?post_type=designfeedback', 'Settings', 'Settings', 'manage_options', 'cycles_settings', array(&$this,'settings_page' )); … … 42 51 43 52 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(); 53 66 echo '<div id="icon-themes" class="icon32"><br></div>'; 54 67 echo '<h2 class="nav-tab-wrapper">'; … … 59 72 } 60 73 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(); 62 84 switch($current) { 63 85 case 'general': 64 86 $this->general_tab(); 65 87 break; 88 case 'emails': 89 $this->emails_tab(); 90 break; 66 91 default: 67 92 $this->general_tab(); 68 93 break; 69 94 } 95 $data = ob_get_contents(); 96 ob_end_clean(); 97 98 echo $data; 99 100 70 101 } 71 102 … … 76 107 ?> 77 108 <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"> 86 127 <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> 88 129 </th> 89 130 <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> 92 132 93 133 </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> 109 141 <?php 110 142 } 111 143 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> 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 } 112 270 113 271 … … 117 275 register_setting('cycles_settings', 'cycles_plugin_slug', array(&$this,'sanitize_slug') ); 118 276 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 } 121 288 public function sanitize_slug($new) { 122 289 $old = get_option( 'cycles_plugin_slug' ); -
design-feedback/trunk/admin/class-design-feedback-admin.php
r1297113 r1461017 50 50 */ 51 51 52 wp_enqueue_style( 'thickbox' );52 wp_enqueue_style( 'thickbox' ); 53 53 wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/design-feedback-admin.css', array(), $this->version, 'all' ); 54 54 } … … 143 143 $callback_args = array(); 144 144 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."\" <".$from."><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."\" <".$from."><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."\" <".$from."><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 } 146 445 147 446 public function render_meta_box_image() { 148 447 149 448 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()); 150 453 151 454 foreach ( array( 'image_design', 'feedback_enabled' ) as $key ) { 152 455 $meta[ $key ] = get_post_meta( get_the_ID(), $key, true ); 153 456 } 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 ); 154 461 155 462 ?> … … 170 477 <p><label><input type="checkbox" name="feedback_enabled" id="feedback_enabled" value="1" <?php checked( $meta['feedback_enabled'] )?>> Allow feedback</label></p> 171 478 <?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> <?=$email?></span> 501 <?php 502 } 503 } 504 ?> 505 </div> 506 </div> 507 <?php endif; ?> 172 508 </div> 173 509 … … 209 545 add_post_meta( $post_ID, $key, $value, true ); 210 546 } 547 if($key == "feedback_enabled" && !isset( $_POST[ $key ] )) { 548 delete_post_meta( $post_ID, $key ); 549 } 211 550 } 212 551 … … 281 620 foreach ( $feedbacks as $feedback ) { 282 621 $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 284 625 $feedback_feedback = nl2br( esc_html( trim( $feedback->feedback ) ) ); 285 626 ?> … … 316 657 317 658 unset( $columns['date'] ); 659 $columns['design_status'] = __( 'Status' ); 318 660 $columns['feedbacks'] = '<img src = "' . plugin_dir_url( __FILE__ ) . 'images/comments-icon.gif"/>'; 319 $columns['date'] = 'Date';661 $columns['date'] = __( 'Date' ); 320 662 return $columns; 321 663 } … … 328 670 */ 329 671 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 336 682 return $column; 337 683 } … … 347 693 public function define_designs_sortable_columns( $columns ) { 348 694 349 $columns['feedbacks'] = 'feedbacks';695 // $columns['feedbacks'] = 'feedbacks'; 350 696 return $columns; 351 697 } … … 391 737 $text .= ob_get_clean(); 392 738 } 393 return$text;739 echo $text; 394 740 } 395 741 … … 448 794 'design-feedback-meta-box-main', 449 795 ); 796 797 if($post->post_status == "publish") { 798 array_push($allowed_meta_boxes,'design-feedback-meta-box-email-invite'); 799 } 450 800 451 801 // Loop through each page key of the '$wp_meta_boxes' global. -
design-feedback/trunk/admin/css/design-feedback-admin.css
r1297113 r1461017 141 141 float:right; 142 142 } 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 39 39 40 40 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> '+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> '+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> '+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> '+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 }); 41 217 } ); 218 219 function 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 224 function 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 } 42 239 43 240 function cycles_load_image() { -
design-feedback/trunk/cycles.php
r1318107 r1461017 16 16 * Plugin URI: https://getCycles.io 17 17 * Description: Instant design feedback and approvals from your clients, all in one place. 18 * Version: 1. 4.118 * Version: 1.5 19 19 * Author: Cycles 20 20 * Author URI: https://getCycles.io -
design-feedback/trunk/includes/class-design-feedback-handler.php
r1297113 r1461017 55 55 $query = "SELECT * FROM $table WHERE post_id = '$post_id'"; 56 56 57 $result = wp_cache_get( 'get_feedbacks_result ');57 $result = wp_cache_get( 'get_feedbacks_result-'.$this->post_id ); 58 58 if ( false === $result ) { 59 59 $result = $wpdb->get_results( $query ); 60 wp_cache_set( 'get_feedbacks_result ', $result );60 wp_cache_set( 'get_feedbacks_result-'.$this->post_id, $result ); 61 61 } 62 62 … … 112 112 } 113 113 } 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 } 114 129 } -
design-feedback/trunk/includes/class-design-feedback.php
r1297113 r1461017 145 145 $this->loader->add_action( 'wp_ajax_get_image', $plugin_admin, 'ajax_get_image' ); 146 146 $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' ); 147 154 $this->loader->add_action( 'save_post', $plugin_admin, 'save_image_metabox' ); 148 155 $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 105 105 ); 106 106 $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)); 107 110 } 108 111 $response = array( … … 350 353 add_post_meta( $post_ID, 'approved_at', date( 'Y-m-d H:i:s' ), true ); 351 354 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)); 352 358 353 359 $response = array(
Note: See TracChangeset
for help on using the changeset viewer.