Plugin Directory

Changeset 3465508


Ignore:
Timestamp:
02/20/2026 05:42:16 AM (6 weeks ago)
Author:
mantrabrain
Message:

Update to version 2.0.2 from GitHub

Location:
ultimate-watermark
Files:
14 edited
1 copied

Legend:

Unmodified
Added
Removed
  • ultimate-watermark/tags/2.0.2/readme.txt

    r3465501 r3465508  
    55Requires at least: 5.0
    66Tested up to: 6.9
    7 Stable tag: 2.0.1
     7Stable tag: 2.0.2
    88License: GPLv3
    99License URI: http://www.gnu.org/licenses/gpl-3.0.html
     
    362362== Changelog ==
    363363
    364 = 2.0.1 - 2026/02/20  =
     364= 2.0.2- 2026/02/20  =
    365365* **Fixed** - Duplication issue fixed
     366* **Fixed** - GD library issue fixed
    366367
    367368= 2.0 - 2026/02/19 =
     
    428429= 1.0.0 - 2019/02/16 =
    429430* **Initial Release** - Core watermarking features
    430 
    431 == Upgrade Notice ==
    432 
    433 = 2.0.2 =
    434 Major update with complete rewrite! Automatic migration from v1.x. Free version now limited to 1 watermark. Backup your site before updating.
    435 
    436 = 1.1.1 =
    437 Important bug fixes and compatibility improvements. Update recommended.
    438 
    439 = 1.0.11 =
    440 WordPress 6.4 compatibility verified. Performance improvements included.
  • ultimate-watermark/tags/2.0.2/src/Admin/Pages/WatermarkPage.php

    r3465062 r3465508  
    591591        $watermark_rules = $watermark['watermark_rules'] ?? [];
    592592       
    593         // If no unified rules, fall back to legacy display
     593        // If no unified rules, show "No rules"
    594594        if (empty($watermark_rules) || !is_array($watermark_rules)) {
    595             return $this->formatLegacyRules($watermark);
     595            return '<span class="rule-item no-rules">' . __('No rules', 'ultimate-watermark') . '</span>';
    596596        }
    597597       
     
    605605        }
    606606       
    607         // If no conditions defined, show as "No restrictions"
     607        // If no conditions defined, show as "No rules"
    608608        if (!$has_conditions) {
    609             return '<span class="rule-item no-restrictions">' . __('No restrictions', 'ultimate-watermark') . '</span>';
     609            return '<span class="rule-item no-rules">' . __('No rules', 'ultimate-watermark') . '</span>';
    610610        }
    611611       
     
    649649       
    650650        if (empty($rule_summaries)) {
    651             return '<span class="rule-item no-restrictions">' . __('No restrictions', 'ultimate-watermark') . '</span>';
     651            return '<span class="rule-item no-rules">' . __('No rules', 'ultimate-watermark') . '</span>';
    652652        }
    653653       
  • ultimate-watermark/tags/2.0.2/src/Integration/RestApiIntegration.php

    r3465062 r3465508  
    717717                $rules = $watermark['watermark_rules'] ?? [];
    718718                if (empty($rules) || !is_array($rules)) {
    719                     return true; // No unified rules = no extra restriction
     719                    return false; // No unified rules = don't apply watermark
    720720                }
    721721                // Check if any rule has conditions
     
    728728                }
    729729                if (!$has_conditions) {
    730                     return true; // No conditions defined = no restriction
     730                    return false; // No conditions defined = don't apply watermark
    731731                }
    732732                $eval_context = \MantraBrain\UltimateWatermark\Utils\RulesEvaluator::buildContext(
  • ultimate-watermark/tags/2.0.2/src/Utils/RulesEvaluator.php

    r3465062 r3465508  
    1919     * If ANY rule passes (rules are OR'd at the top level), the watermark applies.
    2020     * Within a rule, conditions are combined using the rule's logic_operator (AND/OR).
    21      * If no rules have conditions, watermark applies (no restrictions).
     21     * If no rules are set, watermark does NOT apply (must have rules to apply).
    2222     *
    2323     * @param array $rules      The watermark_rules array (keyed by rule_id)
     
    2828    {
    2929        if (empty($rules)) {
    30             return true; // No rules = no restrictions
    31         }
    32 
    33         // Check if ALL rules have zero conditions — treat as unrestricted
     30            return false; // No rules = don't apply watermark
     31        }
     32
     33        // Check if ALL rules have zero conditions — treat as no rules set
    3434        $has_any_conditions = false;
    3535        foreach ($rules as $rule) {
     
    4141
    4242        if (!$has_any_conditions) {
    43             return true; // All rules have empty conditions = no restrictions
     43            return false; // All rules have empty conditions = no rules set, don't apply
    4444        }
    4545
  • ultimate-watermark/tags/2.0.2/src/Utils/WatermarkHelper.php

    r3465062 r3465508  
    724724                }
    725725               
    726                 // Check unified watermark_rules conditions first (if any exist with conditions)
     726                // Check unified watermark_rules - MUST have rules to apply
    727727                $rules = $watermark['watermark_rules'] ?? [];
    728                 if (!empty($rules) && is_array($rules)) {
    729                     // Check if any rule actually has conditions defined
    730                     $has_conditions = false;
    731                     foreach ($rules as $rule) {
    732                         if (!empty($rule['conditions']) && is_array($rule['conditions'])) {
    733                             $has_conditions = true;
    734                             break;
     728                if (empty($rules) || !is_array($rules)) {
     729                    return false; // No rules = don't apply watermark
     730                }
     731               
     732                // Check if any rule actually has conditions defined
     733                $has_conditions = false;
     734                foreach ($rules as $rule) {
     735                    if (!empty($rule['conditions']) && is_array($rule['conditions'])) {
     736                        $has_conditions = true;
     737                        break;
     738                    }
     739                }
     740               
     741                if (!$has_conditions) {
     742                    return false; // No conditions defined = don't apply watermark
     743                }
     744               
     745                // Build context for evaluation
     746                $eval_context = [
     747                    'image_size' => $image_size,
     748                    'post_type' => '',
     749                ];
     750               
     751                // Resolve post type from context
     752                if ($post_id) {
     753                    $parent_post_id = self::getParentPostId($post_id);
     754                    if ($parent_post_id > 0) {
     755                        $parent = get_post($parent_post_id);
     756                        if ($parent) {
     757                            $eval_context['post_type'] = $parent->post_type;
     758                            $categories = wp_get_post_categories($parent_post_id, ['fields' => 'slugs']);
     759                            if (!empty($categories) && !is_wp_error($categories)) {
     760                                $eval_context['post_category'] = $categories[0];
     761                            }
     762
     763                            // WooCommerce product taxonomies
     764                            if ($parent->post_type === 'product') {
     765                                $product_cats = wp_get_post_terms($parent_post_id, 'product_cat', ['fields' => 'slugs']);
     766                                if (!is_wp_error($product_cats) && !empty($product_cats)) {
     767                                    $eval_context['product_cat'] = $product_cats[0];
     768                                    $eval_context['product_cats'] = $product_cats;
     769                                }
     770                                $product_tags = wp_get_post_terms($parent_post_id, 'product_tag', ['fields' => 'slugs']);
     771                                if (!is_wp_error($product_tags) && !empty($product_tags)) {
     772                                    $eval_context['product_tag'] = $product_tags[0];
     773                                    $eval_context['product_tags'] = $product_tags;
     774                                }
     775                            }
    735776                        }
    736777                    }
    737778                   
    738                     if ($has_conditions) {
    739                         // Build context for evaluation
    740                         $eval_context = [
    741                             'image_size' => $image_size,
    742                             'post_type' => '',
    743                         ];
    744                        
    745                         // Resolve post type from context
    746                         if ($post_id) {
    747                             $parent_post_id = self::getParentPostId($post_id);
    748                             if ($parent_post_id > 0) {
    749                                 $parent = get_post($parent_post_id);
    750                                 if ($parent) {
    751                                     $eval_context['post_type'] = $parent->post_type;
    752                                     $categories = wp_get_post_categories($parent_post_id, ['fields' => 'slugs']);
    753                                     if (!empty($categories) && !is_wp_error($categories)) {
    754                                         $eval_context['post_category'] = $categories[0];
    755                                     }
    756 
    757                                     // WooCommerce product taxonomies
    758                                     if ($parent->post_type === 'product') {
    759                                         $product_cats = wp_get_post_terms($parent_post_id, 'product_cat', ['fields' => 'slugs']);
    760                                         if (!is_wp_error($product_cats) && !empty($product_cats)) {
    761                                             $eval_context['product_cat'] = $product_cats[0];
    762                                             $eval_context['product_cats'] = $product_cats;
    763                                         }
    764                                         $product_tags = wp_get_post_terms($parent_post_id, 'product_tag', ['fields' => 'slugs']);
    765                                         if (!is_wp_error($product_tags) && !empty($product_tags)) {
    766                                             $eval_context['product_tag'] = $product_tags[0];
    767                                             $eval_context['product_tags'] = $product_tags;
    768                                         }
    769                                     }
    770                                 }
    771                             }
    772                            
    773                             // File info from attachment
    774                             $file_path = get_attached_file($post_id);
    775                             if ($file_path && file_exists($file_path)) {
    776                                 $eval_context['file_path'] = $file_path;
    777                                 $eval_context['mime_type'] = wp_check_filetype($file_path)['type'] ?? '';
    778                                 $eval_context['file_size_kb'] = round(filesize($file_path) / 1024);
    779                             }
    780                         }
    781                        
    782                         // Evaluate unified rules
    783                         if (!RulesEvaluator::evaluate($rules, $eval_context)) {
    784                             return false;
    785                         }
    786                        
    787                         // Unified rules passed — skip legacy checks since rules cover everything
    788                         return true;
     779                    // File info from attachment
     780                    $file_path = get_attached_file($post_id);
     781                    if ($file_path && file_exists($file_path)) {
     782                        $eval_context['file_path'] = $file_path;
     783                        $eval_context['mime_type'] = wp_check_filetype($file_path)['type'] ?? '';
     784                        $eval_context['file_size_kb'] = round(filesize($file_path) / 1024);
    789785                    }
    790786                }
    791787               
    792                 // Fallback: legacy post type and image size checks
    793                 $post_type_check = self::shouldApplyWatermarkByPostType($watermark, $context, $post_id);
    794                 if (!$post_type_check) {
    795                     return false;
    796                 }
    797                
    798                 // Check image size rules
    799                 $size_check = self::shouldApplyWatermarkByImageSize($watermark, $image_size);
    800                 if (!$size_check) {
    801                     return false;
    802                 }
    803                
    804                 // Both checks passed
    805                 return true;
     788                // Evaluate unified rules
     789                return RulesEvaluator::evaluate($rules, $eval_context);
    806790            });
    807791
  • ultimate-watermark/tags/2.0.2/src/Watermark/Processors/GDWatermarkProcessor.php

    r3465062 r3465508  
    300300
    301301        // Get full size dimensions with fallback strategies
    302         $fullDimensions = $this->getFullSizeDimensions($watermarkData);
     302        $fullDimensions = $this->getFullSizeDimensions($watermarkData, $currentWidth, $currentHeight);
    303303       
    304304        // Calculate scaling ratio
     
    321321     * Get full size dimensions using multiple strategies
    322322     */
    323     private function getFullSizeDimensions(array $watermarkData): array
     323    private function getFullSizeDimensions(array $watermarkData, int $currentWidth, int $currentHeight): array
    324324    {
    325325        // Strategy 1: From watermark data
     
    333333        // Strategy 2: From source image path
    334334        $sourcePath = $watermarkData['_source_image_path'] ?? '';
    335         if ($sourcePath) {
     335        if ($sourcePath && file_exists($sourcePath)) {
    336336            $attachmentId = $this->getAttachmentIdFromPath($sourcePath);
    337337            if ($attachmentId) {
     
    344344
    345345        // Strategy 3: Use current image dimensions (fallback)
    346         throw new \RuntimeException('Unable to determine full size image dimensions');
     346        // This is safe for preview generation and when full size info is unavailable
     347        return ['width' => $currentWidth, 'height' => $currentHeight];
    347348    }
    348349
     
    550551
    551552    /**
    552      * Get attachment ID from file path
    553      */
    554     private function getAttachmentIdFromPath(string $filePath): int
    555     {
     553     * Get attachment ID from image file path
     554     * Handles both full size images and thumbnails/resized versions
     555     */
     556    private function getAttachmentIdFromPath(string $imagePath): ?int
     557    {
     558        if (empty($imagePath)) {
     559            return null;
     560        }
     561       
     562        // Normalize path
     563        $normalizedPath = wp_normalize_path($imagePath);
     564        $uploadDir = wp_upload_dir();
     565        $baseDir = wp_normalize_path($uploadDir['basedir']);
     566       
     567        // Get relative path from uploads directory
     568        if (strpos($normalizedPath, $baseDir) !== 0) {
     569            return null;
     570        }
     571       
     572        $relativePath = str_replace($baseDir . '/', '', $normalizedPath);
     573        $pathInfo = pathinfo($relativePath);
     574        $baseFilename = $pathInfo['filename'];
     575        $directory = $pathInfo['dirname'];
     576       
     577        // First, try exact match (for full size images)
    556578        global $wpdb;
    557        
    558         $fileName = basename($filePath);
    559579        $attachmentId = $wpdb->get_var($wpdb->prepare(
    560             "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_wp_attached_file' AND meta_value LIKE %s",
    561             '%' . $wpdb->esc_like($fileName)
     580            "SELECT post_id FROM {$wpdb->postmeta}
     581            WHERE meta_key = '_wp_attached_file'
     582            AND meta_value = %s
     583            LIMIT 1",
     584            $relativePath
    562585        ));
    563 
    564         return (int) $attachmentId;
     586       
     587        if ($attachmentId) {
     588            return (int) $attachmentId;
     589        }
     590       
     591        // If exact match fails, try to match by base filename and directory
     592        // This handles thumbnails and resized images (e.g., image-150x150.jpg -> image.jpg)
     593        // Remove size suffix (e.g., -150x150) from filename
     594        $baseFilenameClean = preg_replace('/-\d+x\d+$/', '', $baseFilename);
     595        $extension = isset($pathInfo['extension']) ? '.' . $pathInfo['extension'] : '';
     596       
     597        // Try to find attachment with matching base filename in same directory
     598        $possiblePath = $directory === '.' ? $baseFilenameClean . $extension : $directory . '/' . $baseFilenameClean . $extension;
     599       
     600        $attachmentId = $wpdb->get_var($wpdb->prepare(
     601            "SELECT post_id FROM {$wpdb->postmeta}
     602            WHERE meta_key = '_wp_attached_file'
     603            AND meta_value = %s
     604            LIMIT 1",
     605            $possiblePath
     606        ));
     607       
     608        if ($attachmentId) {
     609            return (int) $attachmentId;
     610        }
     611       
     612        // Last resort: search by base filename pattern in metadata
     613        $attachmentId = $wpdb->get_var($wpdb->prepare(
     614            "SELECT post_id FROM {$wpdb->postmeta} pm
     615            INNER JOIN {$wpdb->posts} p ON pm.post_id = p.ID
     616            WHERE pm.meta_key = '_wp_attached_file'
     617            AND pm.meta_value LIKE %s
     618            AND p.post_type = 'attachment'
     619            LIMIT 1",
     620            '%' . $wpdb->esc_like($baseFilenameClean) . '%'
     621        ));
     622       
     623        return $attachmentId ? (int) $attachmentId : null;
    565624    }
    566625
     
    773832        }
    774833    }
     834
     835    /**
     836     * Get supported image formats
     837     *
     838     * @return array Array of supported formats
     839     */
     840    public function getSupportedFormats(): array
     841    {
     842        return ['jpg', 'jpeg', 'png', 'gif', 'webp'];
     843    }
     844
     845    /**
     846     * Check if processor is available
     847     *
     848     * @return bool True if GD library is available
     849     */
     850    public function isAvailable(): bool
     851    {
     852        return extension_loaded('gd') && function_exists('gd_info');
     853    }
    775854}
  • ultimate-watermark/tags/2.0.2/ultimate-watermark.php

    r3465501 r3465508  
    44 * Plugin URI: https://mantrabrain.com/ultimate-watermark
    55 * Description: Advanced WordPress Image Watermarking Plugin
    6  * Version: 2.0.1
     6 * Version: 2.0.2
    77 * Author: MantraBrain
    88 * Author URI: https://mantrabrain.com
     
    1818 * @package UltimateWatermark
    1919 * @author MantraBrain
    20  * @version 2.0
     20 * @version 2.0.2
    2121 */
    2222
     
    3636
    3737// Define plugin constants
    38 define('ULTIMATE_WATERMARK_VERSION', '2.0.1');
     38define('ULTIMATE_WATERMARK_VERSION', '2.0.2');
    3939define('ULTIMATE_WATERMARK_FILE', __FILE__);
    4040define('ULTIMATE_WATERMARK_DIR', plugin_dir_path(__FILE__));
  • ultimate-watermark/trunk/readme.txt

    r3465501 r3465508  
    55Requires at least: 5.0
    66Tested up to: 6.9
    7 Stable tag: 2.0.1
     7Stable tag: 2.0.2
    88License: GPLv3
    99License URI: http://www.gnu.org/licenses/gpl-3.0.html
     
    362362== Changelog ==
    363363
    364 = 2.0.1 - 2026/02/20  =
     364= 2.0.2- 2026/02/20  =
    365365* **Fixed** - Duplication issue fixed
     366* **Fixed** - GD library issue fixed
    366367
    367368= 2.0 - 2026/02/19 =
     
    428429= 1.0.0 - 2019/02/16 =
    429430* **Initial Release** - Core watermarking features
    430 
    431 == Upgrade Notice ==
    432 
    433 = 2.0.2 =
    434 Major update with complete rewrite! Automatic migration from v1.x. Free version now limited to 1 watermark. Backup your site before updating.
    435 
    436 = 1.1.1 =
    437 Important bug fixes and compatibility improvements. Update recommended.
    438 
    439 = 1.0.11 =
    440 WordPress 6.4 compatibility verified. Performance improvements included.
  • ultimate-watermark/trunk/src/Admin/Pages/WatermarkPage.php

    r3465062 r3465508  
    591591        $watermark_rules = $watermark['watermark_rules'] ?? [];
    592592       
    593         // If no unified rules, fall back to legacy display
     593        // If no unified rules, show "No rules"
    594594        if (empty($watermark_rules) || !is_array($watermark_rules)) {
    595             return $this->formatLegacyRules($watermark);
     595            return '<span class="rule-item no-rules">' . __('No rules', 'ultimate-watermark') . '</span>';
    596596        }
    597597       
     
    605605        }
    606606       
    607         // If no conditions defined, show as "No restrictions"
     607        // If no conditions defined, show as "No rules"
    608608        if (!$has_conditions) {
    609             return '<span class="rule-item no-restrictions">' . __('No restrictions', 'ultimate-watermark') . '</span>';
     609            return '<span class="rule-item no-rules">' . __('No rules', 'ultimate-watermark') . '</span>';
    610610        }
    611611       
     
    649649       
    650650        if (empty($rule_summaries)) {
    651             return '<span class="rule-item no-restrictions">' . __('No restrictions', 'ultimate-watermark') . '</span>';
     651            return '<span class="rule-item no-rules">' . __('No rules', 'ultimate-watermark') . '</span>';
    652652        }
    653653       
  • ultimate-watermark/trunk/src/Integration/RestApiIntegration.php

    r3465062 r3465508  
    717717                $rules = $watermark['watermark_rules'] ?? [];
    718718                if (empty($rules) || !is_array($rules)) {
    719                     return true; // No unified rules = no extra restriction
     719                    return false; // No unified rules = don't apply watermark
    720720                }
    721721                // Check if any rule has conditions
     
    728728                }
    729729                if (!$has_conditions) {
    730                     return true; // No conditions defined = no restriction
     730                    return false; // No conditions defined = don't apply watermark
    731731                }
    732732                $eval_context = \MantraBrain\UltimateWatermark\Utils\RulesEvaluator::buildContext(
  • ultimate-watermark/trunk/src/Utils/RulesEvaluator.php

    r3465062 r3465508  
    1919     * If ANY rule passes (rules are OR'd at the top level), the watermark applies.
    2020     * Within a rule, conditions are combined using the rule's logic_operator (AND/OR).
    21      * If no rules have conditions, watermark applies (no restrictions).
     21     * If no rules are set, watermark does NOT apply (must have rules to apply).
    2222     *
    2323     * @param array $rules      The watermark_rules array (keyed by rule_id)
     
    2828    {
    2929        if (empty($rules)) {
    30             return true; // No rules = no restrictions
    31         }
    32 
    33         // Check if ALL rules have zero conditions — treat as unrestricted
     30            return false; // No rules = don't apply watermark
     31        }
     32
     33        // Check if ALL rules have zero conditions — treat as no rules set
    3434        $has_any_conditions = false;
    3535        foreach ($rules as $rule) {
     
    4141
    4242        if (!$has_any_conditions) {
    43             return true; // All rules have empty conditions = no restrictions
     43            return false; // All rules have empty conditions = no rules set, don't apply
    4444        }
    4545
  • ultimate-watermark/trunk/src/Utils/WatermarkHelper.php

    r3465062 r3465508  
    724724                }
    725725               
    726                 // Check unified watermark_rules conditions first (if any exist with conditions)
     726                // Check unified watermark_rules - MUST have rules to apply
    727727                $rules = $watermark['watermark_rules'] ?? [];
    728                 if (!empty($rules) && is_array($rules)) {
    729                     // Check if any rule actually has conditions defined
    730                     $has_conditions = false;
    731                     foreach ($rules as $rule) {
    732                         if (!empty($rule['conditions']) && is_array($rule['conditions'])) {
    733                             $has_conditions = true;
    734                             break;
     728                if (empty($rules) || !is_array($rules)) {
     729                    return false; // No rules = don't apply watermark
     730                }
     731               
     732                // Check if any rule actually has conditions defined
     733                $has_conditions = false;
     734                foreach ($rules as $rule) {
     735                    if (!empty($rule['conditions']) && is_array($rule['conditions'])) {
     736                        $has_conditions = true;
     737                        break;
     738                    }
     739                }
     740               
     741                if (!$has_conditions) {
     742                    return false; // No conditions defined = don't apply watermark
     743                }
     744               
     745                // Build context for evaluation
     746                $eval_context = [
     747                    'image_size' => $image_size,
     748                    'post_type' => '',
     749                ];
     750               
     751                // Resolve post type from context
     752                if ($post_id) {
     753                    $parent_post_id = self::getParentPostId($post_id);
     754                    if ($parent_post_id > 0) {
     755                        $parent = get_post($parent_post_id);
     756                        if ($parent) {
     757                            $eval_context['post_type'] = $parent->post_type;
     758                            $categories = wp_get_post_categories($parent_post_id, ['fields' => 'slugs']);
     759                            if (!empty($categories) && !is_wp_error($categories)) {
     760                                $eval_context['post_category'] = $categories[0];
     761                            }
     762
     763                            // WooCommerce product taxonomies
     764                            if ($parent->post_type === 'product') {
     765                                $product_cats = wp_get_post_terms($parent_post_id, 'product_cat', ['fields' => 'slugs']);
     766                                if (!is_wp_error($product_cats) && !empty($product_cats)) {
     767                                    $eval_context['product_cat'] = $product_cats[0];
     768                                    $eval_context['product_cats'] = $product_cats;
     769                                }
     770                                $product_tags = wp_get_post_terms($parent_post_id, 'product_tag', ['fields' => 'slugs']);
     771                                if (!is_wp_error($product_tags) && !empty($product_tags)) {
     772                                    $eval_context['product_tag'] = $product_tags[0];
     773                                    $eval_context['product_tags'] = $product_tags;
     774                                }
     775                            }
    735776                        }
    736777                    }
    737778                   
    738                     if ($has_conditions) {
    739                         // Build context for evaluation
    740                         $eval_context = [
    741                             'image_size' => $image_size,
    742                             'post_type' => '',
    743                         ];
    744                        
    745                         // Resolve post type from context
    746                         if ($post_id) {
    747                             $parent_post_id = self::getParentPostId($post_id);
    748                             if ($parent_post_id > 0) {
    749                                 $parent = get_post($parent_post_id);
    750                                 if ($parent) {
    751                                     $eval_context['post_type'] = $parent->post_type;
    752                                     $categories = wp_get_post_categories($parent_post_id, ['fields' => 'slugs']);
    753                                     if (!empty($categories) && !is_wp_error($categories)) {
    754                                         $eval_context['post_category'] = $categories[0];
    755                                     }
    756 
    757                                     // WooCommerce product taxonomies
    758                                     if ($parent->post_type === 'product') {
    759                                         $product_cats = wp_get_post_terms($parent_post_id, 'product_cat', ['fields' => 'slugs']);
    760                                         if (!is_wp_error($product_cats) && !empty($product_cats)) {
    761                                             $eval_context['product_cat'] = $product_cats[0];
    762                                             $eval_context['product_cats'] = $product_cats;
    763                                         }
    764                                         $product_tags = wp_get_post_terms($parent_post_id, 'product_tag', ['fields' => 'slugs']);
    765                                         if (!is_wp_error($product_tags) && !empty($product_tags)) {
    766                                             $eval_context['product_tag'] = $product_tags[0];
    767                                             $eval_context['product_tags'] = $product_tags;
    768                                         }
    769                                     }
    770                                 }
    771                             }
    772                            
    773                             // File info from attachment
    774                             $file_path = get_attached_file($post_id);
    775                             if ($file_path && file_exists($file_path)) {
    776                                 $eval_context['file_path'] = $file_path;
    777                                 $eval_context['mime_type'] = wp_check_filetype($file_path)['type'] ?? '';
    778                                 $eval_context['file_size_kb'] = round(filesize($file_path) / 1024);
    779                             }
    780                         }
    781                        
    782                         // Evaluate unified rules
    783                         if (!RulesEvaluator::evaluate($rules, $eval_context)) {
    784                             return false;
    785                         }
    786                        
    787                         // Unified rules passed — skip legacy checks since rules cover everything
    788                         return true;
     779                    // File info from attachment
     780                    $file_path = get_attached_file($post_id);
     781                    if ($file_path && file_exists($file_path)) {
     782                        $eval_context['file_path'] = $file_path;
     783                        $eval_context['mime_type'] = wp_check_filetype($file_path)['type'] ?? '';
     784                        $eval_context['file_size_kb'] = round(filesize($file_path) / 1024);
    789785                    }
    790786                }
    791787               
    792                 // Fallback: legacy post type and image size checks
    793                 $post_type_check = self::shouldApplyWatermarkByPostType($watermark, $context, $post_id);
    794                 if (!$post_type_check) {
    795                     return false;
    796                 }
    797                
    798                 // Check image size rules
    799                 $size_check = self::shouldApplyWatermarkByImageSize($watermark, $image_size);
    800                 if (!$size_check) {
    801                     return false;
    802                 }
    803                
    804                 // Both checks passed
    805                 return true;
     788                // Evaluate unified rules
     789                return RulesEvaluator::evaluate($rules, $eval_context);
    806790            });
    807791
  • ultimate-watermark/trunk/src/Watermark/Processors/GDWatermarkProcessor.php

    r3465062 r3465508  
    300300
    301301        // Get full size dimensions with fallback strategies
    302         $fullDimensions = $this->getFullSizeDimensions($watermarkData);
     302        $fullDimensions = $this->getFullSizeDimensions($watermarkData, $currentWidth, $currentHeight);
    303303       
    304304        // Calculate scaling ratio
     
    321321     * Get full size dimensions using multiple strategies
    322322     */
    323     private function getFullSizeDimensions(array $watermarkData): array
     323    private function getFullSizeDimensions(array $watermarkData, int $currentWidth, int $currentHeight): array
    324324    {
    325325        // Strategy 1: From watermark data
     
    333333        // Strategy 2: From source image path
    334334        $sourcePath = $watermarkData['_source_image_path'] ?? '';
    335         if ($sourcePath) {
     335        if ($sourcePath && file_exists($sourcePath)) {
    336336            $attachmentId = $this->getAttachmentIdFromPath($sourcePath);
    337337            if ($attachmentId) {
     
    344344
    345345        // Strategy 3: Use current image dimensions (fallback)
    346         throw new \RuntimeException('Unable to determine full size image dimensions');
     346        // This is safe for preview generation and when full size info is unavailable
     347        return ['width' => $currentWidth, 'height' => $currentHeight];
    347348    }
    348349
     
    550551
    551552    /**
    552      * Get attachment ID from file path
    553      */
    554     private function getAttachmentIdFromPath(string $filePath): int
    555     {
     553     * Get attachment ID from image file path
     554     * Handles both full size images and thumbnails/resized versions
     555     */
     556    private function getAttachmentIdFromPath(string $imagePath): ?int
     557    {
     558        if (empty($imagePath)) {
     559            return null;
     560        }
     561       
     562        // Normalize path
     563        $normalizedPath = wp_normalize_path($imagePath);
     564        $uploadDir = wp_upload_dir();
     565        $baseDir = wp_normalize_path($uploadDir['basedir']);
     566       
     567        // Get relative path from uploads directory
     568        if (strpos($normalizedPath, $baseDir) !== 0) {
     569            return null;
     570        }
     571       
     572        $relativePath = str_replace($baseDir . '/', '', $normalizedPath);
     573        $pathInfo = pathinfo($relativePath);
     574        $baseFilename = $pathInfo['filename'];
     575        $directory = $pathInfo['dirname'];
     576       
     577        // First, try exact match (for full size images)
    556578        global $wpdb;
    557        
    558         $fileName = basename($filePath);
    559579        $attachmentId = $wpdb->get_var($wpdb->prepare(
    560             "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_wp_attached_file' AND meta_value LIKE %s",
    561             '%' . $wpdb->esc_like($fileName)
     580            "SELECT post_id FROM {$wpdb->postmeta}
     581            WHERE meta_key = '_wp_attached_file'
     582            AND meta_value = %s
     583            LIMIT 1",
     584            $relativePath
    562585        ));
    563 
    564         return (int) $attachmentId;
     586       
     587        if ($attachmentId) {
     588            return (int) $attachmentId;
     589        }
     590       
     591        // If exact match fails, try to match by base filename and directory
     592        // This handles thumbnails and resized images (e.g., image-150x150.jpg -> image.jpg)
     593        // Remove size suffix (e.g., -150x150) from filename
     594        $baseFilenameClean = preg_replace('/-\d+x\d+$/', '', $baseFilename);
     595        $extension = isset($pathInfo['extension']) ? '.' . $pathInfo['extension'] : '';
     596       
     597        // Try to find attachment with matching base filename in same directory
     598        $possiblePath = $directory === '.' ? $baseFilenameClean . $extension : $directory . '/' . $baseFilenameClean . $extension;
     599       
     600        $attachmentId = $wpdb->get_var($wpdb->prepare(
     601            "SELECT post_id FROM {$wpdb->postmeta}
     602            WHERE meta_key = '_wp_attached_file'
     603            AND meta_value = %s
     604            LIMIT 1",
     605            $possiblePath
     606        ));
     607       
     608        if ($attachmentId) {
     609            return (int) $attachmentId;
     610        }
     611       
     612        // Last resort: search by base filename pattern in metadata
     613        $attachmentId = $wpdb->get_var($wpdb->prepare(
     614            "SELECT post_id FROM {$wpdb->postmeta} pm
     615            INNER JOIN {$wpdb->posts} p ON pm.post_id = p.ID
     616            WHERE pm.meta_key = '_wp_attached_file'
     617            AND pm.meta_value LIKE %s
     618            AND p.post_type = 'attachment'
     619            LIMIT 1",
     620            '%' . $wpdb->esc_like($baseFilenameClean) . '%'
     621        ));
     622       
     623        return $attachmentId ? (int) $attachmentId : null;
    565624    }
    566625
     
    773832        }
    774833    }
     834
     835    /**
     836     * Get supported image formats
     837     *
     838     * @return array Array of supported formats
     839     */
     840    public function getSupportedFormats(): array
     841    {
     842        return ['jpg', 'jpeg', 'png', 'gif', 'webp'];
     843    }
     844
     845    /**
     846     * Check if processor is available
     847     *
     848     * @return bool True if GD library is available
     849     */
     850    public function isAvailable(): bool
     851    {
     852        return extension_loaded('gd') && function_exists('gd_info');
     853    }
    775854}
  • ultimate-watermark/trunk/ultimate-watermark.php

    r3465501 r3465508  
    44 * Plugin URI: https://mantrabrain.com/ultimate-watermark
    55 * Description: Advanced WordPress Image Watermarking Plugin
    6  * Version: 2.0.1
     6 * Version: 2.0.2
    77 * Author: MantraBrain
    88 * Author URI: https://mantrabrain.com
     
    1818 * @package UltimateWatermark
    1919 * @author MantraBrain
    20  * @version 2.0
     20 * @version 2.0.2
    2121 */
    2222
     
    3636
    3737// Define plugin constants
    38 define('ULTIMATE_WATERMARK_VERSION', '2.0.1');
     38define('ULTIMATE_WATERMARK_VERSION', '2.0.2');
    3939define('ULTIMATE_WATERMARK_FILE', __FILE__);
    4040define('ULTIMATE_WATERMARK_DIR', plugin_dir_path(__FILE__));
Note: See TracChangeset for help on using the changeset viewer.