diff --git a/classes/class-settings.php b/classes/class-settings.php
index 7aead3bd1..fa00b7b20 100644
--- a/classes/class-settings.php
+++ b/classes/class-settings.php
@@ -551,12 +551,12 @@ public function sanitize_settings( $input ) {
// Support all values in multidimentional arrays too.
array_walk_recursive(
$output[ $name ],
- function ( &$v, $k ) {
- $v = trim( $v );
+ function ( &$v ) {
+ $v = sanitize_text_field( trim( $v ) );
}
);
} else {
- $output[ $name ] = trim( $input[ $name ] );
+ $output[ $name ] = sanitize_text_field( trim( $input[ $name ] ) );
}
}
}
@@ -848,7 +848,7 @@ public function render_field( $field ) {
}
// Prepend an empty row.
- $current_value['exclude_row'] = array( 'helper' => '' ) + ( isset( $current_value['exclude_row'] ) ? $current_value['exclude_row'] : array() );
+ $current_value['exclude_row'] = ( isset( $current_value['exclude_row'] ) ? $current_value['exclude_row'] : array() ) + array( 'helper' => '' );
foreach ( $current_value['exclude_row'] as $key => $value ) {
// Prepare values.
diff --git a/ui/js/exclude.js b/ui/js/exclude.js
index 1b6416f90..d74d33ed0 100644
--- a/ui/js/exclude.js
+++ b/ui/js/exclude.js
@@ -1,10 +1,13 @@
/* globals jQuery, ajaxurl, wp_stream_regenerate_alt_rows */
jQuery(
function( $ ) {
- var initSettingsSelect2 = function() {
+ var $excludeRows = $( '.stream-exclude-list tbody tr:not(.hidden)' );
+ var $placeholderRow = $( '.stream-exclude-list tr.helper' );
+
+ var initSettingsSelect2 = function( $rowsWithSelect2 ) {
var $input_user;
- $( '.stream-exclude-list tr:not(.hidden) select.select2-select.connector_or_context' ).each(
+ $( 'select.select2-select.connector_or_context', $rowsWithSelect2 ).each(
function( k, el ) {
$( el ).select2(
{
@@ -64,7 +67,7 @@ jQuery(
}
);
- $( '.stream-exclude-list tr:not(.hidden) select.select2-select.action' ).each(
+ $( 'select.select2-select.action', $rowsWithSelect2 ).each(
function( k, el ) {
$( el ).select2(
{
@@ -74,7 +77,7 @@ jQuery(
}
);
- $( '.stream-exclude-list tr:not(.hidden) select.select2-select.author_or_role' ).each(
+ $( 'select.select2-select.author_or_role', $rowsWithSelect2 ).each(
function( k, el ) {
$input_user = $( el );
@@ -173,7 +176,7 @@ jQuery(
}
);
- $( '.stream-exclude-list tr:not(.hidden) select.select2-select.ip_address' ).each(
+ $( 'select.select2-select.ip_address', $rowsWithSelect2 ).each(
function( k, el ) {
var $input_ip = $( el ),
searchTerm = '';
@@ -271,7 +274,7 @@ jQuery(
}
);
- $( '.stream-exclude-list tr:not(.hidden) .exclude_rules_remove_rule_row' ).on(
+ $( '.exclude_rules_remove_rule_row', $rowsWithSelect2 ).on(
'click', function() {
var $thisRow = $( this ).closest( 'tr' );
@@ -283,16 +286,16 @@ jQuery(
);
};
- initSettingsSelect2();
+ initSettingsSelect2( $excludeRows );
- $( '.stream-exclude-list tr:not(.hidden) select.select2-select.author_or_role' ).each(
+ $( 'select.select2-select.author_or_role', $excludeRows ).each(
function() {
var $option = $( '' ).val( $( this ).data( 'selected-id' ) );
$( this ).append( $option ).trigger( 'change' );
}
);
- $( '.stream-exclude-list tr:not(.hidden) select.select2-select.connector_or_context' ).each(
+ $( 'select.select2-select.connector_or_context', $excludeRows ).each(
function() {
var parts = [
$( this ).siblings( '.connector' ).val(),
@@ -307,25 +310,12 @@ jQuery(
$( '#exclude_rules_new_rule' ).on(
'click', function() {
- var $excludeList = $( 'table.stream-exclude-list' );
-
- $( 'tr:not(.hidden) select.select2-select', $excludeList ).each(
- function() {
- $( this ).select2( 'destroy' );
- }
- );
-
- var $lastRow = $( 'tr', $excludeList ).last(),
- $newRow = $lastRow.clone();
+ var $newRow = $placeholderRow.clone();
$newRow.removeAttr( 'class' );
- $( '.stream-exclude-list tbody :input' ).off();
- $( ':input', $newRow ).off().val( '' );
-
- $lastRow.after( $newRow );
-
- initSettingsSelect2();
+ $newRow.insertBefore( $placeholderRow );
+ initSettingsSelect2( $newRow );
recalculate_rules_found();
recalculate_rules_selected();
}
@@ -369,6 +359,12 @@ jQuery(
$( '.stream-exclude-list tbody tr:not(.hidden) select.select2-select.ip_address', this ).each(
function() {
var firstSelected = $( 'option:selected', this ).first();
+
+ // Ugly hack to ensure we always pass an empty value or the order of rows gets messed up.
+ if ( ! firstSelected.length ) {
+ $( this ).append( '' );
+ }
+
$( 'option:selected:not(:first)', this ).each(
function() {
firstSelected.attr( 'value', firstSelected.attr( 'value' ) + ',' + $( this ).attr( 'value' ) );