<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class WP_OJS_SSO_User_Meta {
private static $instance = null;
public static function instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
add_filter( 'manage_users_columns', [ $this, 'add_column' ] );
add_filter( 'manage_users_custom_column', [ $this, 'column_content' ], 10, 3 );
add_filter( 'manage_users_sortable_columns', [ $this, 'sortable_column' ] );
add_action( 'pre_get_users', [ $this, 'sort_by_meta' ] );
add_filter( 'bulk_actions-users', [ $this, 'register_bulk_actions' ] );
add_filter( 'handle_bulk_actions-users', [ $this, 'handle_bulk_actions' ], 10, 3 );
add_filter( 'views_users', [ $this, 'subscription_views' ] );
add_action( 'pre_get_users', [ $this, 'filter_users' ] );
}
private function meta_key() {
return WP_OJS_SSO_Plugin::get_option( 'user_meta_key', 'ojs_subscription_active' );
}
private function meta_label() {
return WP_OJS_SSO_Plugin::get_option( 'user_meta_label', __( 'OJS Subscription', 'wp-ojs-sso-bridge' ) );
}
/**
* @param string $filter One of active, requested, none.
* @return array<int, array<string, mixed>>
*/
private function get_subscription_meta_query( $filter ) {
$key = $this->meta_key();
switch ( $filter ) {
case 'active':
return [
[
'key' => $key,
'value' => '1',
'compare' => '=',
],
];
case 'requested':
return [
[
'key' => 'ojs_subscription_requested',
'value' => '1',
'compare' => '=',
],
[
'relation' => 'OR',
[
'key' => $key,
'compare' => 'NOT EXISTS',
],
[
'key' => $key,
'value' => '1',
'compare' => '!=',
],
],
];
case 'none':
return [
[
'relation' => 'OR',
[
'key' => 'ojs_subscription_requested',
'compare' => 'NOT EXISTS',
],
[
'key' => 'ojs_subscription_requested',
'value' => '1',
'compare' => '!=',
],
],
];
}
return [];
}
/**
* @param string $filter One of active, requested, none.
* @return int
*/
private function count_users_by_subscription_filter( $filter ) {
$meta_query = $this->get_subscription_meta_query( $filter );
if ( empty( $meta_query ) ) {
return 0;
}
$query = new WP_User_Query(
[
'fields' => 'ID',
'number' => 1,
'count_total' => true,
'meta_query' => $meta_query,
]
);
return (int) $query->get_total();
}
/**
* Quick-filter links above the users list (alongside role views).
*
* @param array<string, string> $views Existing views.
* @return array<string, string>
*/
public function subscription_views( $views ) {
if ( ! is_admin() ) {
return $views;
}
$current = isset( $_GET['ojs_sub_filter'] ) ? sanitize_key( wp_unslash( $_GET['ojs_sub_filter'] ) ) : '';
$base = admin_url( 'users.php' );
$filters = [
'requested' => __( 'Subscription requested', 'wp-ojs-sso-bridge' ),
'active' => __( 'Active subscription', 'wp-ojs-sso-bridge' ),
];
foreach ( $filters as $slug => $label ) {
$count = $this->count_users_by_subscription_filter( $slug );
$url = add_query_arg( 'ojs_sub_filter', $slug, $base );
$text = sprintf(
/* translators: 1: filter label, 2: number of users */
__( '%1$s <span class="count">(%2$s)</span>', 'wp-ojs-sso-bridge' ),
$label,
number_format_i18n( $count )
);
$views[ 'ojs_sub_' . $slug ] = sprintf(
'<a href="%s"%s>%s</a>',
esc_url( $url ),
( $current === $slug ) ? ' class="current"' : '',
$text
);
}
return $views;
}
public function add_column( $columns ) {
$columns['ojs_subscription'] = $this->meta_label();
$columns['ojs_sub_files'] = __( 'Subscription documents', 'wp-ojs-sso-bridge' );
return $columns;
}
public function column_content( $value, $column_name, $user_id ) {
if ( 'ojs_sub_files' === $column_name ) {
return $this->documents_column_html( (int) $user_id );
}
if ( 'ojs_subscription' !== $column_name ) {
return $value;
}
$active = (bool) get_user_meta( $user_id, $this->meta_key(), true );
$requested = (bool) get_user_meta( $user_id, 'ojs_subscription_requested', true );
if ( $active ) {
return '<span style="color:#46b450;font-weight:600;">' . esc_html__( 'Active', 'wp-ojs-sso-bridge' ) . '</span>';
}
if ( $requested ) {
return '<span style="color:#ffb900;font-weight:600;">' . esc_html__( 'Requested', 'wp-ojs-sso-bridge' ) . '</span>';
}
return '—';
}
/**
* Bonifico + Certificato links (or em dash) for the users list table.
*
* @param int $user_id User ID.
* @return string
*/
private function documents_column_html( $user_id ) {
if ( ! class_exists( 'WP_OJS_SSO_Subscription_Media' ) ) {
return '—';
}
$dash = '—';
$bid = WP_OJS_SSO_Subscription_Media::get_attachment_id( $user_id, WP_OJS_SSO_Subscription_Media::KIND_BONIFICO );
if ( $bid > 0 && current_user_can( 'edit_post', $bid ) ) {
$blink = get_edit_post_link( $bid, 'raw' );
$bon = $blink
? '<a href="' . esc_url( $blink ) . '">' . esc_html__( 'Open', 'wp-ojs-sso-bridge' ) . '</a>'
: $dash;
} else {
$bon = $dash;
}
$cid = WP_OJS_SSO_Subscription_Media::get_attachment_id( $user_id, WP_OJS_SSO_Subscription_Media::KIND_CERTIFICATO );
if ( $cid > 0 && current_user_can( 'edit_post', $cid ) ) {
$clink = get_edit_post_link( $cid, 'raw' );
$cert = $clink
? '<a href="' . esc_url( $clink ) . '">' . esc_html__( 'Open', 'wp-ojs-sso-bridge' ) . '</a>'
: $dash;
} else {
$legacy = WP_OJS_SSO_Subscription_Media::get_legacy_path( $user_id );
if ( $legacy && is_readable( $legacy ) ) {
$durl = WP_OJS_SSO_File_Upload::get_admin_download_url( $user_id );
$cert = '<a href="' . esc_url( $durl ) . '">' . esc_html__( 'Download', 'wp-ojs-sso-bridge' ) . '</a>';
} else {
$cert = $dash;
}
}
return sprintf(
/* translators: 1: Bonifico label, 2: link or dash, 3: Certificato label, 4: link or dash */
'<span class="ojs-sub-docs-col">%1$s %2$s · %3$s %4$s</span>',
'<span class="screen-reader-text">' . esc_html__( 'Bank transfer receipt', 'wp-ojs-sso-bridge' ) . ': </span>' . esc_html__( 'Bonifico', 'wp-ojs-sso-bridge' ) . ':',
$bon,
esc_html__( 'Certificato', 'wp-ojs-sso-bridge' ) . ':',
$cert
);
}
public function sortable_column( $columns ) {
$columns['ojs_subscription'] = 'ojs_subscription';
return $columns;
}
public function sort_by_meta( $query ) {
if ( ! is_admin() || 'ojs_subscription' !== ( $query->get( 'orderby' ) ) ) {
return;
}
$query->set( 'meta_key', $this->meta_key() );
$query->set( 'orderby', 'meta_value' );
}
public function register_bulk_actions( $actions ) {
$actions['ojs_activate_subscription'] = __( 'Activate OJS Subscription', 'wp-ojs-sso-bridge' );
$actions['ojs_deactivate_subscription'] = __( 'Deactivate OJS Subscription', 'wp-ojs-sso-bridge' );
return $actions;
}
public function handle_bulk_actions( $redirect_to, $doaction, $user_ids ) {
if ( ! current_user_can( 'edit_users' ) ) {
return $redirect_to;
}
$key = $this->meta_key();
if ( 'ojs_activate_subscription' === $doaction ) {
foreach ( $user_ids as $uid ) {
update_user_meta( $uid, $key, '1' );
do_action( 'wp_ojs_sso_subscription_changed', $uid, true );
}
$redirect_to = add_query_arg( 'ojs_bulk_activated', count( $user_ids ), $redirect_to );
}
if ( 'ojs_deactivate_subscription' === $doaction ) {
foreach ( $user_ids as $uid ) {
$old = (bool) get_user_meta( $uid, $key, true );
update_user_meta( $uid, $key, '' );
if ( $old ) {
$sessions = WP_Session_Tokens::get_instance( $uid );
$sessions->destroy_all();
}
do_action( 'wp_ojs_sso_subscription_changed', $uid, false );
}
$redirect_to = add_query_arg( 'ojs_bulk_deactivated', count( $user_ids ), $redirect_to );
}
return $redirect_to;
}
public function filter_users( $query ) {
if ( ! is_admin() ) {
return;
}
global $pagenow;
if ( 'users.php' !== $pagenow ) {
return;
}
$filter = isset( $_GET['ojs_sub_filter'] ) ? sanitize_key( wp_unslash( $_GET['ojs_sub_filter'] ) ) : '';
if ( empty( $filter ) ) {
return;
}
$clauses = $this->get_subscription_meta_query( $filter );
if ( empty( $clauses ) ) {
return;
}
$meta_query = $query->get( 'meta_query' ) ?: [];
foreach ( $clauses as $clause ) {
$meta_query[] = $clause;
}
$query->set( 'meta_query', $meta_query );
}
}