Changeset 3465508
- Timestamp:
- 02/20/2026 05:42:16 AM (6 weeks ago)
- Location:
- ultimate-watermark
- Files:
-
- 14 edited
- 1 copied
-
tags/2.0.2 (copied) (copied from ultimate-watermark/trunk)
-
tags/2.0.2/readme.txt (modified) (3 diffs)
-
tags/2.0.2/src/Admin/Pages/WatermarkPage.php (modified) (3 diffs)
-
tags/2.0.2/src/Integration/RestApiIntegration.php (modified) (2 diffs)
-
tags/2.0.2/src/Utils/RulesEvaluator.php (modified) (3 diffs)
-
tags/2.0.2/src/Utils/WatermarkHelper.php (modified) (1 diff)
-
tags/2.0.2/src/Watermark/Processors/GDWatermarkProcessor.php (modified) (6 diffs)
-
tags/2.0.2/ultimate-watermark.php (modified) (3 diffs)
-
trunk/readme.txt (modified) (3 diffs)
-
trunk/src/Admin/Pages/WatermarkPage.php (modified) (3 diffs)
-
trunk/src/Integration/RestApiIntegration.php (modified) (2 diffs)
-
trunk/src/Utils/RulesEvaluator.php (modified) (3 diffs)
-
trunk/src/Utils/WatermarkHelper.php (modified) (1 diff)
-
trunk/src/Watermark/Processors/GDWatermarkProcessor.php (modified) (6 diffs)
-
trunk/ultimate-watermark.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
ultimate-watermark/tags/2.0.2/readme.txt
r3465501 r3465508 5 5 Requires at least: 5.0 6 6 Tested up to: 6.9 7 Stable tag: 2.0. 17 Stable tag: 2.0.2 8 8 License: GPLv3 9 9 License URI: http://www.gnu.org/licenses/gpl-3.0.html … … 362 362 == Changelog == 363 363 364 = 2.0. 1- 2026/02/20 =364 = 2.0.2- 2026/02/20 = 365 365 * **Fixed** - Duplication issue fixed 366 * **Fixed** - GD library issue fixed 366 367 367 368 = 2.0 - 2026/02/19 = … … 428 429 = 1.0.0 - 2019/02/16 = 429 430 * **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 591 591 $watermark_rules = $watermark['watermark_rules'] ?? []; 592 592 593 // If no unified rules, fall back to legacy display593 // If no unified rules, show "No rules" 594 594 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>'; 596 596 } 597 597 … … 605 605 } 606 606 607 // If no conditions defined, show as "No r estrictions"607 // If no conditions defined, show as "No rules" 608 608 if (!$has_conditions) { 609 return '<span class="rule-item no-r estrictions">' . __('No restrictions', 'ultimate-watermark') . '</span>';609 return '<span class="rule-item no-rules">' . __('No rules', 'ultimate-watermark') . '</span>'; 610 610 } 611 611 … … 649 649 650 650 if (empty($rule_summaries)) { 651 return '<span class="rule-item no-r estrictions">' . __('No restrictions', 'ultimate-watermark') . '</span>';651 return '<span class="rule-item no-rules">' . __('No rules', 'ultimate-watermark') . '</span>'; 652 652 } 653 653 -
ultimate-watermark/tags/2.0.2/src/Integration/RestApiIntegration.php
r3465062 r3465508 717 717 $rules = $watermark['watermark_rules'] ?? []; 718 718 if (empty($rules) || !is_array($rules)) { 719 return true; // No unified rules = no extra restriction719 return false; // No unified rules = don't apply watermark 720 720 } 721 721 // Check if any rule has conditions … … 728 728 } 729 729 if (!$has_conditions) { 730 return true; // No conditions defined = no restriction730 return false; // No conditions defined = don't apply watermark 731 731 } 732 732 $eval_context = \MantraBrain\UltimateWatermark\Utils\RulesEvaluator::buildContext( -
ultimate-watermark/tags/2.0.2/src/Utils/RulesEvaluator.php
r3465062 r3465508 19 19 * If ANY rule passes (rules are OR'd at the top level), the watermark applies. 20 20 * 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). 22 22 * 23 23 * @param array $rules The watermark_rules array (keyed by rule_id) … … 28 28 { 29 29 if (empty($rules)) { 30 return true; // No rules = no restrictions31 } 32 33 // Check if ALL rules have zero conditions — treat as unrestricted30 return false; // No rules = don't apply watermark 31 } 32 33 // Check if ALL rules have zero conditions — treat as no rules set 34 34 $has_any_conditions = false; 35 35 foreach ($rules as $rule) { … … 41 41 42 42 if (!$has_any_conditions) { 43 return true; // All rules have empty conditions = no restrictions43 return false; // All rules have empty conditions = no rules set, don't apply 44 44 } 45 45 -
ultimate-watermark/tags/2.0.2/src/Utils/WatermarkHelper.php
r3465062 r3465508 724 724 } 725 725 726 // Check unified watermark_rules conditions first (if any exist with conditions)726 // Check unified watermark_rules - MUST have rules to apply 727 727 $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 } 735 776 } 736 777 } 737 778 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); 789 785 } 790 786 } 791 787 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); 806 790 }); 807 791 -
ultimate-watermark/tags/2.0.2/src/Watermark/Processors/GDWatermarkProcessor.php
r3465062 r3465508 300 300 301 301 // Get full size dimensions with fallback strategies 302 $fullDimensions = $this->getFullSizeDimensions($watermarkData );302 $fullDimensions = $this->getFullSizeDimensions($watermarkData, $currentWidth, $currentHeight); 303 303 304 304 // Calculate scaling ratio … … 321 321 * Get full size dimensions using multiple strategies 322 322 */ 323 private function getFullSizeDimensions(array $watermarkData ): array323 private function getFullSizeDimensions(array $watermarkData, int $currentWidth, int $currentHeight): array 324 324 { 325 325 // Strategy 1: From watermark data … … 333 333 // Strategy 2: From source image path 334 334 $sourcePath = $watermarkData['_source_image_path'] ?? ''; 335 if ($sourcePath ) {335 if ($sourcePath && file_exists($sourcePath)) { 336 336 $attachmentId = $this->getAttachmentIdFromPath($sourcePath); 337 337 if ($attachmentId) { … … 344 344 345 345 // 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]; 347 348 } 348 349 … … 550 551 551 552 /** 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) 556 578 global $wpdb; 557 558 $fileName = basename($filePath);559 579 $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 562 585 )); 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; 565 624 } 566 625 … … 773 832 } 774 833 } 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 } 775 854 } -
ultimate-watermark/tags/2.0.2/ultimate-watermark.php
r3465501 r3465508 4 4 * Plugin URI: https://mantrabrain.com/ultimate-watermark 5 5 * Description: Advanced WordPress Image Watermarking Plugin 6 * Version: 2.0. 16 * Version: 2.0.2 7 7 * Author: MantraBrain 8 8 * Author URI: https://mantrabrain.com … … 18 18 * @package UltimateWatermark 19 19 * @author MantraBrain 20 * @version 2.0 20 * @version 2.0.2 21 21 */ 22 22 … … 36 36 37 37 // Define plugin constants 38 define('ULTIMATE_WATERMARK_VERSION', '2.0. 1');38 define('ULTIMATE_WATERMARK_VERSION', '2.0.2'); 39 39 define('ULTIMATE_WATERMARK_FILE', __FILE__); 40 40 define('ULTIMATE_WATERMARK_DIR', plugin_dir_path(__FILE__)); -
ultimate-watermark/trunk/readme.txt
r3465501 r3465508 5 5 Requires at least: 5.0 6 6 Tested up to: 6.9 7 Stable tag: 2.0. 17 Stable tag: 2.0.2 8 8 License: GPLv3 9 9 License URI: http://www.gnu.org/licenses/gpl-3.0.html … … 362 362 == Changelog == 363 363 364 = 2.0. 1- 2026/02/20 =364 = 2.0.2- 2026/02/20 = 365 365 * **Fixed** - Duplication issue fixed 366 * **Fixed** - GD library issue fixed 366 367 367 368 = 2.0 - 2026/02/19 = … … 428 429 = 1.0.0 - 2019/02/16 = 429 430 * **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 591 591 $watermark_rules = $watermark['watermark_rules'] ?? []; 592 592 593 // If no unified rules, fall back to legacy display593 // If no unified rules, show "No rules" 594 594 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>'; 596 596 } 597 597 … … 605 605 } 606 606 607 // If no conditions defined, show as "No r estrictions"607 // If no conditions defined, show as "No rules" 608 608 if (!$has_conditions) { 609 return '<span class="rule-item no-r estrictions">' . __('No restrictions', 'ultimate-watermark') . '</span>';609 return '<span class="rule-item no-rules">' . __('No rules', 'ultimate-watermark') . '</span>'; 610 610 } 611 611 … … 649 649 650 650 if (empty($rule_summaries)) { 651 return '<span class="rule-item no-r estrictions">' . __('No restrictions', 'ultimate-watermark') . '</span>';651 return '<span class="rule-item no-rules">' . __('No rules', 'ultimate-watermark') . '</span>'; 652 652 } 653 653 -
ultimate-watermark/trunk/src/Integration/RestApiIntegration.php
r3465062 r3465508 717 717 $rules = $watermark['watermark_rules'] ?? []; 718 718 if (empty($rules) || !is_array($rules)) { 719 return true; // No unified rules = no extra restriction719 return false; // No unified rules = don't apply watermark 720 720 } 721 721 // Check if any rule has conditions … … 728 728 } 729 729 if (!$has_conditions) { 730 return true; // No conditions defined = no restriction730 return false; // No conditions defined = don't apply watermark 731 731 } 732 732 $eval_context = \MantraBrain\UltimateWatermark\Utils\RulesEvaluator::buildContext( -
ultimate-watermark/trunk/src/Utils/RulesEvaluator.php
r3465062 r3465508 19 19 * If ANY rule passes (rules are OR'd at the top level), the watermark applies. 20 20 * 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). 22 22 * 23 23 * @param array $rules The watermark_rules array (keyed by rule_id) … … 28 28 { 29 29 if (empty($rules)) { 30 return true; // No rules = no restrictions31 } 32 33 // Check if ALL rules have zero conditions — treat as unrestricted30 return false; // No rules = don't apply watermark 31 } 32 33 // Check if ALL rules have zero conditions — treat as no rules set 34 34 $has_any_conditions = false; 35 35 foreach ($rules as $rule) { … … 41 41 42 42 if (!$has_any_conditions) { 43 return true; // All rules have empty conditions = no restrictions43 return false; // All rules have empty conditions = no rules set, don't apply 44 44 } 45 45 -
ultimate-watermark/trunk/src/Utils/WatermarkHelper.php
r3465062 r3465508 724 724 } 725 725 726 // Check unified watermark_rules conditions first (if any exist with conditions)726 // Check unified watermark_rules - MUST have rules to apply 727 727 $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 } 735 776 } 736 777 } 737 778 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); 789 785 } 790 786 } 791 787 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); 806 790 }); 807 791 -
ultimate-watermark/trunk/src/Watermark/Processors/GDWatermarkProcessor.php
r3465062 r3465508 300 300 301 301 // Get full size dimensions with fallback strategies 302 $fullDimensions = $this->getFullSizeDimensions($watermarkData );302 $fullDimensions = $this->getFullSizeDimensions($watermarkData, $currentWidth, $currentHeight); 303 303 304 304 // Calculate scaling ratio … … 321 321 * Get full size dimensions using multiple strategies 322 322 */ 323 private function getFullSizeDimensions(array $watermarkData ): array323 private function getFullSizeDimensions(array $watermarkData, int $currentWidth, int $currentHeight): array 324 324 { 325 325 // Strategy 1: From watermark data … … 333 333 // Strategy 2: From source image path 334 334 $sourcePath = $watermarkData['_source_image_path'] ?? ''; 335 if ($sourcePath ) {335 if ($sourcePath && file_exists($sourcePath)) { 336 336 $attachmentId = $this->getAttachmentIdFromPath($sourcePath); 337 337 if ($attachmentId) { … … 344 344 345 345 // 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]; 347 348 } 348 349 … … 550 551 551 552 /** 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) 556 578 global $wpdb; 557 558 $fileName = basename($filePath);559 579 $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 562 585 )); 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; 565 624 } 566 625 … … 773 832 } 774 833 } 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 } 775 854 } -
ultimate-watermark/trunk/ultimate-watermark.php
r3465501 r3465508 4 4 * Plugin URI: https://mantrabrain.com/ultimate-watermark 5 5 * Description: Advanced WordPress Image Watermarking Plugin 6 * Version: 2.0. 16 * Version: 2.0.2 7 7 * Author: MantraBrain 8 8 * Author URI: https://mantrabrain.com … … 18 18 * @package UltimateWatermark 19 19 * @author MantraBrain 20 * @version 2.0 20 * @version 2.0.2 21 21 */ 22 22 … … 36 36 37 37 // Define plugin constants 38 define('ULTIMATE_WATERMARK_VERSION', '2.0. 1');38 define('ULTIMATE_WATERMARK_VERSION', '2.0.2'); 39 39 define('ULTIMATE_WATERMARK_FILE', __FILE__); 40 40 define('ULTIMATE_WATERMARK_DIR', plugin_dir_path(__FILE__));
Note: See TracChangeset
for help on using the changeset viewer.