Plugin Directory

Changeset 3435881


Ignore:
Timestamp:
01/09/2026 12:07:44 PM (3 months ago)
Author:
artilab
Message:

1.5.0

Location:
picture-tag/trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • picture-tag/trunk/includes/cache.php

    r3288228 r3435881  
    122122  );
    123123 
    124   wp_redirect($redirect_url);
     124  wp_safe_redirect($redirect_url);
    125125  exit;
    126126}
    127127add_action( 'admin_post_clear_picture_cache', 'arti_handle_clear_picture_cache' );
    128128
     129/**
     130 * Clear picture cache for a specific attachment.
     131 *
     132 * @param int $attachment_id The attachment ID.
     133 */
     134function arti_clear_single_attachment_cache( $attachment_id ) {
     135    // Clear the cache of transient keys first
     136    wp_cache_delete( 'arti_picture_transient_keys_' . $attachment_id );
     137   
     138    // Get all transient keys for this specific attachment
     139    $transient_keys = arti_get_picture_transient_keys( $attachment_id );
     140   
     141    // Delete each transient
     142    if ( ! empty( $transient_keys ) ) {
     143        foreach ( $transient_keys as $key ) {
     144            $transient_name = str_replace( '_transient_', '', $key );
     145            delete_transient( $transient_name );
     146        }
     147    }
     148   
     149    // Clear the file exists cache
     150    if ( function_exists( 'arti_clear_file_exists_cache' ) ) {
     151        arti_clear_file_exists_cache();
     152    }
     153}
     154
    129155// Add hooks for clearing cache when media is updated
    130 add_action('edit_attachment', 'arti_clear_picture_cache');
    131 add_action('add_attachment', 'arti_clear_picture_cache');
    132 add_action('delete_attachment', 'arti_clear_picture_cache');
     156add_action( 'edit_attachment', 'arti_clear_single_attachment_cache' );
     157add_action( 'delete_attachment', 'arti_clear_single_attachment_cache' );
     158
     159// Note: We intentionally don't hook into 'add_attachment' to avoid conflicts
     160// during the upload process. New attachments don't have cached data anyway.
  • picture-tag/trunk/includes/helpers.php

    r3248106 r3435881  
    22if ( ! defined( 'ABSPATH' ) ) {
    33    exit; // Exit if accessed directly
     4}
     5
     6/**
     7 * Check if we're in a context where the plugin should be active.
     8 * Prevents interference with media uploads and other admin operations.
     9 *
     10 * @return bool True if the plugin should process images, false otherwise.
     11 */
     12function arti_should_process_images() {
     13    // Don't process during AJAX media uploads
     14    if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
     15        // Check if it's a media upload or image editing operation
     16        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is context detection, not form processing
     17        $action = isset( $_REQUEST['action'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ) : '';
     18        $skip_actions = array(
     19            'upload-attachment',
     20            'image-editor',
     21            'imgedit-preview',
     22            'edit-attachment',
     23            'save-attachment',
     24            'save-attachment-compat',
     25            'send-attachment-to-editor',
     26            'query-attachments',
     27            'get-attachment',
     28        );
     29        if ( in_array( $action, $skip_actions, true ) ) {
     30            return false;
     31        }
     32    }
     33   
     34    // Don't process during REST API media operations
     35    if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
     36        $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
     37        if ( strpos( $request_uri, '/wp/v2/media' ) !== false ) {
     38            return false;
     39        }
     40    }
     41   
     42    // Allow filtering for edge cases
     43    return apply_filters( 'arti_should_process_images', true );
    444}
    545
     
    2969
    3070/**
    31  * Global cache for storing file check results
    32  */
     71 * Get the file exists cache.
     72 * Uses static variable instead of global for better encapsulation.
     73 *
     74 * @param string|null $key Cache key to retrieve, or null to get all.
     75 * @param mixed $value Value to set, or null to get.
     76 * @param bool $clear Whether to clear the cache.
     77 * @return mixed Cached value, all cache, or null.
     78 */
     79function arti_file_exists_cache( $key = null, $value = null, $clear = false ) {
     80    static $cache = array();
     81   
     82    if ( $clear ) {
     83        $cache = array();
     84        return null;
     85    }
     86   
     87    if ( $key === null ) {
     88        return $cache;
     89    }
     90   
     91    if ( $value !== null ) {
     92        $cache[ $key ] = $value;
     93        return $value;
     94    }
     95   
     96    return isset( $cache[ $key ] ) ? $cache[ $key ] : null;
     97}
     98
     99// Backward compatibility: maintain global variable for existing code
    33100global $arti_file_exists_cache;
    34 if (!isset($arti_file_exists_cache)) {
    35     $arti_file_exists_cache = [];
     101if ( ! isset( $arti_file_exists_cache ) ) {
     102    $arti_file_exists_cache = array();
    36103}
    37104
     
    43110 * @return bool True if file exists, false if not
    44111 */
    45 function arti_check_if_file_exists($url, $force_check = false) {
     112function arti_check_if_file_exists( $url, $force_check = false ) {
    46113    global $arti_file_exists_cache;
    47114   
    48     // Return cached result if available and not forcing a check
    49     if (!$force_check && isset($arti_file_exists_cache[$url])) {
    50         return $arti_file_exists_cache[$url];
     115    // Return cached result from static cache first (faster)
     116    $cached = arti_file_exists_cache( $url );
     117    if ( ! $force_check && $cached !== null ) {
     118        return $cached;
     119    }
     120   
     121    // Backward compatibility: check global cache
     122    if ( ! $force_check && isset( $arti_file_exists_cache[ $url ] ) ) {
     123        return $arti_file_exists_cache[ $url ];
    51124    }
    52125   
     
    58131    // Convert URL to local path
    59132    $file_path = str_replace(
    60         [site_url(), $base_url],
    61         [ABSPATH, $base_dir],
     133        array( site_url(), $base_url ),
     134        array( ABSPATH, $base_dir ),
    62135        $url
    63136    );
    64137   
    65138    // Use quick check for local file
    66     $exists = file_exists($file_path);
    67    
    68     // Store result in cache
    69     $arti_file_exists_cache[$url] = $exists;
     139    $exists = file_exists( $file_path );
     140   
     141    // Store result in both caches
     142    arti_file_exists_cache( $url, $exists );
     143    $arti_file_exists_cache[ $url ] = $exists;
    70144   
    71145    return $exists;
     
    78152 * @return array Array with results where keys are URLs and values are boolean results
    79153 */
    80 function arti_batch_check_files_exist($urls) {
     154function arti_batch_check_files_exist( $urls ) {
    81155    global $arti_file_exists_cache;
    82156   
    83     $uncached_urls = [];
    84     $results = [];
    85    
    86     // First check cache
    87     foreach ($urls as $url) {
    88         if (isset($arti_file_exists_cache[$url])) {
    89             $results[$url] = $arti_file_exists_cache[$url];
     157    $uncached_urls = array();
     158    $results = array();
     159   
     160    // First check static cache (faster)
     161    foreach ( $urls as $url ) {
     162        $cached = arti_file_exists_cache( $url );
     163        if ( $cached !== null ) {
     164            $results[ $url ] = $cached;
     165        } elseif ( isset( $arti_file_exists_cache[ $url ] ) ) {
     166            // Backward compatibility: check global cache
     167            $results[ $url ] = $arti_file_exists_cache[ $url ];
    90168        } else {
    91169            $uncached_urls[] = $url;
     
    93171    }
    94172   
    95     if (empty($uncached_urls)) {
     173    if ( empty( $uncached_urls ) ) {
    96174        return $results;
    97175    }
     
    104182   
    105183    // Check local files
    106     foreach ($uncached_urls as $url) {
     184    foreach ( $uncached_urls as $url ) {
    107185        $file_path = str_replace(
    108             [$site_url, $base_url],
    109             [ABSPATH, $base_dir],
     186            array( $site_url, $base_url ),
     187            array( ABSPATH, $base_dir ),
    110188            $url
    111189        );
    112         $exists = file_exists($file_path);
    113         $results[$url] = $exists;
    114         $arti_file_exists_cache[$url] = $exists;
     190        $exists = file_exists( $file_path );
     191        $results[ $url ] = $exists;
     192       
     193        // Store in both caches
     194        arti_file_exists_cache( $url, $exists );
     195        $arti_file_exists_cache[ $url ] = $exists;
    115196    }
    116197   
     
    123204function arti_clear_file_exists_cache() {
    124205    global $arti_file_exists_cache;
    125     $arti_file_exists_cache = [];
    126 }
     206   
     207    // Clear static cache
     208    arti_file_exists_cache( null, null, true );
     209   
     210    // Clear global cache for backward compatibility
     211    $arti_file_exists_cache = array();
     212}
  • picture-tag/trunk/includes/template-functions.php

    r3286124 r3435881  
    66/**
    77 * Generate a responsive <picture> tag with support for WebP and AVIF formats.
     8 *
     9 * @param int   $image_id Attachment ID.
     10 * @param array $sizes    Array of sizes with scale keys ('1x', '2x').
     11 * @param array $attr     Additional attributes for the img tag.
     12 * @return string HTML output for the picture tag.
    813 */
    914function arti_generate_picture_tag( $image_id, $sizes, $attr ) {
    10     static $transient_cache = [];
     15    static $transient_cache = array();
     16   
     17    // Skip processing during media uploads to prevent conflicts
     18    if ( function_exists( 'arti_should_process_images' ) && ! arti_should_process_images() ) {
     19        return wp_get_attachment_image( $image_id, isset( $sizes['1x'] ) ? $sizes['1x'] : 'large', false, $attr );
     20    }
    1121   
    1222    // Generate a unique key for caching
    13     $cache_key = 'arti_picture_' . $image_id . '_' . md5( serialize( $sizes ) . serialize( $attr ) );
     23    $cache_key = 'arti_picture_' . $image_id . '_' . md5( wp_json_encode( $sizes ) . wp_json_encode( $attr ) );
    1424   
    1525    // Local cache (within one request)
     
    4454    }
    4555   
    46     $webp_urls      = [];
    47     $avif_urls      = [];
    48     $original_srcset = [];
    49     $webp_srcset    = [];
    50     $avif_srcset    = [];
    51     $scale_mapping  = [];
     56    $webp_urls       = array();
     57    $avif_urls       = array();
     58    $original_srcset = array();
     59    $webp_srcset     = array();
     60    $avif_srcset     = array();
     61    $scale_mapping   = array();
     62   
     63    // Get the original image MIME type for proper fallback
     64    $original_mime = get_post_mime_type( $image_id );
     65    if ( ! $original_mime ) {
     66        $original_mime = 'image/jpeg'; // Fallback to JPEG
     67    }
    5268   
    5369    // Collecting URLs for verification
     
    104120  <source srcset="<?php echo esc_attr( implode( ', ', $webp_srcset ) ); ?>" type="image/webp" />
    105121  <?php endif; ?>
    106   <source srcset="<?php echo esc_attr( implode( ', ', $original_srcset ) ); ?>" type="image/jpeg" />
     122  <source srcset="<?php echo esc_attr( implode( ', ', $original_srcset ) ); ?>" type="<?php echo esc_attr( $original_mime ); ?>" />
    107123  <?php echo wp_get_attachment_image( $image_id, $sizes['1x'], false, arti_render_custom_attributes( $attr ) ); ?>
    108124</picture>
     
    110126    $html = ob_get_clean();
    111127   
    112     // We store the result in the cache for 2 week
    113     set_transient( $cache_key, $html, 2 * WEEK_IN_SECONDS );
     128    // Cache duration - filterable, default 2 weeks
     129    $cache_duration = apply_filters( 'arti_picture_cache_duration', 2 * WEEK_IN_SECONDS );
     130   
     131    // We store the result in the cache
     132    set_transient( $cache_key, $html, $cache_duration );
    114133    $transient_cache[ $cache_key ] = $html;
    115134   
  • picture-tag/trunk/languages/picture-tag-uk.l10n.php

    r3286124 r3435881  
    11<?php
     2if ( ! defined( 'ABSPATH' ) ) {
     3    exit;
     4}
    25return ['project-id-version'=>'picture-tag 1.1','po-revision-date'=>'2025-03-01 19:05+0000','last-translator'=>'','language-team'=>'Українська','language'=>'uk','mime-version'=>'1.0','content-type'=>'text/plain; charset=UTF-8','content-transfer-encoding'=>'8bit','x-generator'=>'Loco https://localise.biz/','x-poedit-keywordslist'=>'__;_e;_x;_n;_ex','x-poedit-basepath'=>'../','x-poedit-searchpath-0'=>'.','plural-forms'=>'nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10 >= 2 && n%10<=4 &&(n%100<10||n%100 >= 20)? 1 : 2);','pot-creation-date'=>'2024-12-18 16:10+0000','report-msgid-bugs-to'=>'','x-loco-version'=>'2.6.14; wp-6.7.1','messages'=>['AVIF Path'=>'Шлях до AVIF','Clear Image Cache'=>'Очистити кеш зображень','Image cache cleared!'=>'Кеш зображень очищено!','Picture Tag Settings'=>'Налаштування Picture Tag','Picture Tag with Custom Path Settings'=>'Picture Tag зі спеціальними налаштуваннями шляху','Settings'=>'Налаштування','WebP Path'=>'Шлях до WebP ']];
  • picture-tag/trunk/picture-tag.php

    r3288247 r3435881  
    33 * Plugin Name: Picture Tag
    44 * Description: Picture Tag with Custom Path Settings
    5  * Version: 1.4.2
     5 * Version: 1.5.0
    66 * Author: Artilab
    77 * Author URI: https://artilab.pro/
     
    1818define( 'ARTI_PICTURE_TAG_PLUGIN', __FILE__ );
    1919define( 'ARTI_PICTURE_TAG_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    20 define( 'ARTI_PICTURE_TAG_PLUGIN_VERSION', '1.4.2' );
     20define( 'ARTI_PICTURE_TAG_PLUGIN_VERSION', '1.5.0' );
    2121
    2222
     
    3030// Initialize plugin
    3131function arti_picture_tag_init() {
    32     add_action( 'admin_menu', 'arti_picture_tag_add_settings_page' );
    33     add_action( 'admin_init', 'arti_picture_tag_register_settings' );
     32    // admin_menu and admin_init hooks are already registered in settings.php
     33    // This function is kept for backward compatibility and future initialization needs
     34    do_action( 'arti_picture_tag_loaded' );
    3435}
    3536add_action( 'plugins_loaded', 'arti_picture_tag_init' );
    36 
    37 
    38 
    39 function arti_load_textdomain() {
    40     load_plugin_textdomain('picture-tag', false, dirname( plugin_basename( ARTI_PICTURE_TAG_PLUGIN ) ) . '/languages/');
    41 }
    42 add_action('init', 'arti_load_textdomain', 5);
  • picture-tag/trunk/readme.txt

    r3288236 r3435881  
    33Tags:              responsive images, picture tag
    44Requires at least: 5.0
    5 Tested up to:      6.8
     5Tested up to:      6.9
    66Requires PHP:      7.4
    7 Stable tag:        1.4.2
     7Stable tag:        1.5.0
    88License:           GPL-2.0-or-later
    99License URI:       https://www.gnu.org/licenses/gpl-2.0.html
Note: See TracChangeset for help on using the changeset viewer.