Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion alerts/class-alert-trigger-action.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public function add_fields( $form, $alert = array() ) {
'placeholder' => __( 'Any Action', 'stream' ),
),
);
$form->add_field( 'select2', $args );
$form->add_field( 'grouped_select', $args );
}

/**
Expand Down
26 changes: 10 additions & 16 deletions alerts/class-alert-trigger-author.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,17 @@ public function add_fields( $form, $alert = array() ) {
$value = $alert->alert_meta['trigger_author'];
}

$args = array(
'name' => esc_attr( $this->field_key ),
'value' => esc_attr( $value ),
'options' => $this->get_values(),
'classes' => 'wp_stream_ajax_forward',
'data' => array(
'placeholder' => __( 'Any Author', 'stream' ),
),
$form->add_field(
'grouped_select',
array(
'name' => esc_attr( $this->field_key ),
'value' => esc_attr( $value ),
'options' => $this->get_values(),
'data' => array(
'placeholder' => __( 'Any Author', 'stream' ),
),
)
);
$form->add_field( 'select2', $args );
}

/**
Expand All @@ -80,13 +81,6 @@ public function add_fields( $form, $alert = array() ) {
public function get_values() {
$all_records = array();

$user_count = count_users();
$total_users = $user_count['total_users'];

if ( $total_users > $this->plugin->admin->preload_users_max ) {
return array();
}

$users = array_map(
function ( $user_id ) {
return new Author( $user_id );
Expand Down
2 changes: 1 addition & 1 deletion alerts/class-alert-trigger-context.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public function add_fields( $form, $alert = array() ) {
$context_values = array();

$form->add_field(
'select2',
'grouped_select',
array(
'name' => 'wp_stream_trigger_connector_or_context',
'options' => $this->get_values(),
Expand Down
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### Enhancements

- Add an Outgoing Webhook alert (HTTP POST or PUT, optional headers, JSON body with record-field placeholders). IFTTT is no longer offered when creating a new alert; existing IFTTT alerts still fire. To keep using Maker, configure a webhook whose URL is `https://maker.ifttt.com/trigger/{event}/with/key/{key}`.
- Replace Select2 with native `<select>` elements across the admin (records filters, settings exclude rules, alert triggers). Author/role filters offer every user in grouped native selects; IP exclusion rules accept a comma-separated list in a plain text field. Relative timestamps now use `Intl.RelativeTimeFormat` (locale-aware) with the same bold relative + absolute date presentation as before. The `select2` and `jquery-timeago` dependencies and their bundled vendor copies are gone, and the unused `stream_get_users` and `stream_get_ips` Ajax actions were removed. Editing an alert now also regenerates its list title ("Author > Context > Action") so it matches the saved triggers instead of keeping the creation-time summary.
- Stop tracking Jetpack modules that no longer exist (Google+ authorship, Mobile theme, Custom CSS). Remaining Jetpack module logging was audited against Jetpack 15.5 on 2026-09-07.

### Development
Expand Down
8 changes: 2 additions & 6 deletions classes/class-admin-assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ public function admin_enqueue_scripts( $hook ) {
if ( in_array( $hook, $this->admin->menu->screen_id, true ) ) {
$this->admin->plugin->enqueue_asset(
'admin',
array(
$this->admin->plugin->with_jquery_timeago(),
),
array(),
array(
'i18n' => array(
'confirm_purge' => __( 'Are you sure you want to delete all Stream activity records from the database? This cannot be undone.', 'stream' ),
Expand All @@ -58,9 +56,7 @@ public function admin_enqueue_scripts( $hook ) {

$this->admin->plugin->enqueue_asset(
'admin-exclude',
array(
$this->admin->plugin->with_select2(),
),
array(),
array(
'getActionsNonce' => wp_create_nonce( 'stream_get_actions' ),
)
Expand Down
1 change: 0 additions & 1 deletion classes/class-alerts-admin-ui.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ public function register_scripts() {
$this->plugin->enqueue_asset(
'alerts',
array(
$this->plugin->with_select2(),
'inline-edit-post',
),
array(
Expand Down
12 changes: 12 additions & 0 deletions classes/class-alerts-list.php
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,18 @@ public function save_alert_inline_edit( $data, $postarr ) {
);
$alert_meta = apply_filters( 'wp_stream_alerts_save_meta', $alert_meta, $alert_type );
update_post_meta( $post_id, 'alert_meta', $alert_meta );

// Keep the generated title in sync with the saved triggers. The alerts
// list displays post_title, which was previously only built at creation,
// so editing a trigger left the list showing a stale summary.
$item = (object) array(
'alert_type' => $alert_type,
'alert_meta' => $alert_meta,
'alert_status' => $alert_status,
);
$alert = new Alert( $item, $this->plugin );

$data['post_title'] = $alert->get_title();
return $data;
}
}
103 changes: 74 additions & 29 deletions classes/class-form-generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,16 @@ public function render_field( $field_type, $args, $echo_output = true ) {
$output = '';
switch ( $field_type ) {
case 'text':
$placeholder = '';
if ( ! empty( $args['data']['placeholder'] ) ) {
$placeholder = sprintf( ' placeholder="%s"', esc_attr( $args['data']['placeholder'] ) );
}
$output = sprintf(
'<input type="text" name="%1$s" id="%1$s" class="%2$s" value="%3$s" />',
'<input type="text" name="%1$s" id="%1$s" class="%2$s" value="%3$s"%4$s />',
esc_attr( $args['name'] ),
esc_attr( $args['classes'] ),
esc_attr( $args['value'] )
esc_attr( $args['value'] ),
$placeholder
);
break;
case 'hidden':
Expand Down Expand Up @@ -119,20 +124,28 @@ public function render_field( $field_type, $args, $echo_output = true ) {
}
$output .= '</select>';
break;
case 'select2':
case 'grouped_select':
$values = array();

$multiple = ( $args['multiple'] ) ? ' multiple' : '';
$output = sprintf(
'<select name="%1$s" id="%1$s" class="select2-select %2$s" %3$s%4$s>',
$label = '';
if ( ! empty( $args['data']['placeholder'] ) ) {
$label = sprintf( ' aria-label="%s"', esc_attr( $args['data']['placeholder'] ) );
}
$output = sprintf(
'<select name="%1$s" id="%1$s" class="%2$s" %3$s%4$s%5$s>',
esc_attr( $args['name'] ),
esc_attr( $args['classes'] ),
$this->prepare_data_attributes_string( $args['data'] ), // The data attributes are escaped in the function.
$multiple
$multiple,
$label
);

if ( array_key_exists( 'placeholder', $args['data'] ) && ! $multiple ) {
$output .= '<option value=""></option>';
$output .= sprintf(
'<option value="">%s</option>',
esc_html( $args['data']['placeholder'] )
);
}

foreach ( $args['options'] as $parent ) {
Expand All @@ -144,38 +157,36 @@ public function render_field( $field_type, $args, $echo_output = true ) {
'children' => array(),
)
);
if ( empty( $parent['value'] ) ) {
if ( '' === (string) $parent['value'] && empty( $parent['children'] ) ) {
continue;
}
if ( is_array( $args['value'] ) ) {
$selected = selected( in_array( $parent['value'], $args['value'], true ), true, false );
} else {
$selected = selected( $args['value'], $parent['value'], false );
}
$output .= sprintf(
'<option class="parent" value="%1$s" %2$s>%3$s</option>',
esc_attr( $parent['value'] ),
$selected,
esc_html( $parent['text'] )
);
$values[] = $parent['value'];
if ( ! empty( $parent['children'] ) ) {

// Group header (no value of its own): render children inside an optgroup.
if ( '' === (string) $parent['value'] ) {
$output .= sprintf(
'<optgroup label="%s">',
esc_attr( $parent['text'] )
);
foreach ( $parent['children'] as $child ) {
$output .= sprintf(
'<option class="child" value="%1$s" %2$s>%3$s</option>',
esc_attr( $child['value'] ),
selected( $args['value'], $child['value'], false ),
esc_html( $child['text'] )
);
$output .= $this->render_select_option( $child, $args['value'] );
$values[] = $child['value'];
}
$output .= '</optgroup>';
continue;
}

// Selectable parent option followed by its children, matching the previous flat markup.
$output .= $this->render_select_option( $parent, $args['value'], 'parent' );
$values[] = $parent['value'];
foreach ( $parent['children'] as $child ) {
$output .= $this->render_select_option( $child, $args['value'], 'child' );
$values[] = $child['value'];
}
}

$selected_values = explode( ',', $args['value'] );
$selected_values = is_array( $args['value'] ) ? $args['value'] : explode( ',', (string) $args['value'] );
foreach ( $selected_values as $selected_value ) {
if ( ! empty( $selected_value ) && ! in_array( $selected_value, array_map( 'strval', $values ), true ) ) {
if ( ! empty( $selected_value ) && ! in_array( (string) $selected_value, array_map( 'strval', $values ), true ) ) {
$output .= sprintf(
'<option value="%1$s" selected="selected">%2$s</option>',
esc_attr( $selected_value ),
Expand Down Expand Up @@ -210,6 +221,40 @@ public function render_field( $field_type, $args, $echo_output = true ) {
echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}

/**
* Render a single <option> for a native select.
*
* @param array $option Option array (`value`, `text`).
* @param string|array $current Currently selected value(s).
* @param string $css_class Optional option class ('parent' or 'child').
* @return string
*/
private function render_select_option( $option, $current, $css_class = '' ) {
$option = wp_parse_args(
$option,
array(
'value' => '',
'text' => '',
)
);

if ( is_array( $current ) ) {
$selected = selected( in_array( (string) $option['value'], array_map( 'strval', $current ), true ), true, false );
} else {
$selected = selected( (string) $current, (string) $option['value'], false );
}

$class_attr = '' !== $css_class ? sprintf( ' class="%s"', esc_attr( $css_class ) ) : '';

return sprintf(
'<option%1$s value="%2$s" %3$s>%4$s</option>',
$class_attr,
esc_attr( $option['value'] ),
$selected,
esc_html( $option['text'] )
);
}

/**
* Prepares string with HTML data attributes
*
Expand Down
2 changes: 1 addition & 1 deletion classes/class-list-table.php
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ public function filter_date( $items ) {
<div class="date-interval">

<select class="field-predefined hide-if-no-js chosen-select" name="date_predefined" data-placeholder="<?php esc_attr_e( 'All Time', 'stream' ); ?>">
<option></option>
<option value=""><?php esc_html_e( 'All Time', 'stream' ); ?></option>
<option value="custom" <?php selected( 'custom' === $date_predefined ); ?>><?php esc_attr_e( 'Custom', 'stream' ); ?></option>
<?php
foreach ( $items as $key => $interval ) {
Expand Down
2 changes: 1 addition & 1 deletion classes/class-log.php
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ public function record_matches_rules( $record, $exclude_rules ) {
}

if ( 'ip_address' === $exclude_key ) {
$ip_addresses = explode( ',', $exclude_value );
$ip_addresses = array_filter( array_map( 'trim', explode( ',', (string) $exclude_value ) ) );

if ( in_array( $record['ip_address'], $ip_addresses, true ) ) {
++$matches_found;
Expand Down
94 changes: 0 additions & 94 deletions classes/class-plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -574,98 +574,4 @@ public function enqueue_asset( $handle, $additional_dependencies = array(), $dat
);
}
}

/**
* Enqueue select2 script and locale file if exists.
*
* @return string Script handle.
*/
public function with_select2() {
$handle = 'wp-stream-select2';

// If is enqueued already, bail out.
if ( wp_script_is( $handle ) ) {
return $handle;
}

$path = untrailingslashit( $this->locations['dir'] );
$url = untrailingslashit( $this->locations['url'] );

wp_enqueue_script(
$handle,
"$url/build/select2/js/select2.full.min.js",
array( 'jquery' ),
filemtime( "$path/build/select2/js/select2.full.min.js" ),
true
);
wp_enqueue_style(
$handle,
"$url/build/select2/css/select2.min.css",
array(),
filemtime( "$path/build/select2/css/select2.min.css" )
);

$locale = get_locale();
$lang = substr( $locale, 0, 2 );
$search_files = array( $locale, $lang, 'en' );

foreach ( $search_files as $search_file ) {
if ( file_exists( "$path/build/select2/js/i18n/$search_file.js" ) ) {
wp_enqueue_script(
sanitize_title( "$handle-$search_file" ),
"$url/build/select2/js/i18n/$search_file.js",
array( $handle ),
filemtime( "$path/build/select2/js/i18n/$search_file.js" ),
true
);
break;
}
}

return $handle;
}

/**
* Enqueue jquery.timeago script and locale file if exists.
*
* @return string Script handle.
*/
public function with_jquery_timeago() {
$handle = 'wp-stream-jquery-timeago';

// If is enqueued already, bail out.
if ( wp_script_is( $handle ) ) {
return $handle;
}

$path = untrailingslashit( $this->locations['dir'] );
$url = untrailingslashit( $this->locations['url'] );

wp_enqueue_script(
$handle,
"$url/build/timeago/js/jquery.timeago.js",
array( 'jquery' ),
filemtime( "$path/build/timeago/js/jquery.timeago.js" ),
true
);

$locale = get_locale();
$lang = substr( $locale, 0, 2 );
$search_files = array( $locale, $lang, 'en' );

foreach ( $search_files as $search_file ) {
if ( file_exists( "$path/build/timeago/js/locales/jquery.timeago.$search_file.js" ) ) {
wp_enqueue_script(
sanitize_title( "$handle-$search_file" ),
"$url/build/timeago/js/locales/jquery.timeago.$search_file.js",
array( $handle ),
filemtime( "$path/build/timeago/js/locales/jquery.timeago.$search_file.js" ),
true
);
break;
}
}

return $handle;
}
}
Loading
Loading