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
106 changes: 78 additions & 28 deletions Lib/WeDevs_Settings_API.php
Original file line number Diff line number Diff line change
Expand Up @@ -358,50 +358,100 @@ function callback_multicheck( $args ) {
* @return void
*/
function callback_gateway_selector( $args ) {
$this->render_card_selector(
$args,
[
'block' => 'wpuf-gateway-card',
'data_attribute' => 'data-gateway',
]
);
}

/**
* Displays a card grid for selecting from a generic list of methods
*
* Reuses the same card UI as `gateway_selector` but emits its own
* BEM namespace so the two selector types can evolve independently.
* Used for things like 2FA methods, social login providers, etc.
*
* @since WPUF_SINCE
*
* @param array $args settings field args
*
* @return void
*/
function callback_method_selector( $args ) {
$this->render_card_selector(
$args,
[
'block' => 'wpuf-method-card',
'data_attribute' => 'data-method',
]
);
}

/**
* Shared renderer for card-grid selector field types
*
* Used by `gateway_selector` and `method_selector`. The BEM block name
* and per-card data attribute come from $config so each caller emits
* its own CSS namespace and JS hook target.
*
* @since WPUF_SINCE
*
* @param array $args settings field args
* @param array $config renderer configuration: block, data_attribute
*
* @return void
*/
private function render_card_selector( $args, $config ) {
$value = $this->get_option( $args['id'], $args['section'], $args['std'] );
$value = $value ? $value : [];

$block = $config['block'];
$data_attribute = $config['data_attribute'];

// Inline SVG fallback icons (no image files exist for these)
$bank_svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="48" height="48" fill="none" stroke="#787c82" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18"/><path d="M3 10h18"/><path d="M12 3l9 7H3l9-7z"/><path d="M5 10v8"/><path d="M9 10v8"/><path d="M15 10v8"/><path d="M19 10v8"/></svg>';
$generic_svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="48" height="48" fill="none" stroke="#787c82" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="1" y="4" width="22" height="16" rx="2" ry="2"/><line x1="1" y1="10" x2="23" y2="10"/></svg>';
?>
<fieldset>
<input type="hidden" name="<?php echo esc_attr( $args['section'] ); ?>[<?php echo esc_attr( $args['id'] ); ?>]" value="" />

<div class="wpuf-gateway-cards">
<?php foreach ( $args['options'] as $key => $gateway ) :
<div class="<?php echo esc_attr( $block . 's' ); ?>">
<?php foreach ( $args['options'] as $key => $option ) :
$is_checked = in_array( $key, $value, true );
$is_pro = ! empty( $gateway['is_pro_preview'] ) && $gateway['is_pro_preview'];
$is_pro = ! empty( $option['is_pro_preview'] ) && $option['is_pro_preview'];
$disabled = $is_pro ? 'disabled' : '';
$active_class = $is_checked ? ' wpuf-gateway-card--active' : '';
$pro_class = $is_pro ? ' wpuf-gateway-card--pro-locked' : '';
$icon = ! empty( $gateway['icon'] ) ? $gateway['icon'] : '';
$admin_label = $gateway['admin_label'];
$active_class = $is_checked ? ' ' . $block . '--active' : '';
$pro_class = $is_pro ? ' ' . $block . '--pro-locked' : '';
$icon = ! empty( $option['icon'] ) ? $option['icon'] : '';
$admin_label = isset( $option['admin_label'] ) ? $option['admin_label'] : (string) $key;
?>
<div class="wpuf-gateway-card<?php echo esc_attr( $active_class . $pro_class ); ?>"
data-gateway="<?php echo esc_attr( $key ); ?>">
<div class="<?php echo esc_attr( $block . $active_class . $pro_class ); ?>"
<?php echo esc_attr( $data_attribute ); ?>="<?php echo esc_attr( $key ); ?>">

<input type="checkbox"
class="wpuf-gateway-card__checkbox"
class="<?php echo esc_attr( $block . '__checkbox' ); ?>"
id="wpuf-<?php echo esc_attr( $args['section'] ); ?>[<?php echo esc_attr( $args['id'] ); ?>][<?php echo esc_attr( $key ); ?>]"
name="<?php echo esc_attr( $args['section'] ); ?>[<?php echo esc_attr( $args['id'] ); ?>][<?php echo esc_attr( $key ); ?>]"
value="<?php echo esc_attr( $key ); ?>"
<?php checked( $is_checked, true ); ?>
<?php echo esc_attr( $disabled ); ?> />

<label class="wpuf-gateway-card__toggle"
<label class="<?php echo esc_attr( $block . '__toggle' ); ?>"
for="wpuf-<?php echo esc_attr( $args['section'] ); ?>[<?php echo esc_attr( $args['id'] ); ?>][<?php echo esc_attr( $key ); ?>]"
title="<?php echo esc_attr( sprintf( __( 'Enable %s', 'wp-user-frontend' ), $admin_label ) ); ?>">
<svg class="wpuf-gateway-card__check-on" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="22" height="22">
<svg class="<?php echo esc_attr( $block . '__check-on' ); ?>" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="22" height="22">
<circle cx="12" cy="12" r="12" fill="#00a32a"/>
<path d="M9 12l2 2 4-4" stroke="#fff" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<svg class="wpuf-gateway-card__check-off" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="22" height="22">
<svg class="<?php echo esc_attr( $block . '__check-off' ); ?>" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="22" height="22">
<circle cx="12" cy="12" r="11" fill="none" stroke="#c3c4c7" stroke-width="2"/>
</svg>
</label>

<div class="wpuf-gateway-card__icon">
<div class="<?php echo esc_attr( $block . '__icon' ); ?>">
<?php if ( $icon ) : ?>
<img src="<?php echo esc_url( $icon ); ?>" alt="<?php echo esc_attr( $admin_label ); ?>" />
<?php elseif ( 'bank' === $key ) : ?>
Expand All @@ -411,7 +461,7 @@ class="wpuf-gateway-card__checkbox"
<?php endif; ?>
</div>

<div class="wpuf-gateway-card__name">
<div class="<?php echo esc_attr( $block . '__name' ); ?>">
<?php echo esc_html( $admin_label ); ?>
</div>
</div>
Expand Down Expand Up @@ -998,22 +1048,22 @@ function(){
for (var field_name in dependencies) {
var expected_value = dependencies[field_name];
var $depends_on = $("input[id*='"+ field_name +"'], select[id*='"+ field_name +"']");

// If no field found with the simple selector, try more specific selectors
if ($depends_on.length === 0) {
$depends_on = $("input[name*='["+ field_name +"]'], select[name*='["+ field_name +"]']");
}

// If still no field found, try looking for the field name in the ID attribute
if ($depends_on.length === 0) {
$depends_on = $("input[id*='["+ field_name +"]'], select[id*='["+ field_name +"]']");
}

// If still no field found, try looking for the field name anywhere in the ID
if ($depends_on.length === 0) {
$depends_on = $("input[id*='"+ field_name +"'], select[id*='"+ field_name +"']");
}

if ($depends_on.length === 0) {
all_dependencies_met = false;
break;
Expand All @@ -1023,7 +1073,7 @@ function(){
var current_value = $depends_on.val();
var is_checkbox = $depends_on.attr('type') === 'checkbox';
var is_checked = is_checkbox ? $depends_on.is(':checked') : null;

// For checkboxes, handle empty string as "checked" expectation
var value_matches = false;
if (is_checkbox) {
Expand All @@ -1037,7 +1087,7 @@ function(){
} else {
value_matches = current_value === expected_value;
}

if (!value_matches) {
all_dependencies_met = false;
}
Expand Down Expand Up @@ -1073,26 +1123,26 @@ function checkAllDependencies() {
for (var field_name in dependencies) {
var expected_value = dependencies[field_name];
var $depends_on = $("input[id*='"+ field_name +"'], select[id*='"+ field_name +"']");

// If no field found with the simple selector, try more specific selectors
if ($depends_on.length === 0) {
$depends_on = $("input[name*='["+ field_name +"]'], select[name*='["+ field_name +"]']");
}

// If still no field found, try looking for the field name in the ID attribute
if ($depends_on.length === 0) {
$depends_on = $("input[id*='["+ field_name +"]'], select[id*='["+ field_name +"]']");
}

// If still no field found, try looking for the field name anywhere in the ID
if ($depends_on.length === 0) {
$depends_on = $("input[id*='"+ field_name +"'], select[id*='"+ field_name +"']");
}

var current_value = $depends_on.length > 0 ? $depends_on.val() : 'NOT_FOUND';
var is_checkbox = $depends_on.length > 0 && $depends_on.attr('type') === 'checkbox';
var is_checked = is_checkbox ? $depends_on.is(':checked') : null;

// For checkboxes, handle empty string as "checked" expectation
var value_matches = false;
if ($depends_on.length === 0) {
Expand All @@ -1108,13 +1158,13 @@ function checkAllDependencies() {
} else {
value_matches = current_value === expected_value;
}

if (!value_matches) {
all_met = false;
break;
}
}

if (all_met) {
$this.closest('tr').show();
} else {
Expand Down
54 changes: 36 additions & 18 deletions assets/css/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -1502,12 +1502,14 @@ body.wpuf-modal-open {
.wpuf-login-settings-row.hidden {
display: none !important;
}
.wpuf-gateway-cards {
.wpuf-gateway-cards,
.wpuf-method-cards {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.wpuf-gateway-card {
.wpuf-gateway-card,
.wpuf-method-card {
position: relative;
display: flex;
flex-direction: column;
Expand All @@ -1521,32 +1523,39 @@ body.wpuf-modal-open {
cursor: pointer;
transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.wpuf-gateway-card:hover {
.wpuf-gateway-card:hover,
.wpuf-method-card:hover {
border-color: #c3c4c7;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
}
.wpuf-gateway-card--active:hover {
.wpuf-gateway-card--active:hover,
.wpuf-method-card--active:hover {
border-color: #10b981;
}
.wpuf-gateway-card--focused {
.wpuf-gateway-card--focused,
.wpuf-method-card--focused {
border-color: #10b981;
box-shadow: 0 0 0 1px #10b981;
}
.wpuf-gateway-card--focused:hover {
.wpuf-gateway-card--focused:hover,
.wpuf-method-card--focused:hover {
border-color: #10b981;
}
.wpuf-gateway-card--pro-locked {
.wpuf-gateway-card--pro-locked,
.wpuf-method-card--pro-locked {
opacity: 0.6;
cursor: not-allowed;
}
.wpuf-gateway-card__checkbox {
.wpuf-gateway-card__checkbox,
.wpuf-method-card__checkbox {
position: absolute;
opacity: 0;
width: 0;
height: 0;
pointer-events: none;
}
.wpuf-gateway-card__toggle {
.wpuf-gateway-card__toggle,
.wpuf-method-card__toggle {
position: absolute;
top: 4px;
right: 4px;
Expand All @@ -1555,39 +1564,48 @@ body.wpuf-modal-open {
padding: 4px;
z-index: 2;
}
.wpuf-gateway-card__toggle:hover {
.wpuf-gateway-card__toggle:hover,
.wpuf-method-card__toggle:hover {
opacity: 0.8;
}
.wpuf-gateway-card__check-on {
.wpuf-gateway-card__check-on,
.wpuf-method-card__check-on {
display: none;
}
.wpuf-gateway-card__check-off {
.wpuf-gateway-card__check-off,
.wpuf-method-card__check-off {
display: block;
}
.wpuf-gateway-card--active .wpuf-gateway-card__check-on {
.wpuf-gateway-card--active .wpuf-gateway-card__check-on,
.wpuf-method-card--active .wpuf-method-card__check-on {
display: block;
}
.wpuf-gateway-card--active .wpuf-gateway-card__check-off {
.wpuf-gateway-card--active .wpuf-gateway-card__check-off,
.wpuf-method-card--active .wpuf-method-card__check-off {
display: none;
}
.wpuf-gateway-card__icon {
.wpuf-gateway-card__icon,
.wpuf-method-card__icon {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 48px;
margin-bottom: 8px;
}
.wpuf-gateway-card__icon img {
.wpuf-gateway-card__icon img,
.wpuf-method-card__icon img {
max-width: 100px;
max-height: 48px;
object-fit: contain;
}
.wpuf-gateway-card__icon svg {
.wpuf-gateway-card__icon svg,
.wpuf-method-card__icon svg {
max-width: 48px;
max-height: 48px;
}
.wpuf-gateway-card__name {
.wpuf-gateway-card__name,
.wpuf-method-card__name {
font-size: 13px;
font-weight: 500;
color: #1d2327;
Expand Down
Loading
Loading