Changeset 1971315
- Timestamp:
- 11/09/2018 05:25:29 AM (7 years ago)
- Location:
- frontend-uploader/trunk
- Files:
-
- 11 edited
-
frontend-uploader.php (modified) (32 diffs)
-
lib/js/frontend-uploader.js (modified) (1 diff)
-
lib/php/akismet.php (modified) (3 diffs)
-
lib/php/class-frontend-uploader-wp-posts-list-table.php (modified) (2 diffs)
-
lib/php/class-html-helper.php (modified) (8 diffs)
-
lib/php/frontend-uploader-settings.php (modified) (2 diffs)
-
lib/php/recaptcha.php (modified) (1 diff)
-
lib/php/settings-api/class.settings-api.php (modified) (17 diffs)
-
lib/views/manage-ugc-media.tpl.php (modified) (4 diffs)
-
lib/views/manage-ugc-posts.tpl.php (modified) (4 diffs)
-
readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
frontend-uploader/trunk/frontend-uploader.php
r1734078 r1971315 4 4 Description: Allow your visitors to upload content and moderate it. 5 5 Author: Rinat Khaziev, Daniel Bachhuber 6 Version: 1.3. 16 Version: 1.3.2 7 7 Author URI: http://digitallyconscious.com 8 8 … … 26 26 27 27 // Define consts and bootstrap and dependencies 28 define( 'FU_VERSION', '1.3. 1' );28 define( 'FU_VERSION', '1.3.2' ); 29 29 define( 'FU_ROOT' , dirname( __FILE__ ) ); 30 30 define( 'FU_FILE_PATH' , FU_ROOT . '/' . basename( __FILE__ ) ); … … 156 156 foreach ( $fu_mime_types as $extension => $details ) { 157 157 // Skip if it's not in the settings 158 if ( ! in_array( $extension, $enabled) )158 if ( ! in_array( $extension, $enabled, true ) ) 159 159 continue; 160 160 … … 199 199 global $wp_version; 200 200 if ( version_compare( $wp_version, '3.3', '<' ) ) { 201 wp_die( __( 'Frontend Uploader requires WordPress 3.3 or newer. Please upgrade.', 'frontend-uploader' ) );201 wp_die( esc_html__( 'Frontend Uploader requires WordPress 3.3 or newer. Please upgrade.', 'frontend-uploader' ) ); 202 202 } 203 203 … … 230 230 231 231 $screen = get_current_screen(); 232 if ( ! defined( 'DOING_AJAX' ) && $screen && isset( $screen->base ) && $screen->base == 'upload' && ( !isset( $_GET['page'] ) || $_GET['page'] != 'manage_frontend_uploader' ) ) {232 if ( ! defined( 'DOING_AJAX' ) && $screen && isset( $screen->base ) && $screen->base === 'upload' && ( !isset( $_GET['page'] ) || $_GET['page'] !== 'manage_frontend_uploader' ) ) { 233 233 $where = str_replace( "post_status = 'private'", "post_status = 'inherit'", $where ); 234 234 } … … 242 242 */ 243 243 function _is_public() { 244 return ( current_user_can( 'read' ) && 'on' == $this->settings['auto_approve_user_files'] ) || ( 'on'== $this->settings['auto_approve_any_files'] );244 return ( current_user_can( 'read' ) && 'on' === $this->settings['auto_approve_user_files'] ) || ( 'on' === $this->settings['auto_approve_any_files'] ); 245 245 } 246 246 … … 290 290 $typecheck = wp_check_filetype_and_ext( $k['tmp_name'], $k['name'], false ); 291 291 // Add an error message if MIME-type is not allowed 292 if ( ! in_array( $typecheck['type'], (array) $this->allowed_mime_types ) ) {292 if ( ! in_array( $typecheck['type'], (array) $this->allowed_mime_types, true ) ) { 293 293 $errors['fu-disallowed-mime-type'][] = array( 'name' => $k['name'], 'mime' => $k['type'] ); 294 294 continue; … … 323 323 324 324 // Obfuscate filename if setting is present 325 if ( isset( $this->settings['obfuscate_file_name'] ) && 'on'== $this->settings['obfuscate_file_name'] ){325 if ( isset( $this->settings['obfuscate_file_name'] ) && 'on' === $this->settings['obfuscate_file_name'] ){ 326 326 $fn = explode( '.', $k['name'] ); 327 $m['name'] = uniqid( mt_rand( 1, 1000 ) , true ) . '.' . end( $fn );327 $m['name'] = uniqid( wp_rand( 1, 1000 ) , true ) . '.' . end( $fn ); 328 328 } 329 329 … … 390 390 */ 391 391 function wp_kses_add_srcset( $tags, $context ) { 392 if ( $context == 'post' )392 if ( $context === 'post' ) 393 393 $tags['img']['srcset'] = true; 394 394 … … 524 524 $this->form_fields = !empty( $this->form_fields ) ? $this->form_fields : $this->_get_fields_for_form( $form_post_id, $hash ); 525 525 526 $layout = isset( $_POST['form_layout'] ) && ! empty( $_POST['form_layout'] ) ? $_POST['form_layout']: 'image';526 $layout = isset( $_POST['form_layout'] ) && ! empty( $_POST['form_layout'] ) ? sanitize_text_field( $_POST['form_layout'] ) : 'image'; 527 527 528 528 /** … … 586 586 function _notify_admin( $result = array() ) { 587 587 // Email notifications are disabled, or upload has failed, bailing 588 if ( ! ( 'on' == $this->settings['notify_admin'] && $result['success'] ) )588 if ( ! ( 'on' === $this->settings['notify_admin'] && $result['success'] ) ) 589 589 return; 590 590 … … 627 627 if ( empty( $result ) || !is_array( $result ) ) { 628 628 wp_safe_redirect( wp_get_referer() ); 629 exit; 630 629 631 return; 630 632 } … … 632 634 // Either redirect to success page if it's set and valid 633 635 // Or to referrer 634 $url = isset( $_POST['success_page'] ) && filter_var( $_POST['success_page'], FILTER_VALIDATE_URL ) ? $_POST['success_page']: wp_get_referer();636 $url = isset( $_POST['success_page'] ) && filter_var( $_POST['success_page'], FILTER_VALIDATE_URL ) ? esc_url_raw( $_POST['success_page'] ) : wp_get_referer(); 635 637 636 638 // $query_args will hold everything that's needed for displaying notices to user … … 688 690 include_once FU_ROOT . '/' . $file; 689 691 } else { 690 wp_die( __( "Couldn't find template file", 'frontend-uploader' ) );692 wp_die( esc_html__( "Couldn't find template file", 'frontend-uploader' ) ); 691 693 } 692 694 } … … 697 699 */ 698 700 private function _set_global_query_for_tables( $type = 'posts' ) { 699 if ( ! in_array( $type, array( 'posts', 'media' ) ) )701 if ( ! in_array( $type, array( 'posts', 'media' ), true ) ) 700 702 return false; 701 703 … … 752 754 add_media_page( __( 'Manage UGC', 'frontend-uploader' ), __( 'Manage UGC', 'frontend-uploader' ), $this->manage_permissions, 'manage_frontend_uploader', array( $this, 'admin_list' ) ); 753 755 foreach ( (array) $this->settings['enabled_post_types'] as $cpt ) { 754 if ( $cpt == 'post' ) {756 if ( $cpt === 'post' ) { 755 757 add_posts_page( __( 'Manage UGC Posts', 'frontend-uploader' ), __( 'Manage UGC', 'frontend-uploader' ), $this->manage_permissions, 'manage_frontend_uploader_posts', array( $this, 'admin_posts_list' ) ); 756 758 continue; … … 773 775 } 774 776 775 $post = get_post( $_GET['id'] );776 777 if ( is_object( $post ) && $post->post_status == 'private' ) {777 $post = get_post( (int) $_GET['id'] ); 778 779 if ( is_object( $post ) && $post->post_status === 'private' ) { 778 780 $post->post_status = 'inherit'; 779 781 wp_update_post( $post ); … … 803 805 } 804 806 805 $post = get_post( $_GET['id'] );807 $post = get_post( (int) $_GET['id'] ); 806 808 807 809 if ( is_object( $post ) ) { … … 822 824 'page' => "manage_frontend_uploader_{$post->post_type}s", 823 825 'approved' => 1, 824 'post_type' => $post->post_type != 'post' ? $post->post_type : '',826 'post_type' => $post->post_type !== 'post' ? $post->post_type : '', 825 827 ); 826 828 … … 884 886 extract( $atts ); 885 887 886 $role = in_array( $role, array( 'meta', 'title', 'description', 'author', 'internal', 'content' ) ) ? $role : 'meta';888 $role = in_array( $role, array( 'meta', 'title', 'description', 'author', 'internal', 'content' ), true ) ? $role : 'meta'; 887 889 $name = sanitize_text_field( $name ); 888 890 // Add the field to fields map … … 910 912 // Allow multiple file upload by default. 911 913 // To do so, we need to add array notation to name field: [] 912 if ( !strpos( $name, '[]' ) && $type == 'file' )914 if ( !strpos( $name, '[]' ) && $type === 'file' ) 913 915 $name = 'files' . '[]'; 914 916 … … 916 918 917 919 // No need for wrappers or labels for hidden input 918 if ( $type == 'hidden' )920 if ( $type === 'hidden' ) 919 921 return $input; 920 922 … … 940 942 941 943 // Render WYSIWYG textarea 942 if ( ( isset( $this->settings['wysiwyg_enabled'] ) && 'on' == $this->settings['wysiwyg_enabled'] ) || $wysiwyg_enabled== true ) {944 if ( ( isset( $this->settings['wysiwyg_enabled'] ) && 'on' === $this->settings['wysiwyg_enabled'] ) || $wysiwyg_enabled === true ) { 943 945 ob_start(); 944 946 wp_editor( '', $id, array( … … 1085 1087 $post_id = (int) $post_id; 1086 1088 1087 $this->enqueue_scripts();1089 add_action( 'wp_footer', array( $this, 'enqueue_scripts' ), 0 ); 1088 1090 1089 1091 $form_layout = in_array( $form_layout, array( 'post', 'image', 'media', 'post_image', 'post_media' ), true ) ? $form_layout : 'media'; … … 1091 1093 ob_start(); 1092 1094 ?> 1093 <form action="<?php echo admin_url( 'admin-ajax.php' ) ?>" method="post" id="ugc-media-form-<?php echo $inst++; ?>" class="<?php echo esc_attr( $class )?> fu-upload-form" enctype="multipart/form-data">1095 <form action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ) ?>" method="post" id="ugc-media-form-<?php echo esc_attr( $inst++ ); ?>" class="<?php echo esc_attr( $class )?> fu-upload-form" enctype="multipart/form-data"> 1094 1096 <div class="ugc-inner-wrapper"> 1095 1097 <h2><?php echo esc_html( $title ) ?></h2> … … 1104 1106 // Set post type for layouts that include uploading of posts 1105 1107 // Put it in front of the main form to allow to override it 1106 if ( in_array( $form_layout, array( "post_media", "post_image", "post" ) ) ) {1108 if ( in_array( $form_layout, array( "post_media", "post_image", "post" ), true ) ) { 1107 1109 echo $this->shortcode_content_parser( array( 1108 1110 'type' => 'hidden', … … 1129 1131 } 1130 1132 1131 if ( !( isset( $this->settings['suppress_default_fields'] ) && 'on' == $this->settings['suppress_default_fields'] ) && ( $suppress_default_fields === false ) ) {1133 if ( !( isset( $this->settings['suppress_default_fields'] ) && 'on' === $this->settings['suppress_default_fields'] ) && ( $suppress_default_fields === false ) ) { 1132 1134 1133 1135 // Display title field … … 1179 1181 echo do_shortcode( $content ); 1180 1182 1181 if ( !( isset( $this->settings['suppress_default_fields'] ) && 'on' == $this->settings['suppress_default_fields'] ) && ( $suppress_default_fields === false ) ) {1182 1183 if ( in_array( $form_layout, array( 'image', 'media', 'post_image', 'post_media' ) ) ) {1183 if ( !( isset( $this->settings['suppress_default_fields'] ) && 'on' === $this->settings['suppress_default_fields'] ) && ( $suppress_default_fields === false ) ) { 1184 1185 if ( in_array( $form_layout, array( 'image', 'media', 'post_image', 'post_media' ), true ) ) { 1184 1186 // Default upload field 1185 1187 echo $this->shortcode_content_parser( array( … … 1194 1196 } 1195 1197 1196 if ( $this->settings['enable_recaptcha_protection' ] == 'on' )1198 if ( $this->settings['enable_recaptcha_protection' ] === 'on' ) 1197 1199 echo fu_get_recaptcha_markup(); 1198 1200 … … 1236 1238 ), null, 'input' ); 1237 1239 1238 if ( in_array( $form_layout, array( 'post_media', 'post_image' ) ) ) {1240 if ( in_array( $form_layout, array( 'post_media', 'post_image' ), true ) ) { 1239 1241 // One of supported form layouts 1240 1242 echo $this->shortcode_content_parser( array( … … 1454 1456 * Otherwise it produces JS errors, potentially breaking some post edit screen features 1455 1457 */ 1456 if ( $screen && 'media_page_manage_frontend_uploader' == $screen->base )1458 if ( $screen && 'media_page_manage_frontend_uploader' === $screen->base ) 1457 1459 wp_enqueue_script( 'media', array( 'jquery' ) ); 1458 1460 } … … 1516 1518 function _enable_akismet_protection() { 1517 1519 // Maybe include Akismet 1518 if ( isset( $this->settings['enable_akismet_protection'] ) && 'on' == $this->settings['enable_akismet_protection'] ) {1520 if ( isset( $this->settings['enable_akismet_protection'] ) && 'on' === $this->settings['enable_akismet_protection'] ) { 1519 1521 require_once FU_ROOT . '/lib/php/akismet.php'; 1520 1522 } -
frontend-uploader/trunk/lib/js/frontend-uploader.js
r1402587 r1971315 1 jQuery( function($) { 2 // Drop in _.string 3 _.mixin(s.exports()); 4 var uploadForm = $( '.fu-upload-form' ); 5 var uploadFormInputs = uploadForm.find('input[type="text"], textarea'); 1 jQuery(function ($) { 2 // Drop in _.string 3 _.mixin(s.exports()); 4 var uploadForm = $('.fu-upload-form'); 5 var uploadFormInputs = uploadForm.find('input[type="text"], textarea'); 6 _.each( uploadForm, function (f, i) { 7 $(f).validate({ 8 submitHandler: function (form) { 9 form.submit(); 10 } 11 }) 12 }); 6 13 7 uploadForm.validate({ 8 submitHandler: function(form) { 9 form.submit(); 10 } 11 }); 14 /** 15 * Only set the fields if an error happened 16 * @return {[type]} [description] 17 */ 18 var shouldPopulate = function () { 19 var qv = getQueryVariable('response'); 20 return false === (qv == '' || qv == 'fu-sent' || qv == 'fu-post-sent'); 21 }; 12 22 13 /** 14 * Only set the fields if an error happened 15 * @return {[type]} [description] 16 */ 17 var shouldPopulate = function() { 18 var qv = getQueryVariable('response'); 19 return false === ( qv == '' || qv == 'fu-sent' || qv == 'fu-post-sent' ); 20 }; 23 /** 24 * Extract needed var from location.search 25 * @param {[type]} variable [description] 26 * @return {[type]} [description] 27 */ 28 var getQueryVariable = function (variable) { 29 var query = window.location.search.substring(1); 30 var vars = query.split('&'); 31 for (var i = 0; i < vars.length; i++) { 32 var pair = vars[i].split('='); 33 if (decodeURIComponent(pair[0]) == variable) { 34 return decodeURIComponent(pair[1]); 35 } 36 } 21 37 22 /** 23 * Extract needed var from location.search 24 * @param {[type]} variable [description] 25 * @return {[type]} [description] 26 */ 27 var getQueryVariable = function (variable) { 28 var query = window.location.search.substring(1); 29 var vars = query.split('&'); 30 for (var i = 0; i < vars.length; i++) { 31 var pair = vars[i].split('='); 32 if (decodeURIComponent(pair[0]) == variable) { 33 return decodeURIComponent(pair[1]); 34 } 35 } 38 return ''; 39 } 36 40 37 return ''; 38 } 41 // Strip all tags and escape HTML 42 var sanitize = function (str) { 43 return _.escapeHTML(_.stripTags(str)); 44 }; 39 45 40 // Strip all tags and escape HTML 41 var sanitize = function( str ) { 42 return _.escapeHTML( _.stripTags( str ) ); 43 }; 46 /** 47 * Iterate over form text inputs and textareas and either populate value or remove it from local storage 48 * @param {[type]} value [description] 49 * @param {[type]} key [description] 50 * @param {[type]} list 51 * @return {[type]} [description] 52 */ 53 _.each(uploadFormInputs, function (value, key, list) { 54 var lsKey = $(value).prop('id') + ':value'; 55 if (shouldPopulate()) { 56 $(value).val(sanitize(localStorage.getItem(lsKey))); 57 } else { 58 localStorage.removeItem(lsKey); 59 } 60 }); 44 61 45 /** 46 * Iterate over form text inputs and textareas and either populate value or remove it from local storage 47 * @param {[type]} value [description] 48 * @param {[type]} key [description] 49 * @param {[type]} list ) { var lsKey [description] 50 * @return {[type]} [description] 51 */ 52 _.each( uploadFormInputs, function( value, key, list ) { 53 var lsKey = $(value).prop('id') + ':value'; 54 if ( shouldPopulate() ) { 55 $(value).val( sanitize( localStorage.getItem( lsKey ) ) ); 56 } else { 57 localStorage.removeItem( lsKey ); 58 } 59 }); 62 /** 63 * Store input value in localStorage 64 */ 65 uploadFormInputs.on('change keyup focusin focusout', function (e) { 66 var el = $(e.target); 60 67 61 /** 62 * Store input value in localStorage 63 */ 64 uploadFormInputs.on( "change keyup focusin focusout", function( e ) { 65 var el = $(e.target); 68 var key = el.prop('id') + ':value'; 66 69 67 var key = el.prop('id') + ':value'; 70 // you can never be too safe 71 var val = sanitize(el.val()); 68 72 69 // you can never be too safe 70 var val = sanitize( el.val() ); 71 72 localStorage.setItem( key, val ); 73 }); 73 localStorage.setItem(key, val); 74 }); 74 75 75 76 }); -
frontend-uploader/trunk/lib/php/akismet.php
r1012202 r1971315 18 18 19 19 $content['comment_author'] = isset( $_POST['post_author'] ) ? sanitize_text_field( $_POST['post_author'] ) : null; 20 $content['comment_content'] = isset( $_POST[ 'post_content' ] ) ? $_POST['post_content']: null;20 $content['comment_content'] = isset( $_POST[ 'post_content' ] ) ? wp_kses_post( $_POST['post_content'] ) : null; 21 21 22 22 // Permalink of the post with upload form, fallback to wp_get_referer() 23 23 // Fallback is used to 24 $content['permalink'] = isset( $_POST['form_post_id'] ) ? get_permalink( $_POST['form_post_id']) : wp_get_referer();24 $content['permalink'] = isset( $_POST['form_post_id'] ) ? get_permalink( sanitize_text_area( $_POST['form_post_id'] ) ) : wp_get_referer(); 25 25 26 26 // Set required Akismet values 27 $content['user_ip'] = isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR']: null;28 $content['user_agent'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT']: null;29 $content['referrer'] = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER']: null;27 $content['user_ip'] = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : null; 28 $content['user_agent'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] ) : null; 29 $content['referrer'] = isset( $_SERVER['HTTP_REFERER'] ) ? sanitize_text_field( $_SERVER['HTTP_REFERER'] ) : null; 30 30 $content['blog'] = get_option( 'home' ); 31 31 $content['blog_lang'] = get_locale(); … … 36 36 $ignore = array( 'HTTP_COOKIE', 'HTTP_COOKIE2', 'PHP_AUTH_PW', 'ff', 'fu_nonce' ); 37 37 foreach ( $_POST as $key => $value ) { 38 if ( ! in_array( $key, $ignore ) && is_string( $value ) )38 if ( ! in_array( $key, $ignore, true ) && is_string( $value ) ) 39 39 $content["POST_{$key}"] = $value; 40 40 } 41 41 42 42 foreach ( $_SERVER as $key => $value ) { 43 if ( ! in_array( $key, $ignore ) && is_string( $value ) )43 if ( ! in_array( $key, $ignore, true ) && is_string( $value ) ) 44 44 $content["$key"] = $value; 45 45 else … … 52 52 53 53 // It's a spam 54 if ( $response[1] == 'true' )54 if ( $response[1] === 'true' ) 55 55 $should_process = false; 56 56 -
frontend-uploader/trunk/lib/php/class-frontend-uploader-wp-posts-list-table.php
r1699139 r1971315 10 10 11 11 $screen = get_current_screen(); 12 if ( $screen->post_type == '' ) {12 if ( $screen->post_type === '' ) { 13 13 $screen->post_type ='post'; 14 14 } … … 21 21 function _add_row_actions( $actions, $post ) { 22 22 unset( $actions['inline hide-if-no-js'] ); 23 if ( $post->post_status == 'private' ) {23 if ( $post->post_status === 'private' ) { 24 24 $actions['pass'] = '<a href="'.admin_url( 'admin-ajax.php' ).'?action=approve_ugc_post&id=' . $post->ID . '&post_type=' . $post->post_type . '">'. __( 'Approve', 'frontend-uploader' ) .'</a>'; 25 25 $actions['delete'] = '<a onclick="return showNotice.warn();" href="'.admin_url( 'admin-ajax.php' ).'?action=delete_ugc&id=' . $post->ID . '&post_type=' . $post->post_type . '&fu_nonce=' . wp_create_nonce( FU_NONCE ). '">'. __( 'Delete Permanently', 'frontend-uploader' ) .'</a>'; -
frontend-uploader/trunk/lib/php/class-html-helper.php
r1728963 r1971315 20 20 */ 21 21 function checkboxes( $name = '', $description = '', $data = array(), $checked = array() ) { 22 if ( $name != '' ) {22 if ( $name !== '' ) { 23 23 $name = filter_var( $name, FILTER_SANITIZE_STRING ); 24 24 if ( $description ); … … 26 26 echo '<input type="hidden" name="' . esc_attr( $name ) .'" value="" />'; 27 27 foreach ( (array) $data as $item ) { 28 $is_checked_attr = in_array( $item, (array) $checked ) ? ' checked="true" ' : '';28 $is_checked_attr = in_array( $item, (array) $checked, true ) ? ' checked="true" ' : ''; 29 29 $item = filter_var( $item, FILTER_SANITIZE_STRING ); 30 30 echo '<div class="sm-input-wrapper">'; 31 echo '<input type="checkbox" name="' . esc_attr( $name ) . '[]" value="' . esc_attr( $item ) . '" id="' .esc_attr( $name ) . esc_attr( $item ) . '" ' . $is_checked_attr. ' />';31 echo '<input type="checkbox" name="' . esc_attr( $name ) . '[]" value="' . esc_attr( $item ) . '" id="' .esc_attr( $name ) . esc_attr( $item ) . '" ' . esc_attr( $is_checked_attr ) . ' />'; 32 32 echo '<label for="' .esc_attr( $name ) . esc_attr( $item ) . '">' . esc_attr ( $item ) . '</label>'; 33 33 echo '</div>'; … … 77 77 case 'file': 78 78 case 'checkbox': 79 case 'email': 80 case 'date': 81 case 'datetime': 82 case 'datetime-local': 83 case 'color': 84 case 'month': 85 case 'number': 86 case 'password': 87 case 'range': 88 case 'search': 89 case 'reset': 90 case 'button': 91 case 'tel': 92 case 'time': 93 case 'url': 94 case 'week': 79 95 return $this->_text( $name, $type, $data, $attrs ) ; 80 96 break; … … 106 122 foreach ( (array) $data as $key => $value ) { 107 123 $attrs_to_pass = array( 'value' => $key ); 108 if ( isset( $attrs[ 'default' ] ) && $key == $attrs[ 'default' ] )124 if ( isset( $attrs[ 'default' ] ) && $key === $attrs[ 'default' ] ) 109 125 $attrs_to_pass[ 'selected' ] = 'selected'; 110 126 $ret .= $this->element( 'option', $value, $attrs_to_pass, false ); … … 146 162 $allowed = apply_filters( 'hh_allowed_html_elements' , array( 'div', 'p', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'td', 'option', 'label', 'textarea', 'select', 'option', 'fieldset' ) ); 147 163 $attr_string = $this->_format_attributes( $params ); 148 if ( in_array( $tag, $allowed ) )164 if ( in_array( $tag, $allowed, true ) ) 149 165 return "<{$tag} {$attr_string}>" . ( $escape ? esc_html ( $content ) : $content ) . "</{$tag}>"; 150 166 } … … 165 181 166 182 foreach ( (array) $attrs as $attr => $value ) { 167 if ( in_array( $attr, $this->_allowed_html_attrs() ) && $value != '' )183 if ( in_array( $attr, $this->_allowed_html_attrs(), true ) && $value !== '' ) 168 184 $attr_string .= " {$attr}='" . esc_attr ( $value ) . "'"; 169 185 } … … 182 198 $attr_string = $this->_format_attributes( $params ); 183 199 if ( filter_var( trim( $url ), FILTER_VALIDATE_URL ) ) 184 return '<a href="' . esc_url( trim( $url ) ) . '" ' . $attr_string . '>' . ( $title != '' ? esc_html ( $title ) : esc_url( trim( $url ) ) ) . '</a>';200 return '<a href="' . esc_url( trim( $url ) ) . '" ' . $attr_string . '>' . ( $title !== '' ? esc_html ( $title ) : esc_url( trim( $url ) ) ) . '</a>'; 185 201 } 186 202 … … 211 227 'max', 212 228 'placeholder', 213 214 229 ) ); 215 230 } -
frontend-uploader/trunk/lib/php/frontend-uploader-settings.php
r1688580 r1971315 20 20 function action_current_screen() { 21 21 $screen = get_current_screen(); 22 if ( in_array( $screen->base, array( 'settings_page_fu_settings', 'options' ) ) ) {22 if ( in_array( $screen->base, array( 'settings_page_fu_settings', 'options' ), true ) ) { 23 23 $this->settings_api->set_sections( $this->get_settings_sections() ); 24 24 $this->settings_api->set_fields( $this->get_settings_fields() ); … … 35 35 $fu_public_post_types = get_post_types( array( 'public' => true ), 'objects' ); 36 36 foreach( $fu_public_post_types as $slug => $post_object ) { 37 if ( $slug == 'attachment' ) {37 if ( $slug === 'attachment' ) { 38 38 unset( $fu_public_post_types[$slug] ); 39 39 continue; -
frontend-uploader/trunk/lib/php/recaptcha.php
r1688580 r1971315 21 21 'secret' => fu_get_option( 'recaptcha_secret_key' ), 22 22 'response' => sanitize_text_field( $_POST['g-recaptcha-response'] ), 23 'remoteip' => $_SERVER['REMOTE_ADDR']23 'remoteip' => sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) 24 24 ), 25 25 'timeout' => 3, -
frontend-uploader/trunk/lib/php/settings-api/class.settings-api.php
r1030331 r1971315 103 103 //register settings sections 104 104 foreach ( $this->settings_sections as $section ) { 105 if ( false == get_option( $section['id'] ) ) {105 if ( false === get_option( $section['id'] ) ) { 106 106 add_option( $section['id'] ); 107 107 } … … 143 143 function callback_text( $args ) { 144 144 145 $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ));145 $value = $this->get_option( $args['id'], $args['section'], $args['std'] ); 146 146 $size = isset( $args['size'] ) && !is_null( $args['size'] ) ? $args['size'] : 'regular'; 147 147 148 $html = sprintf( '<input type="text" class="%1$s-text" id="%2$s[%3$s]" name="%2$s[%3$s]" value="%4$s"/>', $size, $args['section'], $args['id'], $value);149 $html .= sprintf( '<span class="description"> %s</span>', $args['desc']);148 $html = sprintf( '<input type="text" class="%1$s-text" id="%2$s[%3$s]" name="%2$s[%3$s]" value="%4$s"/>', esc_attr( $size ), esc_attr( $args['section'] ), esc_attr( $args['id'] ), esc_attr( $value ) ); 149 $html .= sprintf( '<span class="description"> %s</span>', esc_html( $args['desc'] ) ); 150 150 151 151 echo $html; … … 159 159 function callback_checkbox( $args ) { 160 160 161 $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ));162 163 $html = sprintf( '<input type="hidden" name="%1$s[%2$s]" value="off" />', $args['section'], $args['id']);164 $html .= sprintf( '<input type="checkbox" class="checkbox" id="%1$s[%2$s]" name="%1$s[%2$s]" value="on"%4$s />', $args['section'], $args['id'], $value, checked( $value, 'on', false ) );165 $html .= sprintf( '<label for="%1$s[%2$s]"> %3$s</label>', $args['section'], $args['id'], $args['desc']);161 $value = $this->get_option( $args['id'], $args['section'], $args['std'] ); 162 163 $html = sprintf( '<input type="hidden" name="%1$s[%2$s]" value="off" />', esc_attr( $args['section'] ), esc_attr( $args['id'] ) ); 164 $html .= sprintf( '<input type="checkbox" class="checkbox" id="%1$s[%2$s]" name="%1$s[%2$s]" value="on"%4$s />', esc_attr( $args['section'] ), esc_attr( $args['id'] ), esc_attr( $value ), checked( $value, 'on', false ) ); 165 $html .= sprintf( '<label for="%1$s[%2$s]"> %3$s</label>', esc_attr( $args['section'] ), esc_attr( $args['id'] ), esc_html( $args['desc'] ) ); 166 166 167 167 echo $html; … … 180 180 foreach ( $args['options'] as $key => $label ) { 181 181 $checked = isset( $value[$key] ) ? $value[$key] : '0'; 182 $html .= sprintf( '<input type="checkbox" class="checkbox" id="%1$s[%2$s][%3$s]" name="%1$s[%2$s][%3$s]" value="%3$s"%4$s />', $args['section'], $args['id'], $key, checked( $checked, $key, false ) );183 $html .= sprintf( '<label for="%1$s[%2$s][%4$s]"> %3$s</label><br>', $args['section'], $args['id'], $label, $key);184 } 185 $html .= sprintf( '<span class="description"> %s</label>', $args['desc']);182 $html .= sprintf( '<input type="checkbox" class="checkbox" id="%1$s[%2$s][%3$s]" name="%1$s[%2$s][%3$s]" value="%3$s"%4$s />', esc_attr( $args['section'] ), esc_attr( $args['id'] ), esc_attr( $key ), checked( $checked, $key, false ) ); 183 $html .= sprintf( '<label for="%1$s[%2$s][%4$s]"> %3$s</label><br>', esc_attr( $args['section'] ), esc_attr( $args['id'] ), esc_html( $label ), esc_attr( $key ) ); 184 } 185 $html .= sprintf( '<span class="description"> %s</label>', esc_html( $args['desc'] ) ); 186 186 187 187 echo $html; … … 199 199 $html = ''; 200 200 foreach ( $args['options'] as $key => $label ) { 201 $html .= sprintf( '<input type="radio" class="radio" id="%1$s[%2$s][%3$s]" name="%1$s[%2$s]" value="%3$s"%4$s />', $args['section'], $args['id'], $key, checked( $value, $key, false ) );202 $html .= sprintf( '<label for="%1$s[%2$s][%4$s]"> %3$s</label><br>', $args['section'], $args['id'], $label, $key);203 } 204 $html .= sprintf( '<span class="description"> %s</label>', $args['desc']);201 $html .= sprintf( '<input type="radio" class="radio" id="%1$s[%2$s][%3$s]" name="%1$s[%2$s]" value="%3$s"%4$s />', esc_attr( $args['section'] ), esc_attr( $args['id'] ), esc_attr( $key ), checked( $value, $key, false ) ); 202 $html .= sprintf( '<label for="%1$s[%2$s][%4$s]"> %3$s</label><br>', esc_attr( $args['section'] ), esc_attr( $args['id'] ), esc_html( $label ), esc_attr( $key ) ); 203 } 204 $html .= sprintf( '<span class="description"> %s</label>', esc_html( $args['desc'] ) ); 205 205 206 206 echo $html; … … 214 214 function callback_select( $args ) { 215 215 216 $value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ));216 $value = $this->get_option( $args['id'], $args['section'], $args['std'] ); 217 217 $size = isset( $args['size'] ) && !is_null( $args['size'] ) ? $args['size'] : 'regular'; 218 218 219 $html = sprintf( '<select class="%1$s" name="%2$s[%3$s]" id="%2$s[%3$s]">', $size, $args['section'], $args['id']);219 $html = sprintf( '<select class="%1$s" name="%2$s[%3$s]" id="%2$s[%3$s]">', esc_attr( $size ), esc_attr( $args['section'] ), esc_attr( $args['id'] ) ); 220 220 foreach ( $args['options'] as $key => $label ) { 221 $html .= sprintf( '<option value="%s"%s>%s</option>', $key, selected( $value, $key, false ), $label);221 $html .= sprintf( '<option value="%s"%s>%s</option>', esc_attr( $key ), selected( $value, $key, false ), esc_html( $label ) ); 222 222 } 223 223 $html .= sprintf( '</select>' ); 224 $html .= sprintf( '<span class="description"> %s</span>', $args['desc']);224 $html .= sprintf( '<span class="description"> %s</span>', esc_html( $args['desc'] ) ); 225 225 226 226 echo $html; … … 234 234 function callback_textarea( $args ) { 235 235 236 $value = esc_textarea( $this->get_option( $args['id'], $args['section'], $args['std'] ));236 $value = $this->get_option( $args['id'], $args['section'], $args['std'] ); 237 237 $size = isset( $args['size'] ) && !is_null( $args['size'] ) ? $args['size'] : 'regular'; 238 238 239 $html = sprintf( '<textarea rows="5" cols="55" class="%1$s-text" id="%2$s[%3$s]" name="%2$s[%3$s]">%4$s</textarea>', $size, $args['section'], $args['id'], $value);240 $html .= sprintf( '<br><span class="description"> %s</span>', $args['desc']);239 $html = sprintf( '<textarea rows="5" cols="55" class="%1$s-text" id="%2$s[%3$s]" name="%2$s[%3$s]">%4$s</textarea>', esc_attr( $size ), esc_attr( $args['section'] ), esc_attr( $args['id'] ), esc_textarea( $value ) ); 240 $html .= sprintf( '<br><span class="description"> %s</span>', esc_html( $args['desc'] ) ); 241 241 242 242 echo $html; … … 249 249 */ 250 250 function callback_html( $args ) { 251 echo $args['desc'];251 echo esc_textarea( $args['desc'] ); 252 252 } 253 253 … … 262 262 $size = isset( $args['size'] ) && !is_null( $args['size'] ) ? $args['size'] : '500px'; 263 263 264 echo '<div style="width: ' . $size. ';">';264 echo '<div style="width: ' . esc_attr( $size ) . ';">'; 265 265 266 266 wp_editor( $value, $args['section'] . '[' . $args['id'] . ']', array( 'teeny' => true, 'textarea_rows' => 10 ) ); … … 268 268 echo '</div>'; 269 269 270 echo sprintf( '<br><span class="description"> %s</span>', $args['desc']);270 echo sprintf( '<br><span class="description"> %s</span>', esc_html( $args['desc'] ) ); 271 271 } 272 272 … … 282 282 $id = $args['section'] . '[' . $args['id'] . ']'; 283 283 $js_id = $args['section'] . '\\\\[' . $args['id'] . '\\\\]'; 284 $html = sprintf( '<input type="text" class="%1$s-text" id="%2$s[%3$s]" name="%2$s[%3$s]" value="%4$s"/>', $size, $args['section'], $args['id'], $value);285 $html .= '<input type="button" class="button wpsf-browse" id="'. $id.'_button" value="Browse" />284 $html = sprintf( '<input type="text" class="%1$s-text" id="%2$s[%3$s]" name="%2$s[%3$s]" value="%4$s"/>', esc_attr( $size ), esc_attr( $args['section'] ), esc_attr( $args['id'] ), esc_attr( $value ) ); 285 $html .= '<input type="button" class="button wpsf-browse" id="'. esc_attr( $id ) .'_button" value="Browse" /> 286 286 <script type="text/javascript"> 287 287 jQuery(document).ready(function($){ 288 $("#'. $js_id.'_button").click(function() {288 $("#'. wp_json_encode( $js_id ) .'_button").click(function() { 289 289 tb_show("", "media-upload.php?post_id=0&type=image&TB_iframe=true"); 290 290 window.original_send_to_editor = window.send_to_editor; … … 294 294 url = $(html).attr(\'src\'); 295 295 }; 296 $("#'. $js_id.'").val(url);296 $("#'. wp_json_encode( $js_id ) .'").val(url); 297 297 tb_remove(); 298 298 window.send_to_editor = window.original_send_to_editor; … … 302 302 }); 303 303 </script>'; 304 $html .= sprintf( '<span class="description"> %s</span>', $args['desc']);304 $html .= sprintf( '<span class="description"> %s</span>', esc_html( $args['desc'] ) ); 305 305 306 306 echo $html; … … 317 317 $size = isset( $args['size'] ) && !is_null( $args['size'] ) ? $args['size'] : 'regular'; 318 318 319 $html = sprintf( '<input type="password" class="%1$s-text" id="%2$s[%3$s]" name="%2$s[%3$s]" value="%4$s"/>', $size, $args['section'], $args['id'], $value);320 $html .= sprintf( '<span class="description"> %s</span>', $args['desc']);319 $html = sprintf( '<input type="password" class="%1$s-text" id="%2$s[%3$s]" name="%2$s[%3$s]" value="%4$s"/>', esc_attr( $size ), esc_attr( $args['section'] ), esc_attr( $args['id'] ), esc_attr( $value ) ); 320 $html .= sprintf( '<span class="description"> %s</span>', esc_html( $args['desc'] ) ); 321 321 322 322 echo $html; … … 358 358 foreach( $this->settings_fields as $section => $options ) { 359 359 foreach ( $options as $option ) { 360 if ( $option['name'] != $slug )360 if ( $option['name'] !== $slug ) 361 361 continue; 362 362 // Return the callback name … … 395 395 396 396 foreach ( $this->settings_sections as $tab ) { 397 $html .= sprintf( '<a href="#%1$s" class="nav-tab" id="%1$s-tab">%2$s</a>', $tab['id'], $tab['title']);397 $html .= sprintf( '<a href="#%1$s" class="nav-tab" id="%1$s-tab">%2$s</a>', esc_attr( esc_url( $tab['id'] ) ), esc_html( $tab['title'] ) ); 398 398 } 399 399 … … 413 413 <div class="postbox"> 414 414 <?php foreach ( $this->settings_sections as $form ) { ?> 415 <div id="<?php echo $form['id']; ?>" class="group inside">415 <div id="<?php echo esc_attr( $form['id'] ); ?>" class="group inside"> 416 416 <form method="post" action="options.php"> 417 417 -
frontend-uploader/trunk/lib/views/manage-ugc-media.tpl.php
r1402587 r1971315 3 3 set_current_screen( 'upload' ); 4 4 if ( ! current_user_can( 'upload_files' ) ) 5 wp_die( __( 'You do not have permission to upload files.', 'frontend-uploader' ) );5 wp_die( esc_html__( 'You do not have permission to upload files.', 'frontend-uploader' ) ); 6 6 7 7 $wp_list_table = new FU_WP_Media_List_Table(); … … 12 12 ?> 13 13 <div class="wrap"> 14 <?php screen_icon(); ?>15 14 <h2><?php echo esc_html( $title ); ?> <?php 16 15 if ( isset( $_REQUEST['s'] ) && $_REQUEST['s'] ) 17 printf( '<span class="subtitle">' . __( 'Search results for “%s”', 'frontend-uploader' ) . '</span>', get_search_query() ); ?>16 printf( '<span class="subtitle">' . esc_html__( 'Search results for “%s”', 'frontend-uploader' ) . '</span>', get_search_query() ); ?> 18 17 </h2> 19 18 … … 38 37 if ( isset( $_GET['trashed'] ) && (int) $_GET['trashed'] ) { 39 38 $message = sprintf( _n( 'Media attachment moved to the trash.', '%d media attachments moved to the trash.', $_GET['trashed'] ), number_format_i18n( $_GET['trashed'] ) ); 40 $message .= ' <a href="' . esc_url( wp_nonce_url( 'upload.php?doaction=undo&action=untrash&ids='.( isset( $_GET['ids'] ) ? $_GET['ids']: '' ), "bulk-media" ) ) . '">' . __( 'Undo', 'frontend-uploader' ) . '</a>';39 $message .= ' <a href="' . esc_url( wp_nonce_url( 'upload.php?doaction=undo&action=untrash&ids='.( isset( $_GET['ids'] ) ? sanitize_text_field( $_GET['ids'] ) : '' ), "bulk-media" ) ) . '">' . __( 'Undo', 'frontend-uploader' ) . '</a>'; 41 40 $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'trashed' ), $_SERVER['REQUEST_URI'] ); 42 41 } 43 42 44 43 if ( isset( $_GET['untrashed'] ) && (int) $_GET['untrashed'] ) { 45 $message = sprintf( _n( 'Media attachment restored from the trash.', '%d media attachments restored from the trash.', $_GET['untrashed']), number_format_i18n( $_GET['untrashed'] ) );44 $message = sprintf( _n( 'Media attachment restored from the trash.', '%d media attachments restored from the trash.', sanitize_text_field( $_GET['untrashed'] ) ), number_format_i18n( $_GET['untrashed'] ) ); 46 45 $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'untrashed' ), $_SERVER['REQUEST_URI'] ); 47 46 } … … 54 53 $messages[2] = __( 'Media permanently deleted.', 'frontend-uploader' ); 55 54 $messages[3] = __( 'Error saving media attachment.', 'frontend-uploader' ); 56 $messages[4] = __( 'Media moved to the trash.', 'frontend-uploader' ) . ' <a href="' . esc_url( wp_nonce_url( 'upload.php?doaction=undo&action=untrash&ids='.( isset( $_GET['ids'] ) ? $_GET['ids']: '' ), "bulk-media" ) ) . '">' . __( 'Undo', 'frontend-uploader' ) . '</a>';55 $messages[4] = __( 'Media moved to the trash.', 'frontend-uploader' ) . ' <a href="' . esc_url( wp_nonce_url( 'upload.php?doaction=undo&action=untrash&ids='.( isset( $_GET['ids'] ) ? sanitize_text_field( $_GET['ids'] ) : '' ), "bulk-media" ) ) . '">' . __( 'Undo', 'frontend-uploader' ) . '</a>'; 57 56 $messages[5] = __( 'Media restored from the trash.', 'frontend-uploader' ); 58 57 59 58 if ( isset( $_GET['message'] ) && (int) $_GET['message'] ) { 60 $message = $messages[ $_GET['message']];59 $message = $messages[ sanitize_text_field( $_GET['message'] ) ]; 61 60 $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'message' ), $_SERVER['REQUEST_URI'] ); 62 61 } -
frontend-uploader/trunk/lib/views/manage-ugc-posts.tpl.php
r1468826 r1971315 2 2 $title = __( 'Manage UGC Posts', 'frontend-uploader' ); 3 3 if ( ! current_user_can( 'publish_posts' ) ) 4 wp_die( __( 'You do not have permission to publish posts.', 'frontend-uploader' ) );4 wp_die( esc_html__( 'You do not have permission to publish posts.', 'frontend-uploader' ) ); 5 5 6 6 $wp_post_list_table = new FU_WP_Posts_List_Table(); … … 11 11 12 12 <div class="wrap"> 13 <?php screen_icon(); ?>14 13 <h2><?php echo esc_html( $title ); ?><?php 15 14 if ( isset( $_REQUEST['s'] ) && $_REQUEST['s'] ) 16 printf( '<span class="subtitle">' . __( 'Search results for “%s”', 'frontend-uploader' ) . '</span>', get_search_query() ); ?>15 printf( '<span class="subtitle">' . esc_html__( 'Search results for “%s”', 'frontend-uploader' ) . '</span>', get_search_query() ); ?> 17 16 </h2> 18 17 … … 36 35 37 36 if ( isset( $_GET['trashed'] ) && (int) $_GET['trashed'] ) { 38 $message = sprintf( _n( 'Post moved to the trash.', '%d Posts moved to the trash.', $_GET['trashed']), number_format_i18n( $_GET['trashed'] ) );39 $message .= ' <a href="' . esc_url( wp_nonce_url( 'upload.php?doaction=undo&action=untrash&ids='.( isset( $_GET['ids'] ) ? $_GET['ids']: '' ), "bulk-media" ) ) . '">' . __( 'Undo', 'frontend-uploader' ) . '</a>';37 $message = sprintf( _n( 'Post moved to the trash.', '%d Posts moved to the trash.', sanitize_text_field( $_GET['trashed'] ) ), number_format_i18n( $_GET['trashed'] ) ); 38 $message .= ' <a href="' . esc_url( wp_nonce_url( 'upload.php?doaction=undo&action=untrash&ids='.( isset( $_GET['ids'] ) ? sanitize_text_field( $_GET['ids'] ) : '' ), "bulk-media" ) ) . '">' . __( 'Undo', 'frontend-uploader' ) . '</a>'; 40 39 $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'trashed' ), $_SERVER['REQUEST_URI'] ); 41 40 } 42 41 43 42 if ( isset( $_GET['untrashed'] ) && (int) $_GET['untrashed'] ) { 44 $message = sprintf( _n( 'Post restored from the trash.', '%d Posts restored from the trash.', $_GET['untrashed']), number_format_i18n( $_GET['untrashed'] ) );43 $message = sprintf( _n( 'Post restored from the trash.', '%d Posts restored from the trash.', sanitize_text_field( $_GET['untrashed'] ) ), number_format_i18n( $_GET['untrashed'] ) ); 45 44 $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'untrashed' ), $_SERVER['REQUEST_URI'] ); 46 45 } … … 53 52 $messages[2] = __( 'Media permanently deleted.', 'frontend-uploader' ); 54 53 $messages[3] = __( 'Error saving Post.', 'frontend-uploader' ); 55 $messages[4] = __( 'Media moved to the trash.', 'frontend-uploader' ) . ' <a href="' . esc_url( wp_nonce_url( 'upload.php?doaction=undo&action=untrash&ids='.( isset( $_GET['ids'] ) ? $_GET['ids']: '' ), "bulk-media" ) ) . '">' . __( 'Undo', 'frontend-uploader' ) . '</a>';54 $messages[4] = __( 'Media moved to the trash.', 'frontend-uploader' ) . ' <a href="' . esc_url( wp_nonce_url( 'upload.php?doaction=undo&action=untrash&ids='.( isset( $_GET['ids'] ) ? sanitize_text_field( $_GET['ids'] ) : '' ), "bulk-media" ) ) . '">' . __( 'Undo', 'frontend-uploader' ) . '</a>'; 56 55 $messages[5] = __( 'Media restored from the trash.', 'frontend-uploader' ); 57 56 58 57 if ( isset( $_GET['message'] ) && (int) $_GET['message'] ) { 59 $message = $messages[ $_GET['message']];58 $message = $messages[ sanitize_text_field( $_GET['message'] ) ]; 60 59 $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'message' ), $_SERVER['REQUEST_URI'] ); 61 60 } 62 61 63 62 if ( !empty( $message ) ) { ?> 64 <div id="message" class="updated"><p><?php echo $message; ?></p></div>63 <div id="message" class="updated"><p><?php echo esc_html( $message ); ?></p></div> 65 64 <?php } ?> 66 65 -
frontend-uploader/trunk/readme.txt
r1734078 r1971315 4 4 Tags: frontend, image, images, media, uploader, upload, video, audio, photo, photos, picture, pictures, file, user generated content, ugc, frontend upload 5 5 Requires at least: 4.1 6 Tested up to: 4.8.27 Stable tag: 1.3. 16 Tested up to: 5.0 7 Stable tag: 1.3.2 8 8 License: GPLv2 or later 9 9 … … 341 341 == Changelog == 342 342 343 = 1.3.2 (Nov 2, 2018) = 344 * Bugfix: allow multiple forms to be properly validated if they're rendered on the same page. 345 * Feature: add support for all HTML5 input types 346 343 347 = 1.3.1 (Sep 21, 2017) = 344 348 * Bugfix: fix blank page in Manage UGC on Windows machines
Note: See TracChangeset
for help on using the changeset viewer.