<?php
// phpcs:ignoreFile WordPress.WP.I18n.MissingTranslatorsComment
/**
 * Plugin Name: LS Stock Portfolio
 * Plugin URI: https://lakestylez.com/ls-stock-portfolio/
 * Description: Display your Adobe Stock, Unsplash or Pixabay portfolio via shortcode with masonry grid and integrated lightbox.
 * Version: 1.1.0
 * Author: Lake Stylez – Mediendesign
 * Author URI: https://lakestylez.com
 * License: GPL-2.0-or-later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: ls-stock-portfolio
 * Requires at least: 6.2
 * Tested up to: 6.9
 */


if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Freemius SDK bootstrap.
 *
 * This allows selling / licensing LS Stock Portfolio via Freemius in addition
 * to the existing Lemon Squeezy based licensing. If the Freemius SDK is not
 * present or not yet configured, the plugin will continue to work as before.
 *
 * Replace the placeholder values (YOUR_FREEMIUS_ID, YOUR_PUBLIC_KEY, etc.)
 * with the values from your Freemius dashboard.
 */


if ( ! function_exists( 'lsmsp_fs' ) ) {
    function lsmsp_fs() {
        global $lsmsp_fs;

        if ( isset( $lsmsp_fs ) ) {
            return $lsmsp_fs;
        }

        $sdk_path = dirname( __FILE__ ) . '/freemius/start.php';

        if ( file_exists( $sdk_path ) ) {
            // Load the Freemius SDK.
            require_once $sdk_path;

            $lsmsp_fs = fs_dynamic_init(
                array(
                    'id'         => '22269',
                    'slug'       => 'ls-stock-portfolio',
                    'account' => true,   // 🔥 Account-Seite aktivieren
                    'type'       => 'plugin',
                    'public_key' => 'pk_1f9a1620b86b74ae930d2068590bf',
                    // The plugin itself is free with paid plans (Pro) handled by Freemius.
                    /*'is_premium'    => false,*/
                    'has_premium_version' => false,
                    'has_addons'    => false,
                    'has_paid_plans'=> true,
                    'menu'          => array(
                        // Re-use the existing top-level admin menu slug.
                        'slug' => 'ls-stock-portfolio',
                    ),
                )
            );
        } else {
            // SDK not present or not yet installed.
            $lsmsp_fs = false;
        }

        return $lsmsp_fs;
    }

    // Initialize Freemius (if available) early.
    lsmsp_fs();

    // Let other code hook into the SDK initialization if needed.
    do_action( 'lsmsp_fs_loaded' );
}



/**
 * Standardwerte
 */
function lsmsp_defaults() {
    return array(
        'lang'           => 'de',
        'platform'       => 'adobe', // adobe, unsplash, pixabay
        'portfolio_url'  => '',
        'pixabay_api_key' => '',
        'pixabay_username'=> '',
        'unsplash_access_key' => '',
        'unsplash_username'   => '',
        'initial_count'  => 8,
        'backlink_color' => '#cccccc',
        'order'          => 'original',
        'gap'            => '12px',
        'cols'           => 4,
        'cache_hours'    => 6,
        'layout'         => 'grid', // grid | masonry
        'ratio'          => 'auto', // auto | 1:1 | 3:2 | 4:3 | 16:9 (nur Grid)
        'slideshow_interval' => 4, // Slideshow delay in seconds (Pro feature)
                 'button_bg'           => '#ffffff',
                 'button_text_color'   => '#000000',
                 'button_border_color' => '#cccccc',
                 'button_border_radius'=> 3,
                 'lightbox_theme'      => 'default', // default|carousel|filmstrip|fullscreen
                 'lightbox_animation'  => 'default', // default|fade|slide
                 'lightbox_animation_duration' => 600, // in milliseconds, used for fade/slide animations
    );
}

/**
 * Lizenzstatus holen.
 *
 * @return array
 */
function lsmsp_get_license_status() {
    $status = get_option( 'ls_sp_license_status', array() );

    if ( ! is_array( $status ) ) {
        $status = array();
    }

    return $status;
}

/**
 * Prüft, ob Pro aktiv ist.
 *
 * @return bool
 */
function lsmsp_is_pro_active() {
    // First, check if Freemius is loaded and reports that premium code can be used.
    if ( function_exists( 'lsmsp_fs' ) ) {
        $fs = lsmsp_fs();
        if ( $fs && method_exists( $fs, 'can_use_premium_code' ) && $fs->can_use_premium_code() ) {
            return true;
        }
    }

    // Fallback to the existing Lemon Squeezy based license status.
    $status = lsmsp_get_license_status();

    if ( empty( $status['valid'] ) || ! empty( $status['error'] ) ) {
        return false;
    }

    $license_status = isset( $status['license_status'] ) ? $status['license_status'] : '';

    // Abgelaufen / deaktiviert = nicht gültig.
    if ( in_array( $license_status, array( 'expired', 'disabled' ), true ) ) {
        return false;
    }

    // Optional Ablaufdatum prüfen.
    if ( ! empty( $status['expires_at'] ) ) {
        $expires_ts = strtotime( $status['expires_at'] );
        if ( $expires_ts && $expires_ts < time() ) {
            return false;
        }
    }

    return true;
}

/**
 * Checks if Pro is active via Freemius specifically.
 *
 * This is used to hide the Lemon Squeezy license key field when
 * the site is already connected to a Freemius Pro plan.
 *
 * @return bool
 */

function lsmsp_is_freemius_pro_active() {
    if ( ! function_exists( 'lsmsp_fs' ) ) {
        return false;
    }

    $fs = lsmsp_fs();
    if ( ! $fs ) {
        return false;
    }

    // Preferred check: Freemius says premium code can be used.
    if ( method_exists( $fs, 'can_use_premium_code' ) && $fs->can_use_premium_code() ) {
        return true;
    }

    // Fallback: registered + paying plan.
    if (
        method_exists( $fs, 'is_registered' ) &&
        method_exists( $fs, 'is_paying' ) &&
        $fs->is_registered() &&
        $fs->is_paying()
    ) {
        return true;
    }

    return false;
}

/**
 * Checks if Pro is active via the Lemon Squeezy license key.
 *
 * This is used to hide the Freemius "Upgrade" menu entry when
 * the LS license key has activated the Pro features.
 *
 * @return bool
 */
function lsmsp_is_ls_license_key_active() {
    // If Freemius itself reports premium access, we treat that as
    // a Freemius-based activation, not an LS license activation.
    if ( function_exists( 'lsmsp_is_freemius_pro_active' ) && lsmsp_is_freemius_pro_active() ) {
        return false;
    }

    $status = lsmsp_get_license_status();

    if ( empty( $status ) || ! is_array( $status ) ) {
        return false;
    }

    if ( empty( $status['valid'] ) || ! empty( $status['error'] ) ) {
        return false;
    }

    if ( ! empty( $status['license_status'] ) && in_array( $status['license_status'], array( 'expired', 'disabled' ), true ) ) {
        return false;
    }

    if ( ! empty( $status['expires_at'] ) ) {
        $expires_ts = strtotime( $status['expires_at'] );
        if ( $expires_ts && $expires_ts < time() ) {
            return false;
        }
    }

    return true;
}


/**
 * Builds a human-readable instance name for license activation.
 *
 * @return string
 */
function lsmsp_get_license_instance_name() {
    $site_url  = home_url();
    $blog_name = get_bloginfo( 'name', 'display' );

    if ( $blog_name ) {
        return $blog_name . ' – ' . $site_url;
    }

    return $site_url;
}

/**
 * Returns the Lemon Squeezy variant IDs for LS Stock Portfolio Pro.
 *
 * These correspond to:
 * - monthly payment
 * - annual payment
 * - lifetime licence
 *
 * @return array
 */
function lsmsp_get_license_variant_ids() {
    return array(
        'monthly'  => 1135915, // monthly payment
        'annual'   => 1136059, // annual payment
        'lifetime' => 1136061, // lifetime licence
    );
}

/**
 * Try to deactivate a previously activated license key instance.
 *
 * @param string $license_key License key.
 * @param string $instance_id Instance ID returned by the activate endpoint.
 */
function lsmsp_deactivate_license_instance( $license_key, $instance_id ) {
    $license_key = trim( (string) $license_key );
    $instance_id = trim( (string) $instance_id );

    if ( '' === $license_key || '' === $instance_id ) {
        return;
    }

    $response = wp_remote_post(
        'https://api.lemonsqueezy.com/v1/licenses/deactivate',
        array(
            'timeout' => 10,
            'headers' => array(
                'Accept' => 'application/json',
            ),
            'body'    => array(
                'license_key' => $license_key,
                'instance_id' => $instance_id,
            ),
        )
    );

    // We intentionally ignore errors here – a failed deactivation
    // in Lemon Squeezy should not break the WP admin area.
    if ( is_wp_error( $response ) ) {
        return;
    }
}

/**
 * Lemon Squeezy Lizenzkey validieren und Ergebnis speichern.
 *
 * @param string $license_key Roh-Lizenzkey.
 *
 * @return array Status-Array.
 */
function lsmsp_validate_and_store_license_key( $license_key ) {
    $license_key = trim( (string) $license_key );

    // Previous key + status for handling deactivation.
    $previous_key    = get_option( 'ls_sp_license_key', '' );
    $previous_status = lsmsp_get_license_status();

    // Wenn das Feld geleert wurde: ggf. alte Instanz deaktivieren und Status zurücksetzen.
    if ( '' === $license_key ) {
        if ( ! empty( $previous_key ) && ! empty( $previous_status['instance_id'] ) ) {
            lsmsp_deactivate_license_instance( $previous_key, $previous_status['instance_id'] );
        }

        delete_option( 'ls_sp_license_key' );
        delete_option( 'ls_sp_license_status' );

        $status = array(
            'valid'          => false,
            'error'          => '',
            'reason'         => 'empty',
            'instance_id'    => '',
            'license_key'    => '',
            'license_status' => '',
            'expires_at'     => '',
        );

        update_option( 'ls_sp_license_status', $status );

        return $status;
    }

    // Wenn ein anderer Key eingetragen wird, versuchen wir, die alte Instanz zu deaktivieren.
    if ( ! empty( $previous_key ) && $previous_key !== $license_key && ! empty( $previous_status['instance_id'] ) ) {
        lsmsp_deactivate_license_instance( $previous_key, $previous_status['instance_id'] );
    }

    // Roh-Key speichern.
    update_option( 'ls_sp_license_key', $license_key );

    $status = array(
        'valid'          => false,
        'error'          => '',
        'reason'         => '',
        'checked_at'     => time(),
        'license_key'    => substr( $license_key, 0, 16 ) . ( strlen( $license_key ) > 16 ? '…' : '' ),
        'license_status' => '',
        'expires_at'     => '',
        'instance_id'    => '',
    );

    // 1) Lizenzschlüssel validieren.
    $response = wp_remote_post(
        'https://api.lemonsqueezy.com/v1/licenses/validate',
        array(
            'timeout' => 10,
            'headers' => array(
                'Accept' => 'application/json',
            ),
            'body'    => array(
                'license_key' => $license_key,
            ),
        )
    );

    if ( is_wp_error( $response ) ) {
        $status['error']  = $response->get_error_message();
        $status['reason'] = 'request_error';
        update_option( 'ls_sp_license_status', $status );
        return $status;
    }

    $code = wp_remote_retrieve_response_code( $response );
    $body = wp_remote_retrieve_body( $response );

    if ( $code < 200 || $code >= 300 || ! $body ) {
        $status['error']  = __( 'Unexpected response from license server.', 'ls-stock-portfolio' );
        $status['reason'] = 'http_error';
        update_option( 'ls_sp_license_status', $status );
        return $status;
    }

    $data = json_decode( $body, true );

    if ( ! is_array( $data ) ) {
        $status['error']  = __( 'Could not parse response from license server.', 'ls-stock-portfolio' );
        $status['reason'] = 'parse_error';
        update_option( 'ls_sp_license_status', $status );
        return $status;
    }

    $status['license_status'] = isset( $data['license_key']['status'] ) ? (string) $data['license_key']['status'] : '';
    $status['expires_at']     = isset( $data['license_key']['expires_at'] ) ? (string) $data['license_key']['expires_at'] : '';

    $valid = ! empty( $data['valid'] ) && empty( $data['error'] );

    if ( ! $valid ) {
        $status['error']  = ! empty( $data['error'] ) ? (string) $data['error'] : __( 'License key is not valid.', 'ls-stock-portfolio' );
        $status['reason'] = 'invalid';
        update_option( 'ls_sp_license_status', $status );
        return $status;
    }

    // Stricter check: ensure the license belongs to one of our allowed variant IDs.
    $allowed_variants = lsmsp_get_license_variant_ids();
    $allowed_ids      = array();

    if ( is_array( $allowed_variants ) ) {
        foreach ( $allowed_variants as $variant_value ) {
            $allowed_ids[] = (int) $variant_value;
        }
    }
    $allowed_ids = array_filter( array_unique( $allowed_ids ) );

    // Lemon Squeezy returns product and variant information in the "meta" object.
    $meta_variant_id = isset( $data['meta']['variant_id'] ) ? (int) $data['meta']['variant_id'] : 0;

    // Only enforce the variant check if we have at least one allowed ID configured
    // and the API returned a variant_id in the meta data. This avoids breaking installs
    // if the API response format changes unexpectedly.
    if ( $allowed_ids && $meta_variant_id ) {
        if ( ! in_array( $meta_variant_id, $allowed_ids, true ) ) {
            $status['error']  = __( 'This license key is not valid for LS Stock Portfolio Pro.', 'ls-stock-portfolio' );
            $status['reason'] = 'invalid_variant';
            update_option( 'ls_sp_license_status', $status );
            return $status;
        }
    }

    if ( in_array( $status['license_status'], array( 'expired', 'disabled' ), true ) ) {
        if ( 'expired' === $status['license_status'] ) {
            $status['error']  = __( 'Your license key has expired.', 'ls-stock-portfolio' );
            $status['reason'] = 'expired';
        } else {
            $status['error']  = __( 'Your license key has been disabled.', 'ls-stock-portfolio' );
            $status['reason'] = 'disabled';
        }
        update_option( 'ls_sp_license_status', $status );
        return $status;
    }

    if ( $status['expires_at'] ) {
        $expires_ts = strtotime( $status['expires_at'] );
        if ( $expires_ts && $expires_ts < time() ) {
            $status['error']  = __( 'Your license key has expired.', 'ls-stock-portfolio' );
            $status['reason'] = 'expired';
            update_option( 'ls_sp_license_status', $status );
            return $status;
        }
    }

    // 2) Wenn der Key gültig ist, Aktivierungs-Call ausführen.
    $instance_name = lsmsp_get_license_instance_name();

    $activate_response = wp_remote_post(
        'https://api.lemonsqueezy.com/v1/licenses/activate',
        array(
            'timeout' => 10,
            'headers' => array(
                'Accept' => 'application/json',
            ),
            'body'    => array(
                'license_key'   => $license_key,
                'instance_name' => $instance_name,
            ),
        )
    );

    if ( is_wp_error( $activate_response ) ) {
        $status['error']  = $activate_response->get_error_message();
        $status['reason'] = 'activation_request_error';
        update_option( 'ls_sp_license_status', $status );
        return $status;
    }

    $activate_code = wp_remote_retrieve_response_code( $activate_response );
    $activate_body = wp_remote_retrieve_body( $activate_response );

    if ( $activate_code < 200 || $activate_code >= 300 || ! $activate_body ) {
        $status['error']  = __( 'Unexpected response from license server during activation.', 'ls-stock-portfolio' );
        $status['reason'] = 'activation_http_error';
        update_option( 'ls_sp_license_status', $status );
        return $status;
    }

    $activate_data = json_decode( $activate_body, true );

    if ( ! is_array( $activate_data ) ) {
        $status['error']  = __( 'Could not parse activation response from license server.', 'ls-stock-portfolio' );
        $status['reason'] = 'activation_parse_error';
        update_option( 'ls_sp_license_status', $status );
        return $status;
    }

    if ( empty( $activate_data['activated'] ) || ! empty( $activate_data['error'] ) ) {
        $status['error']  = ! empty( $activate_data['error'] ) ? (string) $activate_data['error'] : __( 'License key could not be activated.', 'ls-stock-portfolio' );
        $status['reason'] = 'activation_failed';
        update_option( 'ls_sp_license_status', $status );
        return $status;
    }

    if ( isset( $activate_data['instance']['id'] ) ) {
        $status['instance_id'] = (string) $activate_data['instance']['id'];
    }

    if ( isset( $activate_data['license_key']['status'] ) ) {
        $status['license_status'] = (string) $activate_data['license_key']['status'];
    }

    // Wenn wir bis hierher gekommen sind, ist alles OK.
    $status['valid']  = true;
    $status['reason'] = 'ok';

    update_option( 'ls_sp_license_status', $status );

    return $status;
}


/**
 * Admin-Menü
 */
add_action(
    'admin_menu',
    function () {
        add_menu_page(
            'LS Stock Portfolio',
            'Stock Portfolio',
            'manage_options',
            'ls-stock-portfolio',
            'lsmsp_admin_page',
            'dashicons-format-gallery',
            56
        );
    }
);

/**
 * Hide Freemius "Upgrade" submenu when Pro is active.
 *
 * Wenn Pro über den LS-Lizenzschlüssel oder über Freemius selbst aktiv ist,
 * blenden wir den "Upgrade"-Menüpunkt aus, damit es keinen verwirrenden
 * zweiten Upgrade-Pfad gibt.
 */
function lsmsp_maybe_hide_freemius_upgrade_submenu() {
    if ( ! is_admin() ) {
        return;
    }

    // Wenn im Rahmen des Settings-Posts der LS-Lizenzschlüssel geleert wird,
    // soll in *diesem* Request das Upgrade-Menü sichtbar bleiben, auch wenn
    // die bisher gespeicherten Optionen noch einen gültigen Key enthalten.
    if ( isset( $_POST['ls_sp_save'], $_POST['ls_sp_license_key'] ) ) {
        $posted_key = sanitize_text_field( wp_unslash( $_POST['ls_sp_license_key'] ) );

        // Nur eingreifen, wenn der gepostete Key wirklich leer ist und kein Freemius-Pro aktiv ist.
        if ( '' === $posted_key ) {
            $fs_pro = false;
            if ( function_exists( 'lsmsp_is_freemius_pro_active' ) ) {
                $fs_pro = lsmsp_is_freemius_pro_active();
            }

            if ( ! $fs_pro ) {
                // LS-Key wird entfernt und es gibt kein Freemius-Pro:
                // Upgrade-Link für diesen Request NICHT ausblenden.
                return;
            }
        }
    }

    // --- Prüfen, ob Pro aktiv ist (LS-Lizenz oder Freemius-Pro) ---

    $is_ls_pro = false;

    // Bevorzugt über unsere zentrale Helper-Funktion prüfen.
    if ( function_exists( 'lsmsp_is_pro_active' ) ) {
        $is_ls_pro = lsmsp_is_pro_active();
    } else {
        // Fallback: direkt aus dem gespeicherten Lizenz-Status lesen.
        $status = get_option( 'ls_sp_license_status', array() );
        if ( ! empty( $status['valid'] ) && empty( $status['error'] ) ) {
            $is_ls_pro = true;
        }
    }

    // Prüfen, ob eine gültige LS-Lizenz *und* ein gespeicherter Lizenzschlüssel vorhanden sind.
    $is_ls_pro = false;
    $license_key = get_option( 'ls_sp_license_key', '' );
    $status      = get_option( 'ls_sp_license_status', array() );

    if (
        '' !== $license_key // nur wenn überhaupt ein Key gespeichert ist
        && ! empty( $status['valid'] )
        && empty( $status['error'] )
    ) {
        $is_ls_pro = true;
    }

    // Optional: Freemius-Pro ebenfalls als "Pro" werten.
    $is_fs_pro = false;
    if ( function_exists( 'lsmsp_is_freemius_pro_active' ) ) {
        $is_fs_pro = lsmsp_is_freemius_pro_active();
    }

    // Nur wenn irgendeine Pro-Variante aktiv ist, wird das Upgrade-Menü versteckt.
    if ( ! $is_ls_pro && ! $is_fs_pro ) {
        return;
    }

    $parent_slug = 'ls-stock-portfolio';

    // 1) Bekannte Freemius-Slugs direkt entfernen.
    $possible_upgrade_slugs = array(
        'ls-stock-portfolio-pricing',
        'ls-stock-portfolio_pricing',
    );

    foreach ( $possible_upgrade_slugs as $slug ) {
        remove_submenu_page( $parent_slug, $slug );
    }

    // 2) Zur Sicherheit das globale $submenu-Array nach "Upgrade" durchsuchen.
    global $submenu;

    if ( empty( $submenu ) || empty( $submenu[ $parent_slug ] ) || ! is_array( $submenu[ $parent_slug ] ) ) {
        return;
    }

    foreach ( $submenu[ $parent_slug ] as $index => $item ) {
        // $item[0] = Menü-Titel, $item[2] = Slug.
        $title = isset( $item[0] ) ? wp_strip_all_tags( $item[0] ) : '';
        if ( $title && false !== stripos( $title, 'upgrade' ) ) {
            unset( $submenu[ $parent_slug ][ $index ] );
        }
    }
}

// Sehr spät ausführen, damit Freemius seine Menüs bereits registriert hat.

add_action( 'admin_menu', 'lsmsp_maybe_hide_freemius_upgrade_submenu', 999999 );

/**
 * Fallback: Hide Freemius "Upgrade" submenu via CSS when Pro is active.
 *
 * In some environments Freemius may register its menu very late and
 * `remove_submenu_page()` does not always catch it reliably. As a
 * safety net we also hide the entry via CSS if any Pro mode is active.
 */
function lsmsp_admin_hide_upgrade_css() {
    if ( ! is_admin() ) {
        return;
    }

    // Wenn im Rahmen des Settings-Posts der LS-Lizenzschlüssel geleert wird,
    // soll in *diesem* Request der Upgrade-Link sichtbar bleiben, auch wenn
    // die bisher gespeicherten Optionen noch einen gültigen Key enthalten.
    if ( isset( $_POST['ls_sp_save'], $_POST['ls_sp_license_key'] ) ) {
        $posted_key = sanitize_text_field( wp_unslash( $_POST['ls_sp_license_key'] ) );

        // Nur eingreifen, wenn der gepostete Key wirklich leer ist und kein Freemius-Pro aktiv ist.
        if ( '' === $posted_key ) {
            $fs_pro = false;
            if ( function_exists( 'lsmsp_is_freemius_pro_active' ) ) {
                $fs_pro = lsmsp_is_freemius_pro_active();
            }

            if ( ! $fs_pro ) {
                // LS-Key wird entfernt und es gibt kein Freemius-Pro:
                // Upgrade-Link für diesen Request NICHT via CSS ausblenden.
                return;
            }
        }
    }

    // Prüfen ob Pro aktiv ist (LS-Lizenz mit Key oder Freemius-Pro).
    $license_key = get_option( 'ls_sp_license_key', '' );
    $status      = get_option( 'ls_sp_license_status', array() );

    $is_ls_pro = (
        '' !== $license_key
        && ! empty( $status['valid'] )
        && empty( $status['error'] )
    );

    $is_fs_pro = function_exists( 'lsmsp_is_freemius_pro_active' ) && lsmsp_is_freemius_pro_active();

    if ( ! $is_ls_pro && ! $is_fs_pro ) {
        // In der Free-Version soll der Upgrade-Link sichtbar bleiben.
        return;
    }
    ?>
    <style type="text/css">
        /* Hide Freemius "Upgrade" submenu under the LS Stock Portfolio menu when Pro is active */
        #toplevel_page_ls-stock-portfolio ul.wp-submenu a[href*="ls-stock-portfolio-pricing"],
        #toplevel_page_ls-stock-portfolio ul.wp-submenu a[href*="ls-stock-portfolio_pricing"],
        #toplevel_page_ls-stock-portfolio ul.wp-submenu a[href*="page=ls-stock-portfolio-pricing"],
        #toplevel_page_ls-stock-portfolio ul.wp-submenu a[href*="page=ls-stock-portfolio_pricing"] {
            display: none !important;
        }
    </style>
    <?php
}
add_action( 'admin_head', 'lsmsp_admin_hide_upgrade_css', 20 );

/**
 * Admin-Seite
 */
function lsmsp_admin_page() {
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }

    $defaults = lsmsp_defaults();
    $opts     = get_option( 'ls_sp_settings', array() );
    $opts     = wp_parse_args( $opts, $defaults );
    $license_status = lsmsp_get_license_status();

    // speichern
    if ( isset( $_POST['ls_sp_save'] ) && check_admin_referer( 'ls_sp_save_settings' ) ) {
        $old_url      = $opts['portfolio_url'] ?? '';
        $old_order    = $opts['order'] ?? 'original';
        $old_platform = $opts['platform'] ?? 'adobe';

        $opts['lang']           = isset( $_POST['ls_sp_lang'] )
            ? sanitize_text_field( wp_unslash( $_POST['ls_sp_lang'] ) )
            : 'de';

        $opts['platform']       = isset( $_POST['ls_sp_platform'] )
            ? sanitize_text_field( wp_unslash( $_POST['ls_sp_platform'] ) )
            : 'adobe';

        $opts['pixabay_api_key'] = isset( $_POST['ls_sp_pixabay_api_key'] )
            ? sanitize_text_field( wp_unslash( $_POST['ls_sp_pixabay_api_key'] ) )
            : '';
        $opts['pixabay_username'] = isset( $_POST['ls_sp_pixabay_username'] )
            ? sanitize_text_field( wp_unslash( $_POST['ls_sp_pixabay_username'] ) )
            : '';

        $opts['unsplash_access_key'] = isset( $_POST['ls_sp_unsplash_access_key'] )
            ? sanitize_text_field( wp_unslash( $_POST['ls_sp_unsplash_access_key'] ) )
            : '';
        $opts['unsplash_username'] = isset( $_POST['ls_sp_unsplash_username'] )
            ? sanitize_text_field( wp_unslash( $_POST['ls_sp_unsplash_username'] ) )
            : '';

        $opts['portfolio_url']  = isset( $_POST['ls_sp_portfolio_url'] )
            ? esc_url_raw( wp_unslash( $_POST['ls_sp_portfolio_url'] ) )
            : '';

        $opts['initial_count']  = isset( $_POST['ls_sp_initial_count'] )
            ? max( 1, intval( wp_unslash( $_POST['ls_sp_initial_count'] ) ) )
            : 8;

        $opts['backlink_color'] = isset( $_POST['ls_sp_backlink_color'] )
            ? sanitize_text_field( wp_unslash( $_POST['ls_sp_backlink_color'] ) )
            : '#cccccc';

        $opts['order']          = isset( $_POST['ls_sp_order'] )
            ? sanitize_text_field( wp_unslash( $_POST['ls_sp_order'] ) )
            : 'original';

        $opts['layout']         = isset( $_POST['ls_sp_layout'] )
            ? sanitize_text_field( wp_unslash( $_POST['ls_sp_layout'] ) )
            : 'grid';

        $opts['ratio']          = isset( $_POST['ls_sp_ratio'] )
            ? sanitize_text_field( wp_unslash( $_POST['ls_sp_ratio'] ) )
            : 'auto';

        $opts['gap']            = isset( $_POST['ls_sp_gap'] )
            ? sanitize_text_field( wp_unslash( $_POST['ls_sp_gap'] ) )
            : '12px';

        $opts['cols']           = isset( $_POST['ls_sp_cols'] )
            ? max( 1, intval( wp_unslash( $_POST['ls_sp_cols'] ) ) )
            : 4;

        $opts['cache_hours']    = isset( $_POST['ls_sp_cache_hours'] )
            ? max( 1, intval( wp_unslash( $_POST['ls_sp_cache_hours'] ) ) )
            : 6;
        
        // Slideshow interval (seconds) – only changeable in Pro, free version stays at 4 seconds.
        if ( isset( $_POST['ls_sp_slideshow_interval'] ) ) {
            $interval = intval( wp_unslash( $_POST['ls_sp_slideshow_interval'] ) );
            if ( $interval < 1 ) {
                $interval = 4;
            }
            if ( lsmsp_is_pro_active() ) {
                $opts['slideshow_interval'] = $interval;
            }
        }

        // Load more button styling (Pro only).
        if ( lsmsp_is_pro_active() ) {
            if ( isset( $_POST['ls_sp_button_bg'] ) ) {
                $opts['button_bg'] = sanitize_text_field( wp_unslash( $_POST['ls_sp_button_bg'] ) );
            }
            if ( isset( $_POST['ls_sp_button_text_color'] ) ) {
                $opts['button_text_color'] = sanitize_text_field( wp_unslash( $_POST['ls_sp_button_text_color'] ) );
            }
            if ( isset( $_POST['ls_sp_button_border_color'] ) ) {
                $opts['button_border_color'] = sanitize_text_field( wp_unslash( $_POST['ls_sp_button_border_color'] ) );
            }
            if ( isset( $_POST['ls_sp_button_border_radius'] ) ) {
                $opts['button_border_radius'] = max( 0, intval( wp_unslash( $_POST['ls_sp_button_border_radius'] ) ) );
            }
        }
        
        // Lightbox theme and animation (Pro only).
        if ( lsmsp_is_pro_active() ) {
            if ( isset( $_POST['ls_sp_lightbox_theme'] ) ) {
                $theme = sanitize_text_field( wp_unslash( $_POST['ls_sp_lightbox_theme'] ) );
                $allowed_themes = array( 'default', 'carousel', 'filmstrip', 'fullscreen' );
                if ( in_array( $theme, $allowed_themes, true ) ) {
                    $opts['lightbox_theme'] = $theme;
                }
            }

            if ( isset( $_POST['ls_sp_lightbox_animation'] ) ) {
                $anim = sanitize_text_field( wp_unslash( $_POST['ls_sp_lightbox_animation'] ) );
                $allowed_anims = array( 'default', 'fade', 'slide' );
                if ( in_array( $anim, $allowed_anims, true ) ) {
                    $opts['lightbox_animation'] = $anim;
                }
            }
        }
        
        if ( isset( $_POST['ls_sp_lightbox_animation_duration'] ) ) {
            $duration = intval( wp_unslash( $_POST['ls_sp_lightbox_animation_duration'] ) );
            if ( $duration < 100 ) {
                $duration = 100;
            } elseif ( $duration > 5000 ) {
                $duration = 5000;
            }
            $opts['lightbox_animation_duration'] = $duration;
        }

        $posted_license_key = isset( $_POST['ls_sp_license_key'] )
            ? sanitize_text_field( wp_unslash( $_POST['ls_sp_license_key'] ) )
            : '';

        $current_license_key = get_option( 'ls_sp_license_key', '' );

        if ( $posted_license_key !== $current_license_key ) {
            $license_status = lsmsp_validate_and_store_license_key( $posted_license_key );
        } else {
            $license_status = lsmsp_get_license_status();
        }

        update_option( 'ls_sp_settings', $opts );
        
        if ( isset( $license_status['reason'] ) && 'empty' === $license_status['reason'] ) {
            echo '<div class="notice notice-info is-dismissible" style="border-left-color:#cc7a00;"><p style="color:#cc7a00;font-weight:600;">' .
                 esc_html__( 'License key removed. The plugin is running in the free version.', 'ls-stock-portfolio' ) .
                 '</p></div>';
        } elseif ( ! empty( $license_status['valid'] ) && empty( $license_status['error'] ) ) {
            echo '<div class="notice notice-success is-dismissible" style="border-left-color:#1a7f37;"><p style="color:#1a7f37;font-weight:600;">' .
                 esc_html__( 'Pro license successfully activated. The frontend backlink will be hidden.', 'ls-stock-portfolio' ) .
                 '</p></div>';
        } elseif ( ! empty( $license_status['error'] ) ) {
            echo '<div class="notice notice-error is-dismissible" style="border-left-color:#cc0000;"><p style="color:#cc0000;font-weight:600;">' .
                 esc_html( sprintf( __( 'License error: %s', 'ls-stock-portfolio' ), $license_status['error'] ) ) .
                 '</p></div>';
        }

        // Cache für alle Plattformen (Adobe, Unsplash, Pixabay) leeren,
        // basierend auf den aktuell gesetzten Quellen.
        $platforms = array( 'adobe', 'unsplash', 'pixabay' );

        foreach ( $platforms as $pf ) {
            switch ( $pf ) {
                case 'pixabay':
                    $source = ! empty( $opts['pixabay_username'] ) ? $opts['pixabay_username'] : '';
                    break;

                case 'unsplash':
                    $source = ! empty( $opts['unsplash_username'] ) ? $opts['unsplash_username'] : '';
                    break;

                case 'adobe':
                default:
                    $source = ! empty( $opts['portfolio_url'] ) ? $opts['portfolio_url'] : '';
                    break;
            }

            if ( $source ) {
                delete_transient( 'ls_sp_cache_' . md5( $pf . '|' . $source . '|original' ) );
                delete_transient( 'ls_sp_cache_' . md5( $pf . '|' . $source . '|random' ) );
            }
        }

        echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Settings saved.', 'ls-stock-portfolio' ) . '</p></div>';
    }

    ?>
    <div class="wrap">
        <h1>LS Stock Portfolio – Settings</h1>
        <style>
            .ls-sp-shortcodes { margin-top: 24px; }
            .ls-sp-shortcodes h2 { margin-bottom: 10px; }
            .ls-sp-shortcodes-table code {
                display: inline-block;
                padding: 2px 6px;
                background: #f6f7f7;
                border: 1px solid #dcdcde;
                border-radius: 3px;
                font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
                font-size: 12px;
            }
            .ls-sp-shortcodes-table th {
                width: 230px;
                vertical-align: top;
                padding-top: 10px;
            }
            .ls-sp-shortcodes-table td p {
                margin: 0 0 4px;
            }
            .ls-sp-shortcodes .description {
                margin-top: 8px;
                color: #646970;
            }
            .ls-sp-shortcodes-table code[data-ls-sp-copy] {
                cursor: pointer;
                transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
            }
            .ls-sp-shortcodes-table code.ls-sp-copied {
                background: #d1f2d3;
                border-color: #46b450;
                color: #1d3a1d;
            }
        </style>

        <div class="ls-sp-header-row" style="display:flex;align-items:center;justify-content:space-between;gap:24px;flex-wrap:wrap;margin:12px 0 8px;">
            <div class="ls-sp-tabs-wrapper" style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
                <span style="font-weight:600;"><?php esc_html_e( 'Platform profiles:', 'ls-stock-portfolio' ); ?></span>
                <button type="button" class="button ls-sp-tab ls-sp-tab-adobe" data-platform="adobe">
                    Adobe Stock
                </button>
                <button type="button" class="button ls-sp-tab ls-sp-tab-unsplash" data-platform="unsplash">
                    Unsplash
                </button>
                <button type="button" class="button ls-sp-tab ls-sp-tab-pixabay" data-platform="pixabay">
                    Pixabay
                </button>
            </div>

            <a href="<?php echo esc_url( 'https://lakestylez.com' ); ?>" target="_blank" rel="noopener noreferrer"
               style="display:inline-flex;align-items:center;justify-content:center;text-decoration:none;">
                <img src="<?php echo esc_url( plugins_url( 'assets/img/ls-sticker-logo.png', __FILE__ ) ); ?>"
                     alt="Lake Stylez – Mediendesign"
                     style="max-width:96px;height:auto;display:block;border-radius:50%;box-shadow:0 0 8px rgba(0,0,0,0.08);">
            </a>
        </div>

        <p class="description" style="max-width:720px;margin:0 0 16px 2px;">
            <?php esc_html_e( 'Select the platform you want to configure above. The display options below apply to all shortcodes.', 'ls-stock-portfolio' ); ?>
        </p>

        <form method="post">
            <?php wp_nonce_field( 'ls_sp_save_settings' ); ?>
            <input type="hidden" name="ls_sp_platform" id="ls_sp_platform" value="<?php echo esc_attr( $opts['platform'] ); ?>">

            <table class="form-table">
                <tr class="ls-sp-platform-row" data-platform="unsplash">
                    <th><label for="ls_sp_unsplash_access_key">Unsplash Access Key</label></th>
                    <td>
                        <input type="text" class="regular-text" id="ls_sp_unsplash_access_key" name="ls_sp_unsplash_access_key"
                               value="<?php echo esc_attr( $opts['unsplash_access_key'] ); ?>"
                               placeholder="Required for Unsplash">
                    </td>
                </tr>
                <tr class="ls-sp-platform-row" data-platform="unsplash">
                    <th><label for="ls_sp_unsplash_username">Unsplash username</label></th>
                    <td>
                        <input type="text" class="regular-text" id="ls_sp_unsplash_username" name="ls_sp_unsplash_username"
                               value="<?php echo esc_attr( $opts['unsplash_username'] ); ?>"
                               placeholder="Your Unsplash username">
                    </td>
                </tr>
                <tr class="ls-sp-platform-row" data-platform="pixabay">
                    <th><label for="ls_sp_pixabay_api_key">Pixabay API Key</label></th>
                    <td>
                        <input type="text" class="regular-text" id="ls_sp_pixabay_api_key" name="ls_sp_pixabay_api_key"
                               value="<?php echo esc_attr( $opts['pixabay_api_key'] ); ?>"
                               placeholder="Only required for Pixabay">
                    </td>
                </tr>
                <tr class="ls-sp-platform-row" data-platform="pixabay">
                    <th><label for="ls_sp_pixabay_username">Pixabay tags</label></th>
                    <td>
                        <input type="text" class="regular-text" id="ls_sp_pixabay_username" name="ls_sp_pixabay_username"
                               value="<?php echo esc_attr( $opts['pixabay_username'] ); ?>"
                               placeholder="Tags for the search, e.g. lakestylez_portfolio, seegraphie_ai">
                    </td>
                </tr>
                <tr class="ls-sp-platform-row" data-platform="adobe">
                    <th><label for="ls_sp_portfolio_url">Portfolio URL</label></th>
                    <td>
                        <input type="text" class="regular-text" id="ls_sp_portfolio_url" name="ls_sp_portfolio_url"
                               value="<?php echo esc_attr( $opts['portfolio_url'] ); ?>"
                               placeholder="https://stock.adobe.com/de/contributor/...">
                    </td>
                </tr>
                <tr>
                    <th><label for="ls_sp_initial_count">Initial image count</label></th>
                    <td><input type="number" min="1" id="ls_sp_initial_count" name="ls_sp_initial_count"
                               value="<?php echo intval( $opts['initial_count'] ); ?>"></td>
                </tr>
                <tr>
                    <th><label for="ls_sp_backlink_color">Backlink color</label></th>
                    <td><input type="text" id="ls_sp_backlink_color" name="ls_sp_backlink_color"
                               value="<?php echo esc_attr( $opts['backlink_color'] ); ?>"></td>
                </tr>
                <tr>
                    <th><label for="ls_sp_order">Order</label></th>
                    <td>
                        <select name="ls_sp_order" id="ls_sp_order">
                            <option value="original" <?php selected( $opts['order'], 'original' ); ?>>Original order</option>
                            <option value="random" <?php selected( $opts['order'], 'random' ); ?>>Random</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <th><label for="ls_sp_layout">Layout</label></th>
                    <td>
                        <select name="ls_sp_layout" id="ls_sp_layout">
                            <option value="grid" <?php selected( $opts['layout'], 'grid' ); ?>>Standard grid (rows)</option>
                            <option value="masonry" <?php selected( $opts['layout'], 'masonry' ); ?>>Masonry (gapless)</option>
                        </select>
                    </td>
                </tr>
                <tr class="ls-sp-ratio-row">
                    <th><label for="ls_sp_ratio">Image aspect ratio (grid only)</label></th>
                    <td>
                        <select name="ls_sp_ratio" id="ls_sp_ratio">
                            <option value="auto" <?php selected( isset( $opts['ratio'] ) ? $opts['ratio'] : 'auto', 'auto' ); ?>>Automatic</option>
                            <option value="1:1" <?php selected( isset( $opts['ratio'] ) ? $opts['ratio'] : 'auto', '1:1' ); ?>>Square (1:1)</option>
                            <option value="3:2" <?php selected( isset( $opts['ratio'] ) ? $opts['ratio'] : 'auto', '3:2' ); ?>>Wide (3:2)</option>
                            <option value="4:3" <?php selected( isset( $opts['ratio'] ) ? $opts['ratio'] : 'auto', '4:3' ); ?>>Classic (4:3)</option>
                            <option value="16:9" <?php selected( isset( $opts['ratio'] ) ? $opts['ratio'] : 'auto', '16:9' ); ?>>Widescreen (16:9)</option>
                        </select>
                        <p class="description"><?php esc_html_e( 'Only affects the standard grid. In the masonry layout the original aspect ratios are kept.', 'ls-stock-portfolio' ); ?></p>
                    </td>
                </tr>
    <tr>
        <th><label for="ls_sp_lightbox_animation_duration">Lightbox animation duration (ms)</label></th>
        <td>
            <input type="number"
                   min="100"
                   max="5000"
                   step="50"
                   id="ls_sp_lightbox_animation_duration"
                   name="ls_sp_lightbox_animation_duration"
                   value="<?php echo isset( $opts['lightbox_animation_duration'] ) ? intval( $opts['lightbox_animation_duration'] ) : 600; ?>"
                   <?php disabled( ! lsmsp_is_pro_active() ); ?>>
            <p class="description">
                <?php
                if ( lsmsp_is_pro_active() ) {
                    esc_html_e( 'Controls the duration of fade and slide animations in the lightbox (in milliseconds).', 'ls-stock-portfolio' );
                } else {
                    esc_html_e( 'Available in Pro: controls the duration of fade and slide animations in the lightbox. The default duration of 600 ms is used in the free version.', 'ls-stock-portfolio' );
                }
                ?>
            </p>
        </td>
    </tr>
    <tr>
        <th><label for="ls_sp_slideshow_interval">Slideshow interval (seconds)</label></th>
        <td>
            <input type="number" min="1" max="60" id="ls_sp_slideshow_interval" name="ls_sp_slideshow_interval"
                   value="<?php echo intval( $opts['slideshow_interval'] ); ?>" <?php disabled( ! lsmsp_is_pro_active() ); ?>>
            <p class="description">
                <?php
                if ( lsmsp_is_pro_active() ) {
                    esc_html_e( 'Controls the delay between slides in the lightbox slideshow.', 'ls-stock-portfolio' );
                } else {
                    esc_html_e( 'Available in Pro: controls the delay between slides in the lightbox slideshow. The default interval of 4 seconds is used in the free version.', 'ls-stock-portfolio' );
                }
                ?>
            </p>
        </td>
    </tr>
    
    <tr>
        <th><label for="ls_sp_button_bg">Load more button style (Pro)</label></th>
        <td>
            <fieldset>
                <p>
                    <label for="ls_sp_button_bg" style="display:inline-block;min-width:140px;">
                        <?php esc_html_e( 'Background color', 'ls-stock-portfolio' ); ?>
                    </label>
                    <input type="text"
                           id="ls_sp_button_bg"
                           name="ls_sp_button_bg"
                           value="<?php echo esc_attr( $opts['button_bg'] ); ?>"
                           <?php disabled( ! lsmsp_is_pro_active() ); ?>
                           placeholder="#ffffff">
                </p>
                <p>
                    <label for="ls_sp_button_text_color" style="display:inline-block;min-width:140px;">
                        <?php esc_html_e( 'Text color', 'ls-stock-portfolio' ); ?>
                    </label>
                    <input type="text"
                           id="ls_sp_button_text_color"
                           name="ls_sp_button_text_color"
                           value="<?php echo esc_attr( $opts['button_text_color'] ); ?>"
                           <?php disabled( ! lsmsp_is_pro_active() ); ?>
                           placeholder="#000000">
                </p>
                <p>
                    <label for="ls_sp_button_border_color" style="display:inline-block;min-width:140px;">
                        <?php esc_html_e( 'Border color', 'ls-stock-portfolio' ); ?>
                    </label>
                    <input type="text"
                           id="ls_sp_button_border_color"
                           name="ls_sp_button_border_color"
                           value="<?php echo esc_attr( $opts['button_border_color'] ); ?>"
                           <?php disabled( ! lsmsp_is_pro_active() ); ?>
                           placeholder="#cccccc">
                </p>
                <p>
                    <label for="ls_sp_button_border_radius" style="display:inline-block;min-width:140px;">
                        <?php esc_html_e( 'Border radius (px)', 'ls-stock-portfolio' ); ?>
                    </label>
                    <input type="number"
                           min="0"
                           id="ls_sp_button_border_radius"
                           name="ls_sp_button_border_radius"
                           value="<?php echo intval( $opts['button_border_radius'] ); ?>"
                           <?php disabled( ! lsmsp_is_pro_active() ); ?>>
                </p>
                <p class="description">
                    <?php
                    if ( lsmsp_is_pro_active() ) {
                        esc_html_e( 'Adjust the styling of the \"Load more images\" button. Leave these values at their defaults to keep the standard look.', 'ls-stock-portfolio' );
                    } else {
                        esc_html_e( 'Available in Pro: customize the styling of the \"Load more images\" button. The free version uses the default styling.', 'ls-stock-portfolio' );
                    }
                    ?>
                </p>
            </fieldset>
        </td>
    </tr>
                

                

                

                

                

                

                
    <tr>
        <th><label for="ls_sp_lightbox_theme"><?php esc_html_e( 'Lightbox theme (Pro)', 'ls-stock-portfolio' ); ?></label></th>
        <td>
    <select name="ls_sp_lightbox_theme" id="ls_sp_lightbox_theme" <?php disabled( ! lsmsp_is_pro_active() ); ?>>
        <option value="default" <?php selected( $opts['lightbox_theme'], 'default' ); ?>>
            <?php esc_html_e( 'Default', 'ls-stock-portfolio' ); ?>
        </option>
        <option value="carousel" <?php selected( $opts['lightbox_theme'], 'carousel' ); ?>>
            <?php esc_html_e( 'Carousel', 'ls-stock-portfolio' ); ?>
        </option>
        <option value="filmstrip" <?php selected( $opts['lightbox_theme'], 'filmstrip' ); ?>>
            <?php esc_html_e( 'Filmstrip', 'ls-stock-portfolio' ); ?>
        </option>
        <option value="fullscreen" <?php selected( $opts['lightbox_theme'], 'fullscreen' ); ?>>
            <?php esc_html_e( 'Fullscreen', 'ls-stock-portfolio' ); ?>
        </option>
    </select>
    <p class="description">
        <?php
        if ( lsmsp_is_pro_active() ) {
            esc_html_e( 'Choose the lightbox layout used when viewing images.', 'ls-stock-portfolio' );
        } else {
            esc_html_e( 'Available in Pro: choose different lightbox layouts such as carousel, filmstrip or fullscreen. The free version uses the default layout.', 'ls-stock-portfolio' );
        }
        ?>
    </p>
        </td>
    </tr>
    <tr>
        <th><label for="ls_sp_lightbox_animation"><?php esc_html_e( 'Lightbox animation (Pro)', 'ls-stock-portfolio' ); ?></label></th>
        <td>
            <select name="ls_sp_lightbox_animation" id="ls_sp_lightbox_animation" <?php disabled( ! lsmsp_is_pro_active() ); ?>>
                <option value="default" <?php selected( $opts['lightbox_animation'], 'default' ); ?>><?php esc_html_e( 'Default', 'ls-stock-portfolio' ); ?></option>
                <option value="fade" <?php selected( $opts['lightbox_animation'], 'fade' ); ?>><?php esc_html_e( 'Fade', 'ls-stock-portfolio' ); ?></option>
                <option value="slide" <?php selected( $opts['lightbox_animation'], 'slide' ); ?>><?php esc_html_e( 'Slide', 'ls-stock-portfolio' ); ?></option>
            </select>
            <p class="description">
                <?php
                if ( lsmsp_is_pro_active() ) {
                    esc_html_e( 'Control how images transition inside the lightbox.', 'ls-stock-portfolio' );
                } else {
                    esc_html_e( 'Available in Pro: add fade or slide transitions inside the lightbox. The free version uses the default transition.', 'ls-stock-portfolio' );
                }
                ?>
            </p>
        </td>
    </tr>

                <tr>
                    <th><label for="ls_sp_gap">Gap between images</label></th>
                    <td><input type="text" id="ls_sp_gap" name="ls_sp_gap"
                               value="<?php echo esc_attr( $opts['gap'] ); ?>" placeholder="e.g. 12px"></td>
                </tr>
                <tr>
                    <th><label for="ls_sp_cols">Images per row</label></th>
                    <td><input type="number" min="1" id="ls_sp_cols" name="ls_sp_cols"
                               value="<?php echo intval( $opts['cols'] ); ?>"></td>
                </tr>
                <tr>
                    <th><label for="ls_sp_cache_hours">Cache duration (hours)</label></th>
                    <td><input type="number" min="1" id="ls_sp_cache_hours" name="ls_sp_cache_hours"
                               value="<?php echo intval( $opts['cache_hours'] ); ?>"></td>
                </tr>
                <tr>
                    <th><label for="ls_sp_lang">Language</label></th>
                    <td>
                        <select name="ls_sp_lang" id="ls_sp_lang">
                            <option value="de" <?php selected( $opts['lang'], 'de' ); ?>>German</option>
                            <option value="en" <?php selected( $opts['lang'], 'en' ); ?>>English</option>
                        </select>
                    </td>
                </tr>
    <?php
    $lsmsp_freemius_pro = function_exists( 'lsmsp_is_freemius_pro_active' ) && lsmsp_is_freemius_pro_active();

    if ( ! $lsmsp_freemius_pro ) :
    ?>
        
        
        
     <!--------------------------------------------------------------------------------------------------------------------------
        
        
    <tr>
        <th scope="row"><label for="ls_sp_license_key"><?php esc_html_e( 'License key (Pro)', 'ls-stock-portfolio' ); ?></label></th>
        <td>
            <?php
            $saved_license_key = get_option( 'ls_sp_license_key', '' );
            ?>
            <input type="text" class="regular-text" id="ls_sp_license_key" name="ls_sp_license_key"
                   value="<?php echo esc_attr( $saved_license_key ); ?>"
                   placeholder="<?php esc_attr_e( 'Paste your license key here…', 'ls-stock-portfolio' ); ?>">
            <p class="description">
                <?php
                esc_html_e( 'Activate LS Stock Portfolio Pro with your license key.', 'ls-stock-portfolio' );
                echo ' ';
                esc_html_e( 'If you purchased the plugin via Freemius, Pro features will be enabled automatically and no license key is required here.', 'ls-stock-portfolio' );
                ?>
            </p>
            <?php
            if ( ! empty( $license_status ) ) :
                echo '<p class="description" style="margin-top:4px;">';
                if ( ! empty( $license_status['valid'] ) && empty( $license_status['error'] ) ) {
                    echo '<span style="color:#1a7f37;font-weight:600;">' .
                         esc_html__( 'Pro is active. The frontend backlink will be hidden automatically. Thanks a lot for your support! :)', 'ls-stock-portfolio' ) .
                         '</span>';
                } elseif ( ! empty( $license_status['error'] ) ) {
                    /* translators: %s: license error message. */
                    echo '<span style="color:#cc0000;font-weight:600;">' .
                         esc_html( sprintf( __( 'License error: %s', 'ls-stock-portfolio' ), $license_status['error'] ) ) .
                         '</span>';
                } elseif ( isset( $license_status['reason'] ) && 'empty' === $license_status['reason'] ) {
                    echo '<span style="color:#cc7a00;font-weight:600;">' .
                         esc_html__( 'No license key saved. The plugin is running in the free version.', 'ls-stock-portfolio' ) .
                         '</span>';
                }
                echo '</p>';
            endif;
            ?>
        </td>
    </tr>
    
    
    --------------------------------------------------------------------------------------------------------------------------->
    
    
    
    <?php endif; ?>
            </table>

            <!-- Button + PayPal nebeneinander (nur Backend) -->
            <div style="display:flex;align-items:center;gap:16px;margin-top:12px;">
                <input type="submit" name="ls_sp_save" class="button-primary" value="Save changes">

                <?php if ( ! lsmsp_is_pro_active() ) : ?>
                <a href="<?php echo esc_url( 'https://www.paypal.com/donate?hosted_button_id=KDN9QUMA5JHHE' ); ?>"
                   target="_blank"
                   rel="noopener"
                   class="button-secondary">
                    <?php esc_html_e( 'Donate via PayPal', 'ls-stock-portfolio' ); ?>
                </a>
                <?php endif; ?>
            </div>

            <?php if ( ! lsmsp_is_pro_active() ) : ?>
            <div class="notice" style="margin-top:20px;padding:16px 20px;background:#f6f7f7;border:1px solid #dcdcde;border-radius:4px;">
                <p style="margin-top:0;">
                    <?php esc_html_e( 'You are using the free version. If you like this plugin, you can support further development with a small donation or upgrade to the Pro version.', 'ls-stock-portfolio' ); ?><br>
                    <?php esc_html_e( 'Note: Donations do not unlock Pro features. A valid Pro license is required to activate all premium functionality.', 'ls-stock-portfolio' ); ?>
                </p>
                <p>
                    <?php
                    // Determine the appropriate upgrade URL: prefer Freemius checkout, fall back to Lemon Squeezy.
                    $lsmsp_upgrade_url = '';

                    if ( function_exists( 'lsmsp_fs' ) ) {
                        $fs = lsmsp_fs();
                        if ( $fs && method_exists( $fs, 'get_upgrade_url' ) ) {
                            $lsmsp_upgrade_url = $fs->get_upgrade_url();
                        }
                    }

                    if ( ! $lsmsp_upgrade_url ) {
                        // Fallback to the existing Lemon Squeezy purchase link.
                        $lsmsp_upgrade_url = 'https://ls-mediendesign.lemonsqueezy.com/buy/08e518dc-f3f7-4931-99a5-6282b389a1ef';
                    }
                    ?>
                    <a href="<?php echo esc_url( $lsmsp_upgrade_url ); ?>"
                       target="_self"
                       rel="noopener"
                       class="button-primary">
                        <?php esc_html_e( 'Upgrade to LS Stock Portfolio Pro', 'ls-stock-portfolio' ); ?>
                    </a>

                    <a href="<?php echo esc_url( 'https://www.paypal.com/donate?hosted_button_id=KDN9QUMA5JHHE' ); ?>"
                       target="_blank"
                       rel="noopener"
                       class="button-secondary">
                        <?php esc_html_e( 'Donate via PayPal', 'ls-stock-portfolio' ); ?>
                    </a>
                </p>
            </div>
            <?php endif; ?>

            <div class="ls-sp-shortcodes">
                <h2><?php esc_html_e( 'Shortcodes', 'ls-stock-portfolio' ); ?></h2>

                <table class="widefat striped ls-sp-shortcodes-table">
                    <tbody>
                    <tr>
                        <th scope="row"><?php esc_html_e( 'Standard', 'ls-stock-portfolio' ); ?></th>
                        <td>
                            <p>
                                <?php esc_html_e( 'Single platform – optionally with attribute', 'ls-stock-portfolio' ); ?>
                                <code>platform="adobe|unsplash|pixabay"</code>.
                            </p>
                            <p>
                                <?php esc_html_e( 'Advanced options (optional):', 'ls-stock-portfolio' ); ?>
                                <code>cols="5"</code>,
                                <code>gap="8px"</code>,
                                <code>layout="masonry"</code>,
                                <code>initial="18"</code>,
                                <code>lang="en"</code>,
                                <code>backlink_color="#999999"</code>,
                                <code>ratio="1:1"</code>
                            </p>
                            <code class="ls-sp-copy" data-ls-sp-copy="[lsmsp_stock_portfolio]">[lsmsp_stock_portfolio]</code>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><?php esc_html_e( 'Adobe Stock only', 'ls-stock-portfolio' ); ?></th>
                        <td>
                            <code class="ls-sp-copy" data-ls-sp-copy="[lsmsp_stock_portfolio_adobe]">[lsmsp_stock_portfolio_adobe]</code>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><?php esc_html_e( 'Unsplash only', 'ls-stock-portfolio' ); ?></th>
                        <td>
                            <code class="ls-sp-copy" data-ls-sp-copy="[lsmsp_stock_portfolio_unsplash]">[lsmsp_stock_portfolio_unsplash]</code>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><?php esc_html_e( 'Pixabay only', 'ls-stock-portfolio' ); ?></th>
                        <td>
                            <code class="ls-sp-copy" data-ls-sp-copy="[lsmsp_stock_portfolio_pixabay]">[lsmsp_stock_portfolio_pixabay]</code>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><?php esc_html_e( 'All platforms (separate blocks)', 'ls-stock-portfolio' ); ?></th>
                        <td>
                            <p>
                                <?php esc_html_e( 'Control order with', 'ls-stock-portfolio' ); ?>
                                <code>order="asc|desc|random"</code>
                                <?php esc_html_e( 'and select platforms via', 'ls-stock-portfolio' ); ?>
                                <code>platforms="adobe,unsplash,pixabay"</code>.
                            </p>
                            <code class="ls-sp-copy" data-ls-sp-copy='[lsmsp_stock_portfolio_all platforms="adobe,unsplash,pixabay" order="asc"]'>[lsmsp_stock_portfolio_all]</code>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><?php esc_html_e( 'All platforms (mixed grid)', 'ls-stock-portfolio' ); ?></th>
                        <td>
                            <p>
                                <?php esc_html_e( 'Mixed images in a single grid, controlled via', 'ls-stock-portfolio' ); ?>
                                <code>platforms="adobe,unsplash,pixabay"</code>
                                <?php esc_html_e( 'and', 'ls-stock-portfolio' ); ?>
                                <code>order="asc|desc|random"</code>.
                            </p>
                            <code class="ls-sp-copy" data-ls-sp-copy='[lsmsp_stock_portfolio_mix platforms="adobe,unsplash,pixabay" order="asc"]'>[lsmsp_stock_portfolio_mix]</code>
                        </td>
                    </tr>
                    </tbody>
                </table>

                <p class="description">
                    <?php esc_html_e( 'Tip: Click a shortcode to copy it to the clipboard and then paste it into pages, posts or widget areas.', 'ls-stock-portfolio' ); ?>
                </p>
            </div>
        </form>
        <script>
            document.addEventListener('DOMContentLoaded', function () {
                // Sofort nach Laden der Seite das "Upgrade"-Submenü nach aktuellem Pro-Status ein-/ausblenden
                var lsSpIsPro = <?php echo lsmsp_is_pro_active() ? 'true' : 'false'; ?>;

                try {
                    var submenuLinks = document.querySelectorAll(
                        '#toplevel_page_ls-stock-portfolio ul.wp-submenu li a'
                    );

                    submenuLinks.forEach(function (link) {
                        var label = (link.textContent || '').toLowerCase();

                        if (label.indexOf('upgrade') !== -1) {
                            // Wenn Pro aktiv: "Upgrade" verstecken, sonst anzeigen
                            if (lsSpIsPro) {
                                if (link.parentElement) {
                                    link.parentElement.style.display = 'none';
                                }
                            } else {
                                if (link.parentElement) {
                                    link.parentElement.style.display = '';
                                }
                            }
                        }
                    });
                } catch (e) {
                    // Fallback: wenn irgendwas schiefgeht, einfach nix tun
                }

                var platformInput = document.getElementById('ls_sp_platform');
                var rows = document.querySelectorAll('.ls-sp-platform-row');
                var tabs = document.querySelectorAll('.ls-sp-tab');

                if (!platformInput) {
                    return;
                }

                function setActiveTab(platform) {
                    if (!tabs || !tabs.length) {
                        return;
                    }
                    tabs.forEach(function (tab) {
                        var target = tab.getAttribute('data-platform');
                        if (target === platform) {
                            tab.classList.add('button-primary');
                            tab.classList.remove('button-secondary');
                        } else {
                            tab.classList.remove('button-primary');
                            tab.classList.add('button-secondary');
                        }
                    });
                }

                function updatePlatformRows() {
                    var value = platformInput.value || 'adobe';
                    rows.forEach(function (row) {
                        var target = row.getAttribute('data-platform');
                        if (!target) {
                            return;
                        }
                        if (target === value) {
                            row.style.display = '';
                        } else {
                            row.style.display = 'none';
                        }
                    });
                    setActiveTab(value);
                }

                if (tabs && tabs.length) {
                    tabs.forEach(function (tab) {
                        tab.addEventListener('click', function (e) {
                            e.preventDefault();
                            var target = tab.getAttribute('data-platform');
                            if (!target) {
                                return;
                            }
                            platformInput.value = target;
                            updatePlatformRows();
                        });
                    });
                }

                // Click-to-copy for shortcode blocks
                var shortcodeCodes = document.querySelectorAll('.ls-sp-shortcodes-table code[data-ls-sp-copy]');
                if (shortcodeCodes.length) {
                    shortcodeCodes.forEach(function (codeEl) {
                        codeEl.addEventListener('click', function () {
                            var text = codeEl.getAttribute('data-ls-sp-copy') || codeEl.textContent || '';
                            if (!text) {
                                return;
                            }

                            function markCopied(success) {
                                var original = codeEl.getAttribute('data-ls-sp-original');
                                if (!original) {
                                    original = codeEl.textContent;
                                    codeEl.setAttribute('data-ls-sp-original', original);
                                }

                                codeEl.classList.add('ls-sp-copied');
                                codeEl.textContent = success ? 'Copied!' : 'Error';

                                setTimeout(function () {
                                    var restore = codeEl.getAttribute('data-ls-sp-original') || original;
                                    codeEl.textContent = restore;
                                    codeEl.classList.remove('ls-sp-copied');
                                }, 1200);
                            }

                            function fallbackCopy() {
                                var ta = document.createElement('textarea');
                                ta.value = text;
                                ta.style.position = 'fixed';
                                ta.style.opacity = '0';
                                ta.style.left = '-9999px';
                                document.body.appendChild(ta);
                                ta.focus();
                                ta.select();
                                try {
                                    var ok = document.execCommand('copy');
                                    markCopied(ok);
                                } catch (e) {
                                    markCopied(false);
                                }
                                document.body.removeChild(ta);
                            }

                            if (navigator.clipboard && navigator.clipboard.writeText) {
                                navigator.clipboard.writeText(text)
                                    .then(function () {
                                        markCopied(true);
                                    })
                                    .catch(function () {
                                        fallbackCopy();
                                    });
                            } else {
                                fallbackCopy();
                            }
                        });
                    });
                }

                // Bildformat-Option nur anzeigen, wenn Layout = Grid
                var layoutSelect = document.getElementById('ls_sp_layout');
                var ratioRow = document.querySelector('tr.ls-sp-ratio-row');

                function lsSpUpdateRatioRow() {
                    if (!layoutSelect || !ratioRow) {
                        return;
                    }
                    if (layoutSelect.value === 'grid') {
                        ratioRow.style.display = '';
                    } else {
                        ratioRow.style.display = 'none';
                    }
                }

                if (layoutSelect) {
                    layoutSelect.addEventListener('change', lsSpUpdateRatioRow);
                    lsSpUpdateRatioRow();
                }

                updatePlatformRows();
            });
        </script>
    </div>
    <?php
}

/**
 * Bilder aus Portfolio holen + cachen (plattformabhängig)
 *
 * @param string|null $forced_platform Optional: erzwingt eine bestimmte Plattform (adobe|unsplash|pixabay).
 */
function lsmsp_get_images( $forced_platform = null ) {
    $opts = get_option( 'ls_sp_settings', array() );
    $opts = wp_parse_args( $opts, lsmsp_defaults() );

    if ( in_array( $forced_platform, array( 'adobe', 'unsplash', 'pixabay' ), true ) ) {
        $platform = $forced_platform;
    } else {
        $platform = ! empty( $opts['platform'] ) ? $opts['platform'] : 'adobe';
    }

    // Cache-Key: Plattform + Quelle (URL oder Benutzername) + Sortierung
    $cache_source = '';
    switch ( $platform ) {
        case 'pixabay':
            $cache_source = ! empty( $opts['pixabay_username'] ) ? $opts['pixabay_username'] : '';
            break;
        case 'unsplash':
            $cache_source = ! empty( $opts['unsplash_username'] ) ? $opts['unsplash_username'] : '';
            break;
        case 'adobe':
        default:
            $cache_source = ! empty( $opts['portfolio_url'] ) ? $opts['portfolio_url'] : '';
            break;
    }
    if ( empty( $cache_source ) ) {
        return array();
    }
    $cache_key = 'ls_sp_cache_' . md5( $platform . '|' . $cache_source . '|' . $opts['order'] );
    $cached    = get_transient( $cache_key );
    if ( $cached && is_array( $cached ) ) {
        return $cached;
    }

    switch ( $platform ) {
        case 'unsplash':
            $images = lsmsp_get_images_unsplash( $opts );
            break;
        case 'pixabay':
            $images = lsmsp_get_images_pixabay( $opts );
            break;
        case 'adobe':
        default:
            $images = lsmsp_get_images_adobe( $opts );
            break;
    }

    if ( ! is_array( $images ) ) {
        $images = array();
    }

    $ttl = max( 1, intval( $opts['cache_hours'] ) ) * HOUR_IN_SECONDS;
    set_transient( $cache_key, $images, $ttl );

    return $images;
}

/**
 * Provider: Adobe Stock
 */
function lsmsp_get_images_adobe( $opts ) {
    if ( empty( $opts['portfolio_url'] ) ) {
        return array();
    }

    $resp = wp_remote_get(
        $opts['portfolio_url'],
        array(
            'timeout' => 5,
        )
    );
    if ( is_wp_error( $resp ) ) {
        return array();
    }
    $html = wp_remote_retrieve_body( $resp );
    if ( ! $html ) {
        return array();
    }

    // Get initial count from settings
    $initial = isset( $opts['initial_count'] ) ? max( 1, intval( $opts['initial_count'] ) ) : 8;

    // Extract all ftcdn.net preview image URLs from the contributor portfolio HTML
    preg_match_all( '#https://(?:as|t)[0-9]\.ftcdn\.net/[^"\']+#i', $html, $matches );
    if ( empty( $matches[0] ) ) {
        return array();
    }
    $urls = array_values( array_unique( $matches[0] ) );

    // Set a generous, but safe, upper limit for Adobe items based on initial image count
    $max_items = min( $initial * 10, 150 );

    $images = array();
    $seen_ids = array();
    foreach ( $urls as $url ) {
        $asset_id = '';
        if ( preg_match( '/1000_F_([0-9]+)_/i', $url, $mid ) ) {
            $asset_id = $mid[1];
        }
        if ( ! $asset_id ) {
            continue;
        }
        if ( in_array( $asset_id, $seen_ids, true ) ) {
            continue;
        }
        $seen_ids[] = $asset_id;
        $detail_url = 'https://stock.adobe.com/de/search?k=' . rawurlencode( $asset_id ) . '&asset_id=' . rawurlencode( $asset_id );
        $images[] = array(
            'full'       => $url,
            'thumb'      => $url,
            'title'      => '',
            'author'     => '',
            'detail_url' => $detail_url,
        );
        if ( count( $images ) >= $max_items ) {
            break;
        }
    }

    // Apply random order if requested
    if ( 'random' === $opts['order'] ) {
        shuffle( $images );
    }

    return $images;
}


/**
 * Provider: Unsplash
 */
function lsmsp_get_images_unsplash( $opts ) {
    $access_key = ! empty( $opts['unsplash_access_key'] ) ? $opts['unsplash_access_key'] : '';
    $username   = ! empty( $opts['unsplash_username'] ) ? $opts['unsplash_username'] : '';

    if ( empty( $access_key ) || empty( $username ) ) {
        return array();
    }

    // Fetch multiple pages from the Unsplash API so that "Load more" can work reliably.
    $per_page  = 30; // Unsplash maximum
    $max_pages = 3;  // Up to 90 images per cache refresh
    $all_items = array();

    for ( $page = 1; $page <= $max_pages; $page++ ) {
        $args = array(
            'per_page' => $per_page,
            'order_by' => 'latest',
            'page'     => $page,
        );

        $endpoint = add_query_arg( $args, 'https://api.unsplash.com/users/' . rawurlencode( $username ) . '/photos' );

        $resp = wp_remote_get(
            $endpoint,
            array(
                'headers' => array(
                    'Authorization' => 'Client-ID ' . $access_key,
                ),
            )
        );

        if ( is_wp_error( $resp ) ) {
            break;
        }

        $body = wp_remote_retrieve_body( $resp );
        if ( ! $body ) {
            break;
        }

        $data = json_decode( $body, true );
        if ( ! is_array( $data ) || empty( $data ) ) {
            break;
        }

        $all_items = array_merge( $all_items, $data );
    }

    if ( empty( $all_items ) ) {
        return array();
    }

    $images = array();

    foreach ( $all_items as $item ) {
        if ( empty( $item['urls'] ) || ! is_array( $item['urls'] ) ) {
            continue;
        }

        // Direct image URLs for the lightbox
        $full  = ! empty( $item['urls']['full'] )
            ? $item['urls']['full']
            : ( ! empty( $item['urls']['regular'] ) ? $item['urls']['regular'] : '' );

        $thumb = ! empty( $item['urls']['small'] )
            ? $item['urls']['small']
            : ( ! empty( $item['urls']['thumb'] ) ? $item['urls']['thumb'] : $full );

        if ( ! $full ) {
            continue;
        }

        // Attribution data for Unsplash guidelines
        $name        = ! empty( $item['user']['name'] ) ? $item['user']['name'] : '';
        $profile_url = ! empty( $item['user']['links']['html'] ) ? $item['user']['links']['html'] : '';
        $photo_url   = ! empty( $item['links']['html'] ) ? $item['links']['html'] : '';

        $images[] = array(
            'full'           => $full,
            'thumb'          => $thumb,
            'credit_name'    => $name,
            'credit_profile' => $profile_url,
            'credit_photo'   => $photo_url,
        );
    }

    if ( 'random' === $opts['order'] ) {
        shuffle( $images );
    }

    return $images;
}

/**
 * Provider: Pixabay
 */
function lsmsp_get_images_pixabay( $opts ) {
    $api_key  = ! empty( $opts['pixabay_api_key'] ) ? $opts['pixabay_api_key'] : '';
    $tags_raw = ! empty( $opts['pixabay_username'] ) ? $opts['pixabay_username'] : '';

    if ( empty( $api_key ) || empty( $tags_raw ) ) {
        return array();
    }

    // Interpret the stored value as one or more tags (comma-separated).
    $tags_raw  = trim( $tags_raw );
    $tag_parts = preg_split( '/[,]+/', $tags_raw );
    $tag_parts = array_filter( array_map( 'trim', $tag_parts ) );

    if ( empty( $tag_parts ) ) {
        return array();
    }

    $images   = array();
    $seen_ids = array();

    foreach ( $tag_parts as $tag ) {
        if ( '' === $tag ) {
            continue;
        }

        $args = array(
            'key'         => $api_key,
            'image_type'  => 'photo',
            'per_page'    => 200,
            'safesearch'  => 'true',
            'orientation' => 'all',
            'order'       => 'latest',
            'q'           => $tag,
        );

        $endpoint = add_query_arg( $args, 'https://pixabay.com/api/' );

        $resp = wp_remote_get( $endpoint );
        if ( is_wp_error( $resp ) ) {
            continue;
        }

        $body = wp_remote_retrieve_body( $resp );
        if ( ! $body ) {
            continue;
        }

        $data = json_decode( $body, true );
        if ( ! is_array( $data ) || empty( $data['hits'] ) || ! is_array( $data['hits'] ) ) {
            continue;
        }

        foreach ( $data['hits'] as $hit ) {
            if ( empty( $hit['largeImageURL'] ) && empty( $hit['webformatURL'] ) ) {
                continue;
            }

            $id = isset( $hit['id'] ) ? intval( $hit['id'] ) : 0;
            if ( $id && in_array( $id, $seen_ids, true ) ) {
                continue;
            }
            if ( $id ) {
                $seen_ids[] = $id;
            }

            $full  = ! empty( $hit['largeImageURL'] ) ? $hit['largeImageURL'] : $hit['webformatURL'];
            $thumb = ! empty( $hit['webformatURL'] ) ? $hit['webformatURL'] : $full;

            $credit_name = ! empty( $hit['user'] ) ? $hit['user'] : '';
            $detail_url  = ! empty( $hit['pageURL'] ) ? $hit['pageURL'] : '';

            $images[] = array(
                'full'        => $full,
                'thumb'       => $thumb,
                'credit_name' => $credit_name,
                'detail_url'  => $detail_url,
            );
        }
    }

    if ( 'random' === $opts['order'] && ! empty( $images ) ) {
        shuffle( $images );
    }

    return $images;
}

/**
 * Shortcodes
 */

// Basis-Shortcode – nutzt optional das Attribut "platform" oder die Standard-Einstellung.
function lsmsp_shortcode_stock_portfolio( $atts = array() ) {
    $atts = shortcode_atts(
        array(
            'platform'       => '',
            'cols'           => '',   // Anzahl Spalten überschreiben
            'gap'            => '',   // Abstand überschreiben (z. B. "8px")
            'layout'         => '',   // grid|masonry
            'initial'        => '',   // Anzahl initialer Bilder
            'backlink_color' => '',   // Hex-Farbe für Backlink
            'lang'           => '',   // de|en
            'ratio'          => '',   // auto | 1:1 | 3:2 | 4:3 | 16:9 (nur Grid)
        ),
        $atts,
        'lsmsp_stock_portfolio'
    );

    $forced_platform = null;
    if ( in_array( $atts['platform'], array( 'adobe', 'unsplash', 'pixabay' ), true ) ) {
        $forced_platform = $atts['platform'];
    }

    // Per-Shortcode-Overrides vorbereiten.
    $override = array();
    if ( '' !== $atts['cols'] ) {
        $override['cols'] = $atts['cols'];
    }
    if ( '' !== $atts['gap'] ) {
        $override['gap'] = $atts['gap'];
    }
    if ( '' !== $atts['layout'] ) {
        $override['layout'] = $atts['layout'];
    }
    if ( '' !== $atts['initial'] ) {
        $override['initial_count'] = $atts['initial'];
    }
    if ( '' !== $atts['backlink_color'] ) {
        $override['backlink_color'] = $atts['backlink_color'];
    }
    if ( '' !== $atts['lang'] ) {
        $override['lang'] = $atts['lang'];
    }
    if ( '' !== $atts['ratio'] ) {
        $override['ratio'] = $atts['ratio'];
    }

    ob_start();
    lsmsp_render_frontend( $forced_platform, $override );
    return ob_get_clean();
}
add_shortcode( 'lsmsp_stock_portfolio', 'lsmsp_shortcode_stock_portfolio' );

// Adobe-spezifischer Shortcode.
function lsmsp_shortcode_stock_portfolio_adobe() {
    ob_start();
    lsmsp_render_frontend( 'adobe' );
    return ob_get_clean();
}
add_shortcode( 'lsmsp_stock_portfolio_adobe', 'lsmsp_shortcode_stock_portfolio_adobe' );

// Unsplash-spezifischer Shortcode.
function lsmsp_shortcode_stock_portfolio_unsplash() {
    ob_start();
    lsmsp_render_frontend( 'unsplash' );
    return ob_get_clean();
}
add_shortcode( 'lsmsp_stock_portfolio_unsplash', 'lsmsp_shortcode_stock_portfolio_unsplash' );

// Pixabay-spezifischer Shortcode.
function lsmsp_shortcode_stock_portfolio_pixabay() {
    ob_start();
    lsmsp_render_frontend( 'pixabay' );
    return ob_get_clean();
}
add_shortcode( 'lsmsp_stock_portfolio_pixabay', 'lsmsp_shortcode_stock_portfolio_pixabay' );

// Alle Plattformen – rendert mehrere Grids nacheinander.
function lsmsp_shortcode_stock_portfolio_all( $atts = array() ) {
    $atts = shortcode_atts(
        array(
            'order'     => 'asc',                         // asc | desc | random
            'platforms' => 'adobe,unsplash,pixabay',      // Kommagetrennte Liste
        ),
        $atts,
        'lsmsp_stock_portfolio_all'
    );

    // Plattformliste parsen und auf gültige Werte begrenzen.
    $platforms_raw = explode( ',', $atts['platforms'] );
    $platforms     = array();

    foreach ( $platforms_raw as $pf ) {
        $pf = strtolower( trim( $pf ) );
        if ( in_array( $pf, array( 'adobe', 'unsplash', 'pixabay' ), true ) && ! in_array( $pf, $platforms, true ) ) {
            $platforms[] = $pf;
        }
    }

    if ( empty( $platforms ) ) {
        $platforms = array( 'adobe', 'unsplash', 'pixabay' );
    }

    // Reihenfolge der Plattformen steuern.
    switch ( strtolower( $atts['order'] ) ) {
        case 'desc':
            $platforms = array_reverse( $platforms );
            break;
        case 'random':
            shuffle( $platforms );
            break;
        case 'asc':
        default:
            // Original-Reihenfolge beibehalten.
            break;
    }

    // Für die Überschriften die Sprache ermitteln.
    $opts = get_option( 'ls_sp_settings', array() );
    $opts = wp_parse_args( $opts, lsmsp_defaults() );
    $lang = ( 'en' === $opts['lang'] ) ? 'en' : 'de';

    ob_start();

    foreach ( $platforms as $pf ) {
        $title = '';
        if ( 'adobe' === $pf ) {
            $title = ( 'en' === $lang ) ? 'Adobe Stock Portfolio' : 'Adobe Stock Portfolio';
        } elseif ( 'unsplash' === $pf ) {
            $title = ( 'en' === $lang ) ? 'Unsplash Portfolio' : 'Unsplash Portfolio';
        } elseif ( 'pixabay' === $pf ) {
            $title = ( 'en' === $lang ) ? 'Pixabay Portfolio' : 'Pixabay Portfolio';
        }

        echo '<div class="ls-sp-all-section ls-sp-all-' . esc_attr( $pf ) . '" style="margin-bottom:40px;">';
        if ( $title ) {
            echo '<h2 class="ls-sp-all-title" style="margin-bottom:12px;">' . esc_html( $title ) . '</h2>';
        }
        lsmsp_render_frontend( $pf );
        echo '</div>';
    }

    return ob_get_clean();
}
add_shortcode( 'lsmsp_stock_portfolio_all', 'lsmsp_shortcode_stock_portfolio_all' );

// Gemischtes Grid aus mehreren Plattformen – alle Bilder in einem gemeinsamen Portfolio.
function lsmsp_shortcode_stock_portfolio_mix( $atts = array() ) {
    $atts = shortcode_atts(
        array(
            'order'     => 'asc',                         // asc | desc | random
            'platforms' => 'adobe,unsplash,pixabay',      // Kommagetrennte Liste
            'limit'     => 0,                             // 0 = nutzt initial_count aus den Einstellungen
        ),
        $atts,
        'lsmsp_stock_portfolio_mix'
    );

    // Plattformliste parsen und auf gültige Werte begrenzen.
    $platforms_raw = explode( ',', $atts['platforms'] );
    $platforms     = array();

    foreach ( $platforms_raw as $pf ) {
        $pf = strtolower( trim( $pf ) );
        if ( in_array( $pf, array( 'adobe', 'unsplash', 'pixabay' ), true ) && ! in_array( $pf, $platforms, true ) ) {
            $platforms[] = $pf;
        }
    }

    if ( empty( $platforms ) ) {
        $platforms = array( 'adobe', 'unsplash', 'pixabay' );
    }

    // Basis-Einstellungen laden.
    $opts = get_option( 'ls_sp_settings', array() );
    $opts = wp_parse_args( $opts, lsmsp_defaults() );

    // Bilder aller gewünschten Plattformen einsammeln (aus Cache, da ls_sp_get_images das bereits übernimmt).
    $merged = array();

    foreach ( $platforms as $pf ) {
        $imgs = lsmsp_get_images( $pf );
        if ( ! is_array( $imgs ) || empty( $imgs ) ) {
            continue;
        }
        foreach ( $imgs as $img ) {
            $merged[] = array(
                'platform' => $pf,
                'img'      => $img,
            );
        }
    }

    if ( empty( $merged ) ) {
        return '';
    }

    // Reihenfolge der Bilder steuern.
    $order = strtolower( $atts['order'] );
    if ( 'random' === $order ) {
        shuffle( $merged );
    } elseif ( 'desc' === $order ) {
        $merged = array_reverse( $merged );
    } // 'asc' = Originalreihenfolge belassen

    // Wie viele Bilder initial anzeigen?
    $initial = max( 1, intval( $opts['initial_count'] ) );
    $limit   = intval( $atts['limit'] );
    if ( $limit > 0 ) {
        $initial = $limit;
    }

    $visible = array_slice( $merged, 0, $initial );
    $hidden  = array_slice( $merged, $initial );

    // Layout-Einstellungen übernehmen (analog zu ls_sp_render_frontend).
    $cols   = max( 1, intval( $opts['cols'] ) );
    $gap    = $opts['gap'] ? $opts['gap'] : '12px';
    $layout = ! empty( $opts['layout'] ) ? $opts['layout'] : 'grid';

    $text_credit = 'Lake Stylez – Mediendesign';

    $item_width = 'calc((100% - (' . ( $cols - 1 ) . ' * ' . $gap . ')) / ' . $cols . ')';

    // Sprache für Button-Text ermitteln.
    $lang      = ( isset( $opts['lang'] ) && 'en' === $opts['lang'] ) ? 'en' : 'de';
    $btn_label = ( 'en' === $lang ) ? 'Load more images' : 'Weitere Bilder laden';

    // Default button style (free und Basis für Pro).
    $btn_style = 'display:inline-block;padding:6px 18px;border:1px solid #ccc;background:#fff;border-radius:3px;cursor:pointer;';

    if ( lsmsp_is_pro_active() ) {
        $btn_bg     = ! empty( $opts['button_bg'] ) ? $opts['button_bg'] : '#ffffff';
        $btn_text   = ! empty( $opts['button_text_color'] ) ? $opts['button_text_color'] : '#000000';
        $btn_border = ! empty( $opts['button_border_color'] ) ? $opts['button_border_color'] : '#cccccc';
        $btn_radius = isset( $opts['button_border_radius'] ) ? max( 0, intval( $opts['button_border_radius'] ) ) : 3;

        $btn_style = 'display:inline-block;padding:6px 18px;border:1px solid ' . $btn_border . ';background:' . $btn_bg . ';border-radius:' . $btn_radius . 'px;cursor:pointer;color:' . $btn_text . ';';
    }

    ob_start();
    ?>
    <div class="ls-sp-container" style="width:100%;">
        <div class="ls-sp-grid"
             data-limit="<?php echo esc_attr( $initial ); ?>"
             data-cols="<?php echo esc_attr( $cols ); ?>"
             data-gap="<?php echo esc_attr( $gap ); ?>"
             data-lightbox="1"
             data-layout="<?php echo esc_attr( $layout ); ?>"
             data-platform="mixed"
             style="display:flex;flex-wrap:wrap;gap:<?php echo esc_attr( $gap ); ?>;width:100%;">
            <?php
            foreach ( $visible as $entry ) {
                $pf  = isset( $entry['platform'] ) ? $entry['platform'] : 'adobe';
                $img = isset( $entry['img'] ) ? $entry['img'] : array();
                if ( empty( $img ) ) {
                    continue;
                }
                lsmsp_render_item( $img, $opts, $pf, $item_width, false );
            }
            ?>
        </div>

        <?php if ( ! empty( $hidden ) ) : ?>
            <div class="ls-sp-mix-hidden" style="display:none;">
                <?php
                foreach ( $hidden as $entry ) {
                    $pf  = isset( $entry['platform'] ) ? $entry['platform'] : 'adobe';
                    $img = isset( $entry['img'] ) ? $entry['img'] : array();
                    if ( empty( $img ) ) {
                        continue;
                    }
                    lsmsp_render_item( $img, $opts, $pf, $item_width, false );
                }
                ?>
            </div>

            <div class="ls-sp-load-more-wrap" style="text-align:center;margin-top:16px;">
                <button type="button"
                        class="ls-sp-load-more-mix ls-sp-more"
                        style="<?php echo esc_attr( $btn_style ); ?>">
                    <?php echo esc_html( $btn_label ); ?>
                </button>
            </div>
        <?php endif; ?>

        <?php if ( ! lsmsp_is_pro_active() ) : ?>
        <div class="ls-sp-credit" style="text-align:center;margin-top:10px;">
            <a href="<?php echo esc_url( 'https://lakestylez.com' ); ?>" target="_blank" rel="noopener"
               style="color:<?php echo esc_attr( $opts['backlink_color'] ); ?> !important;font-size:12px;text-decoration:none;">
                &copy; <?php echo esc_html( gmdate( 'Y' ) ); ?> <?php echo esc_html( $text_credit ); ?>
            </a>
        </div>
        <?php endif; ?>
    </div>
    <?php
    return ob_get_clean();
}
add_shortcode( 'lsmsp_stock_portfolio_mix', 'lsmsp_shortcode_stock_portfolio_mix' );

/**
 * Render a single grid item for LS Stock Portfolio.
 */
function lsmsp_render_item( $img, $opts, $platform, $item_width, $is_hidden = false ) {
    $layout = ! empty( $opts['layout'] ) ? $opts['layout'] : 'grid';
    $ratio  = ! empty( $opts['ratio'] ) ? $opts['ratio'] : 'auto';

    $style = 'box-sizing:border-box;width:' . $item_width . ';';
    if ( $is_hidden ) {
        $style .= 'display:none;';
    }

    // Optionales zusätzliches Styling für feste Seitenverhältnisse im Grid-Layout
    $img_extra_style = '';
    if ( 'grid' === $layout && $ratio && 'auto' !== $ratio ) {
        if ( '1:1' === $ratio ) {
            $img_extra_style = 'aspect-ratio:1/1;object-fit:cover;';
        } elseif ( '3:2' === $ratio ) {
            $img_extra_style = 'aspect-ratio:3/2;object-fit:cover;';
        } elseif ( '4:3' === $ratio ) {
            $img_extra_style = 'aspect-ratio:4/3;object-fit:cover;';
        } elseif ( '16:9' === $ratio ) {
            $img_extra_style = 'aspect-ratio:16/9;object-fit:cover;';
        }
    }

    // Prepare Unsplash/Adobe/Pixabay credit attributes for lightbox
    $credit_text_attr = '';
    $credit_url_attr  = '';

    if ( 'unsplash' === $platform ) {
        $credit_name = ! empty( $img['credit_name'] ) ? $img['credit_name'] : '';
        $credit_url  = '';

        if ( ! empty( $img['credit_photo'] ) ) {
            $credit_url = $img['credit_photo'];
        } elseif ( ! empty( $img['credit_profile'] ) ) {
            $credit_url = $img['credit_profile'];
        }

        if ( $credit_name && $credit_url ) {
            $utm              = ( false === strpos( $credit_url, '?' ) )
                ? '?utm_source=LSStockPortfolio&amp;utm_medium=referral'
                : '&amp;utm_source=LSStockPortfolio&amp;utm_medium=referral';
            $credit_url_full  = $credit_url . $utm;
            $credit_text_attr = sprintf( 'Photo by %s on Unsplash', $credit_name );
            $credit_url_attr  = $credit_url_full;
        }
    } elseif ( 'adobe' === $platform ) {
        $title  = ! empty( $img['title'] ) ? $img['title'] : '';
        $author = ! empty( $img['author'] ) ? $img['author'] : '';
        $detail = ! empty( $img['detail_url'] ) ? $img['detail_url'] : '';

        if ( $detail ) {
            $label_parts = array();

            if ( $title ) {
                $label_parts[] = $title;
            }

            if ( $author ) {
                $label_parts[] = $author;
            }

            if ( ! empty( $label_parts ) ) {
                $label = implode( ' – ', $label_parts ) . ' (Adobe Stock)';
            } else {
                $label = ( 'en' === $opts['lang'] )
                    ? 'View on Adobe Stock'
                    : 'Auf Adobe Stock ansehen';
            }

            $credit_text_attr = $label;
            $credit_url_attr  = $detail;
        }
    } elseif ( 'pixabay' === $platform ) {
        $name   = ! empty( $img['credit_name'] ) ? $img['credit_name'] : '';
        $detail = ! empty( $img['detail_url'] ) ? $img['detail_url'] : '';

        if ( $name && $detail ) {
            $credit_text_attr = sprintf( 'Photo by %s on Pixabay', $name );
            $credit_url_attr  = $detail;
        }
    }
    ?>
    <div class="ls-sp-item" style="<?php echo esc_attr( $style ); ?>">
        <a href="<?php echo esc_url( $img['full'] ); ?>"
           class="ls-sp-link"
           <?php if ( $credit_text_attr && $credit_url_attr ) : ?>
               data-ls-sp-credit-text="<?php echo esc_attr( $credit_text_attr ); ?>"
               data-ls-sp-credit-url="<?php echo esc_url( $credit_url_attr ); ?>"
           <?php endif; ?>
           style="display:block;width:100%;height:100%;">
            <img src="<?php echo esc_url( $img['thumb'] ); ?>"
                 alt="<?php esc_attr_e( 'Stock Portfolio', 'ls-stock-portfolio' ); ?>"
                 loading="<?php echo ( 'masonry' === $layout ) ? 'eager' : 'lazy'; ?>"
                 style="width:100%;height:auto;display:block;border-radius:6px;<?php echo esc_attr( $img_extra_style ); ?>">
        </a>
        <!-- No thumbnail credit output; all credits handled in lightbox -->
    </div>
    <?php
}

/**
 * Frontend HTML
 *
 * @param string|null $forced_platform Optional: erzwingt eine bestimmte Plattform (adobe|unsplash|pixabay).
 * @param array $override Optional: Per-Shortcode-Overrides für Einstellungen.
 */
function lsmsp_render_frontend( $forced_platform = null, $override = array() ) {
    $opts = get_option( 'ls_sp_settings', array() );
    $opts = wp_parse_args( $opts, lsmsp_defaults() );

    // Per-Shortcode-Overrides anwenden (optional)
    if ( ! empty( $override ) && is_array( $override ) ) {
        if ( isset( $override['cols'] ) ) {
            $opts['cols'] = max( 1, intval( $override['cols'] ) );
        }
        if ( isset( $override['gap'] ) && '' !== $override['gap'] ) {
            $opts['gap'] = $override['gap'];
        }
        if ( isset( $override['layout'] ) && in_array( $override['layout'], array( 'grid', 'masonry' ), true ) ) {
            $opts['layout'] = $override['layout'];
        }
        if ( isset( $override['initial_count'] ) ) {
            $opts['initial_count'] = max( 1, intval( $override['initial_count'] ) );
        }
        if ( isset( $override['backlink_color'] ) && '' !== $override['backlink_color'] ) {
            $opts['backlink_color'] = $override['backlink_color'];
        }
        if ( isset( $override['lang'] ) && in_array( $override['lang'], array( 'de', 'en' ), true ) ) {
            $opts['lang'] = $override['lang'];
        }
        if ( isset( $override['ratio'] ) && '' !== $override['ratio'] ) {
            $allowed_ratios = array( 'auto', '1:1', '3:2', '4:3', '16:9' );
            if ( in_array( $override['ratio'], $allowed_ratios, true ) ) {
                $opts['ratio'] = $override['ratio'];
            }
        }
    }

    if ( in_array( $forced_platform, array( 'adobe', 'unsplash', 'pixabay' ), true ) ) {
        $platform = $forced_platform;
    } else {
        $platform = ! empty( $opts['platform'] ) ? $opts['platform'] : 'adobe';
    }

    $images = lsmsp_get_images( $platform );

    $initial = max( 1, intval( $opts['initial_count'] ) );
    $cols    = max( 1, intval( $opts['cols'] ) );
    $gap     = $opts['gap'] ? $opts['gap'] : '12px';
    $layout  = ! empty( $opts['layout'] ) ? $opts['layout'] : 'grid';

    // Texte je Sprache
    $text_more   = ( 'en' === $opts['lang'] ) ? 'Load more images' : 'Weitere Bilder laden';
    $text_credit = 'Lake Stylez – Mediendesign';

    // Breite immer automatisch kalkulieren
    $item_width = 'calc((100% - (' . ( $cols - 1 ) . ' * ' . $gap . ')) / ' . $cols . ')';

    ?>
    <div class="ls-sp-container" style="width:100%;">
        <div class="ls-sp-grid"
             data-limit="<?php echo esc_attr( $initial ); ?>"
             data-cols="<?php echo esc_attr( $cols ); ?>"
             data-gap="<?php echo esc_attr( $gap ); ?>"
             data-lightbox="1"
             data-layout="<?php echo esc_attr( $layout ); ?>"
             data-platform="<?php echo esc_attr( $platform ); ?>"
             data-ratio="<?php echo esc_attr( isset( $opts['ratio'] ) ? $opts['ratio'] : 'auto' ); ?>"
             style="display:flex;flex-wrap:wrap;gap:<?php echo esc_attr( $gap ); ?>;width:100%;">
            <?php
            $i = 0;
            foreach ( $images as $img ) {
                $i++;
                if ( $i > $initial ) {
                    break;
                }
                lsmsp_render_item( $img, $opts, $platform, $item_width, false );
            }
            ?>
        </div>

        <?php
        // Default button style (free und Basis für Pro).
        $btn_style = 'display:inline-block;padding:6px 18px;border:1px solid #ccc;background:#fff;border-radius:3px;cursor:pointer;';

        if ( lsmsp_is_pro_active() ) {
            $btn_bg     = ! empty( $opts['button_bg'] ) ? $opts['button_bg'] : '#ffffff';
            $btn_text   = ! empty( $opts['button_text_color'] ) ? $opts['button_text_color'] : '#000000';
            $btn_border = ! empty( $opts['button_border_color'] ) ? $opts['button_border_color'] : '#cccccc';
            $btn_radius = isset( $opts['button_border_radius'] ) ? max( 0, intval( $opts['button_border_radius'] ) ) : 3;

            $btn_style = 'display:inline-block;padding:6px 18px;border:1px solid ' . $btn_border . ';background:' . $btn_bg . ';border-radius:' . $btn_radius . 'px;cursor:pointer;color:' . $btn_text . ';';
        }
        ?>
        <div class="ls-sp-footer" style="text-align:center;margin-top:24px;">
            <?php if ( count( $images ) > $initial ) : ?>
                <button class="ls-sp-more"
                        style="<?php echo esc_attr( $btn_style ); ?>">
                    <?php echo esc_html( $text_more ); ?>
                </button>
            <?php endif; ?>
        </div>

        <?php if ( ! lsmsp_is_pro_active() ) : ?>
        <div class="ls-sp-credit" style="text-align:center;margin-top:10px;">
            <a href="<?php echo esc_url( 'https://lakestylez.com' ); ?>" target="_blank" rel="noopener"
               style="color:<?php echo esc_attr( $opts['backlink_color'] ); ?> !important;font-size:12px;text-decoration:none;">
                &copy; <?php echo esc_html( gmdate( 'Y' ) ); ?> <?php echo esc_html( $text_credit ); ?>
            </a>
        </div>
        <?php endif; ?>
    </div>
    <?php
}

/**
 * Register frontend script.
 */
function lsmsp_register_frontend_script() {
    $version = '1.0.1';

    wp_register_script(
        'ls-sp-frontend',
        plugins_url( 'assets/js/frontend.js', __FILE__ ),
        array(),
        $version,
        true
    );
}
add_action( 'init', 'lsmsp_register_frontend_script' );

/**
 * Enqueue frontend script and pass config to JS.
 */
function lsmsp_enqueue_frontend_script() {
    if ( is_admin() ) {
        return;
    }

    // Only load the frontend script on pages that actually use one of the LS Stock Portfolio shortcodes.
    $has_shortcode = false;

    if ( is_singular() ) {
        global $post;

        if ( $post instanceof WP_Post ) {
            $content = $post->post_content;

            if (
                has_shortcode( $content, 'lsmsp_stock_portfolio' ) ||
                has_shortcode( $content, 'lsmsp_stock_portfolio_adobe' ) ||
                has_shortcode( $content, 'lsmsp_stock_portfolio_unsplash' ) ||
                has_shortcode( $content, 'lsmsp_stock_portfolio_pixabay' ) ||
                has_shortcode( $content, 'lsmsp_stock_portfolio_all' ) ||
                has_shortcode( $content, 'lsmsp_stock_portfolio_mix' )
            ) {
                $has_shortcode = true;
            }
        }
    }

    if ( ! $has_shortcode ) {
        return;
    }

    $opts = get_option( 'ls_sp_settings', array() );
    $opts = wp_parse_args( $opts, lsmsp_defaults() );
    $lang = ( isset( $opts['lang'] ) && 'en' === $opts['lang'] ) ? 'en' : 'de';

    $more    = ( 'en' === $lang ) ? 'Load more images' : 'Weitere Bilder laden';
    $loading = ( 'en' === $lang ) ? 'Loading…' : 'Lade …';
    $nomore  = ( 'en' === $lang ) ? 'No more images' : 'Keine weiteren Bilder';
    $error   = ( 'en' === $lang ) ? 'Error loading images' : 'Fehler beim Laden';

    // Slideshow interval: Pro can customize, free uses 4 seconds.
    $interval_seconds = isset( $opts['slideshow_interval'] ) ? max( 1, intval( $opts['slideshow_interval'] ) ) : 4;
    if ( ! lsmsp_is_pro_active() ) {
        $interval_seconds = 4;
    }
    $interval_ms = $interval_seconds * 1000;

    // Lightbox theme and animation: Pro can customize, free uses defaults.
    $allowed_themes = array( 'default', 'carousel', 'filmstrip', 'fullscreen' );
    $theme_option   = isset( $opts['lightbox_theme'] ) ? $opts['lightbox_theme'] : 'default';
    $theme          = in_array( $theme_option, $allowed_themes, true ) ? $theme_option : 'default';

    $allowed_anims  = array( 'default', 'fade', 'slide' );
    $anim_option    = isset( $opts['lightbox_animation'] ) ? $opts['lightbox_animation'] : 'default';
    $animation      = in_array( $anim_option, $allowed_anims, true ) ? $anim_option : 'default';

    if ( ! lsmsp_is_pro_active() ) {
        $theme     = 'default';
        $animation = 'default';
    }
    
    $config = array(
        'ajaxUrl'                    => admin_url( 'admin-ajax.php' ),
        'nonce'                      => wp_create_nonce( 'ls_sp_load_more' ),
        'slideshowInterval'          => $interval_ms,
        'isPro'                      => lsmsp_is_pro_active(),
        'lightboxTheme'              => $theme,
        'lightboxAnimation'          => $animation,
        'lightboxAnimationDuration'  => isset( $opts['lightbox_animation_duration'] ) ? (int) $opts['lightbox_animation_duration'] : 600,
        'i18n'                       => array(
            'more'    => $more,
            'loading' => $loading,
            'noMore'  => $nomore,
            'error'   => $error,
        ),
    );

    // Fallback: ensure window.lsSpConfig is always defined, even if localization is altered by other plugins/themes.
    wp_add_inline_script(
        'ls-sp-frontend',
        'window.lsSpConfig = window.lsSpConfig || ' . wp_json_encode( $config ) . ';',
        'before'
    );

    wp_enqueue_script( 'ls-sp-frontend' );
    wp_localize_script( 'ls-sp-frontend', 'lsSpConfig', $config );
}
add_action( 'wp_enqueue_scripts', 'lsmsp_enqueue_frontend_script' );

/**
 * AJAX: weitere Bilder laden
 */
function lsmsp_ajax_load_more() {
    check_ajax_referer( 'ls_sp_load_more', 'nonce' );

    $offset = isset( $_POST['offset'] ) ? intval( wp_unslash( $_POST['offset'] ) ) : 0;
    $limit  = isset( $_POST['limit'] ) ? intval( wp_unslash( $_POST['limit'] ) ) : 0;

    if ( $limit < 1 ) {
        $limit = 8;
    }

    $opts = get_option( 'ls_sp_settings', array() );
    $opts = wp_parse_args( $opts, lsmsp_defaults() );

    // Optional: ratio override (from shortcode) für nachgeladene Bilder übernehmen.
    $ratio = isset( $_POST['ratio'] ) ? sanitize_text_field( wp_unslash( $_POST['ratio'] ) ) : '';
    if ( '' !== $ratio ) {
        $allowed_ratios = array( 'auto', '1:1', '3:2', '4:3', '16:9' );
        if ( in_array( $ratio, $allowed_ratios, true ) ) {
            $opts['ratio'] = $ratio;
        }
    }

    $requested_platform = isset( $_POST['platform'] )
        ? sanitize_text_field( wp_unslash( $_POST['platform'] ) )
        : '';

    if ( in_array( $requested_platform, array( 'adobe', 'unsplash', 'pixabay' ), true ) ) {
        $platform = $requested_platform;
    } else {
        $platform = ! empty( $opts['platform'] ) ? $opts['platform'] : 'adobe';
    }

    $all_images = lsmsp_get_images( $platform );
    $total      = is_array( $all_images ) ? count( $all_images ) : 0;

    if ( $total <= $offset ) {
        wp_send_json_success(
            array(
                'html'     => '',
                'has_more' => false,
            )
        );
    }

    $slice = array_slice( $all_images, $offset, $limit );

    $cols   = max( 1, intval( $opts['cols'] ) );
    $gap    = $opts['gap'] ? $opts['gap'] : '12px';
    $width  = 'calc((100% - (' . ( $cols - 1 ) . ' * ' . $gap . ')) / ' . $cols . ')';

    ob_start();
    if ( is_array( $slice ) ) {
        foreach ( $slice as $img ) {
            lsmsp_render_item( $img, $opts, $platform, $width, false );
        }
    }
    $html = ob_get_clean();

    $has_more = ( $offset + $limit ) < $total;

    wp_send_json_success(
        array(
            'html'     => $html,
            'has_more' => $has_more,
        )
    );
}
add_action( 'wp_ajax_ls_sp_load_more', 'lsmsp_ajax_load_more' );
add_action( 'wp_ajax_nopriv_ls_sp_load_more', 'lsmsp_ajax_load_more' );













