From a77bf8ea390952fb5fd58e6ebed21204865ddaf2 Mon Sep 17 00:00:00 2001
From: David Smith <david@gravitywiz.com>
Date: Thu, 7 Aug 2025 17:30:33 -0400
Subject: [PATCH 1/9] Update and rename gw-product-quantity-conditional.php to
 gw-product-quantity-conditional-logic.php

---
 ...ditional.php => gw-product-quantity-conditional-logic.php} | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
 rename gravity-forms/{gw-product-quantity-conditional.php => gw-product-quantity-conditional-logic.php} (94%)

diff --git a/gravity-forms/gw-product-quantity-conditional.php b/gravity-forms/gw-product-quantity-conditional-logic.php
similarity index 94%
rename from gravity-forms/gw-product-quantity-conditional.php
rename to gravity-forms/gw-product-quantity-conditional-logic.php
index 04cf00c7..323c0430 100644
--- a/gravity-forms/gw-product-quantity-conditional.php
+++ b/gravity-forms/gw-product-quantity-conditional-logic.php
@@ -1,12 +1,12 @@
 <?php
 /**
- * Gravity Wiz // Gravity Forms // Product Quantity Conditional
+ * Gravity Wiz // Gravity Forms // Product Quantity Conditional Logic
  *
  * Instruction Video: https://www.loom.com/share/38547a28853f4706b10cfdb42eaa45ca
  *
  * Adds quantity field options to conditional logic for Single Product fields.
  *
- * Plugin Name:  GF Product Quantity Conditional
+ * Plugin Name:  GF Product Quantity Conditional Logic
  * Plugin URI:   https://gravitywiz.com/
  * Description:  Adds quantity field options to conditional logic for Single Product fields that don't have dedicated quantity fields
  * Author:       Gravity Wiz

From 7808a1c63a1d5610f13fa265756adb4002cf8540 Mon Sep 17 00:00:00 2001
From: Saif Sultan <saif@gravitywiz.com>
Date: Fri, 8 Aug 2025 21:48:18 +0530
Subject: [PATCH 2/9] `gpcc-copy-to-conditionally-hidden-fields.php`: Fixed an
 issue with copying to Multi Choice field.

---
 .../gpcc-copy-to-conditionally-hidden-fields.php    | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/gp-copy-cat/gpcc-copy-to-conditionally-hidden-fields.php b/gp-copy-cat/gpcc-copy-to-conditionally-hidden-fields.php
index ccae50af..4851678d 100644
--- a/gp-copy-cat/gpcc-copy-to-conditionally-hidden-fields.php
+++ b/gp-copy-cat/gpcc-copy-to-conditionally-hidden-fields.php
@@ -47,13 +47,14 @@
 				}
 			}
 
-			if ( is_array( $source_values ) ) {
-				foreach ( $source_values as $input_id => $source_value ) {
-					$target_input_id           = str_replace( "{$source_field->id}.", "{$target['target']}.", $input_id );
-					$entry[ $target_input_id ] = $source_value;
+			$values = is_array( $source_values ) ? array_values( $source_values ) : [ $source_values ];
+
+			foreach ( $values as $index => $value ) {
+				$target_input_id           = is_array( $source_values ) ? "{$target['target']}." . ( $index + 1 ) : $target['target'];
+				$entry[ $target_input_id ] = $value;
+				if ( ! is_array( $source_values ) ) {
+					break;
 				}
-			} else {
-				$entry[ $target['target'] ] = $source_values;
 			}
 		}
 	}

From d6e5edf6cdbf9225e9e0d9a808886066d52211b5 Mon Sep 17 00:00:00 2001
From: Saif Sultan <saif@gravitywiz.com>
Date: Fri, 8 Aug 2025 21:50:03 +0530
Subject: [PATCH 3/9] `gpppw-capture-count-as-field-value.js`: Fixed an issue
 with snippet not working with Conditional Logic in play.

---
 gp-pay-per-word/gpppw-capture-count-as-field-value.js | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/gp-pay-per-word/gpppw-capture-count-as-field-value.js b/gp-pay-per-word/gpppw-capture-count-as-field-value.js
index 4714ccd3..2f9a4fe2 100644
--- a/gp-pay-per-word/gpppw-capture-count-as-field-value.js
+++ b/gp-pay-per-word/gpppw-capture-count-as-field-value.js
@@ -9,6 +9,13 @@
  * [1]: https://gravitywiz.com/gravity-forms-code-chest/
  */
 gform.addFilter( 'gpppw_word_count', function( wordCount ) {
-  // Update "4" to the ID of the field which should be populated with the word count.
-	$( '#input_GFFORMID_4' ).val( wordCount ).change();
+	// Update "2" to the ID of the field which should be populated with the word count.
+	var $field = $( '#input_GFFORMID_2' );
+
+	// Only update if value is actually different
+	if ( $field.val() != wordCount ) {
+		$field.val( wordCount ).change();
+	}
+
+	return wordCount;
 }, 11 );

From 25ab6f282ff3494dc73921063fdc63f7b8152c6d Mon Sep 17 00:00:00 2001
From: SebastianWiz <165194375+SebastianWiz@users.noreply.github.com>
Date: Fri, 8 Aug 2025 10:46:36 -0700
Subject: [PATCH 4/9] `gw-require-unique-values.php`: Added support for
 whole-field validation for multi-input fields.

---
 gravity-forms/gw-require-unique-values.php | 27 ++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/gravity-forms/gw-require-unique-values.php b/gravity-forms/gw-require-unique-values.php
index 189430d4..4917f966 100644
--- a/gravity-forms/gw-require-unique-values.php
+++ b/gravity-forms/gw-require-unique-values.php
@@ -11,7 +11,7 @@
  * Plugin URI:   https://gravitywiz.com/gravity-forms-require-unique-values-for-different-fields/
  * Description:  Require two or more fields on the same form to be different from each other.
  * Author:       Gravity Wiz
- * Version:      0.2
+ * Version:      0.3
  * Author URI:   https://gravitywiz.com/
  */
 class GW_Require_Unique_Values {
@@ -52,6 +52,10 @@ public function init() {
 		add_filter( sprintf( 'gform_field_validation_%s', $this->_args['form_id'] ), array( $this, 'validate' ), 10, 4 );
 	}
 
+	private function get_all_field_ids() {
+		return array_merge( $this->_args['field_ids'], array( $this->_args['master_field_id'] ) );
+	}
+
 	public function validate( $result, $value, $form, $field ) {
 
 		if ( ! $this->is_applicable_field( $field ) ) {
@@ -83,8 +87,12 @@ public function validate( $result, $value, $form, $field ) {
 		} else {
 			$values = $this->get_group_values( $form, $field->id );
 
+			// Check if this should be validated as whole field
+			$all_field_ids = $this->get_all_field_ids();
+			$validate_as_whole = in_array( $field->id, $all_field_ids );
+
 			// If the field has inputs, let's loop through them and check if they are unique.
-			if ( is_array( $field->inputs ) && ! empty( $field->inputs ) ) {
+			if ( is_array( $field->inputs ) && ! empty( $field->inputs ) && ! $validate_as_whole ) {
 				$is_unique = true;
 
 				foreach ( $field->inputs as $input ) {
@@ -194,6 +202,21 @@ public function get_filtered_value( $field, $input_id = null ) {
 			$value = $value[ $input_id ];
 		}
 
+		// When using a field ID (not input ID) for multi-input fields, combine all subfield values into one for validation.
+		if ( ! $input_id && is_array( $field->inputs ) && is_array( $value ) ) {
+			$all_field_ids = $this->get_all_field_ids();
+			if ( in_array( $field->id, $all_field_ids ) ) {
+				$combined_parts = array();
+				foreach ( $field->inputs as $input ) {
+					$input_value = rgar( $value, $input['id'] );
+					if ( ! empty( $input_value ) ) {
+						$combined_parts[] = $input_value;
+					}
+				}
+				$value = array( implode( ' ', $combined_parts ) );
+			}
+		}
+
 		$value = ! is_array( $value ) ? array( $value ) : $value;
 		$value = array_filter( $value );
 

From 453ad6aa85a1f9b10e739b62279a50eae59712a6 Mon Sep 17 00:00:00 2001
From: SebastianWiz <165194375+SebastianWiz@users.noreply.github.com>
Date: Mon, 11 Aug 2025 08:03:46 -0700
Subject: [PATCH 5/9] `gpeb-display-stars-for-rating-fields.php`: Added
 customizable SVG star with empty star display option for rating fields.

---
 .../gpeb-display-stars-for-rating-fields.php  | 36 +++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/gp-entry-blocks/gpeb-display-stars-for-rating-fields.php b/gp-entry-blocks/gpeb-display-stars-for-rating-fields.php
index 833ec937..3804fca9 100644
--- a/gp-entry-blocks/gpeb-display-stars-for-rating-fields.php
+++ b/gp-entry-blocks/gpeb-display-stars-for-rating-fields.php
@@ -4,16 +4,48 @@
  * https://gravitywiz.com/documentation/gravity-forms-entry-blocks/
  */
 add_filter( 'gpeb_entry', function( $entry, $form ) {
+
+	// Configure star settings
+	$config = [
+		'star_size'        => 24,        // Width/height of stars in pixels
+		'star_color'       => '#FFAC33', // Color of the stars
+		'stroke_width'     => 1.5,       // Thickness of star outline
+		'show_empty_stars' => false,     // Whether to show empty stars
+	];
+
+	$star_size    = max( 1, (int) $config['star_size'] );
+	$stroke_width = (float) $config['stroke_width'];
+	$star_color   = sanitize_hex_color( $config['star_color'] ) ?: '#FFAC33';
+
+	$star_svg = '<svg xmlns="http://www.w3.org/2000/svg" width="' . esc_attr( $star_size ) . '" height="' . esc_attr( $star_size ) . '" viewBox="0 0 24 24" stroke="' . esc_attr( $star_color ) . '" stroke-width="' . esc_attr( $stroke_width ) . '" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>';
+
 	foreach ( $form['fields'] as $field ) {
 		if ( $field->get_input_type() === 'rating' ) {
 			$selected_value = $entry[ $field->id ];
 			foreach ( $field->choices as $index => $choice ) {
 				if ( $choice['value'] === $selected_value ) {
-					$entry[ $field->id ] = str_repeat( '⭐', $index + 1 );
-					break 2;
+					$filled_stars = str_repeat(str_replace('<svg ', '<svg fill="' . esc_attr( $star_color ) . '" class="gpeb-filled-star" ', $star_svg), $index + 1);
+					$empty_stars = $config['show_empty_stars'] ? str_repeat(str_replace('<svg ', '<svg fill="none" class="gpeb-outline-star" ', $star_svg), 5 - ($index + 1)) : '';
+
+					$entry[$field->id] = $filled_stars . $empty_stars;
+					break;
 				}
 			}
 		}
 	}
 	return $entry;
 }, 10, 2 );
+
+// Unescape HTML-encoded SVG content for rating fields
+if ( ! function_exists( 'decode_rating_field_svgs' ) ) {
+	function decode_rating_field_svgs($content, $entry_form, $entry) {
+		foreach ($entry_form['fields'] as $field) {
+			if ($field->get_input_type() === 'rating' && isset($entry[$field->id]) && strpos($entry[$field->id], '<svg') !== false) {
+				$content = str_replace(esc_html($entry[$field->id]), $entry[$field->id], $content);
+			}
+		}
+		return $content;
+	}
+}
+add_filter('gpeb_loop_entry_content', 'decode_rating_field_svgs', 10, 3);
+add_filter('gpeb_view_entry_content', 'decode_rating_field_svgs', 10, 3);
\ No newline at end of file

From 1c23cffc2bdc61fddf2ffb5c94d3c0d75af9de9f Mon Sep 17 00:00:00 2001
From: Lee Hanbury <lee.hanbury@gmail.com>
Date: Thu, 7 Aug 2025 15:39:01 +0100
Subject: [PATCH 6/9] `gpuid-multiple-ids.php`: Added option to use multiple
 field IDs for count

This is to extend the raffle/lottery ticket example on here: https://gravitywiz.com/gravity-forms-build-raffle-or-lottery/

While the guide supports "packages" of pre-defined counts for choice selections, it does not allow user-defined counts for multiple ticket types.

This PR allows you to specify multiple field IDs that will all be counted and totalled to the final count allowing you to sell multiple ticket types with as many as a user would like to purchase.
---
 gp-unique-id/gpuid-multiple-ids.php | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/gp-unique-id/gpuid-multiple-ids.php b/gp-unique-id/gpuid-multiple-ids.php
index 2e36bf20..a1eaab7c 100644
--- a/gp-unique-id/gpuid-multiple-ids.php
+++ b/gp-unique-id/gpuid-multiple-ids.php
@@ -122,6 +122,9 @@ function get_count( $entry ) {
 			if ( isset( $count['choices'] ) ) {
 				$value = call_user_func( 'array_shift', explode( '|', rgar( $entry, $count['field_id'] ) ) );
 				$count = rgar( $count['choices'], $value );
+			} elseif ( ! empty( $count['field_ids'] ) && is_array( $count['field_ids'] ) ) {
+				$counts = array_map( fn ( string|int|float $id ): string|int => rgar( $entry, $id ), $count['field_ids'] );
+				$count  = array_reduce( $counts, fn ( int $carry, string|int $count ): int => $carry + absint( $count ), 0 );
 			} else {
 				$count = rgar( $entry, $count['field_id'] );
 			}
@@ -188,3 +191,15 @@ function reinforce_check_unqiue_query( $query, $form_id, $field_id, $unique ) {
 //         )
 //     )
 // ) );
+
+// new GPUID_Multiple_IDs( array(
+//     'form_id'         => 694,
+//     'target_field_id' => 36,
+//     'source_field_id' => 35,
+//     'count'           => array(
+//         'field_ids'   => array(
+//             '11.3',
+//             20,
+//         ),
+//     ),
+// ) );

From e68edbea137a12e05ca8749b4bff351baa0f9795 Mon Sep 17 00:00:00 2001
From: veryspry <ehlinger.matt@gmail.com>
Date: Wed, 13 Aug 2025 14:37:10 -0500
Subject: [PATCH 7/9] Tooling: Updated GH `actions/checkout` to v5.

---
 .github/workflows/php-lint-pr.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/php-lint-pr.yml b/.github/workflows/php-lint-pr.yml
index 6b870449..1f9cc777 100644
--- a/.github/workflows/php-lint-pr.yml
+++ b/.github/workflows/php-lint-pr.yml
@@ -7,7 +7,7 @@ jobs:
     name: PHPCS (Files Changed)
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v5
         with:
           fetch-depth: 0 # The blame will not work without this
 
@@ -23,4 +23,4 @@ jobs:
         with:
           files: "**.php,**.js,**.css"
           phpcs_path: ./vendor/bin/phpcs
-          standard: phpcs.xml
\ No newline at end of file
+          standard: phpcs.xml

From 96e3f6ab1be9befa55f217125a453456d7d1eb57 Mon Sep 17 00:00:00 2001
From: veryspry <ehlinger.matt@gmail.com>
Date: Wed, 13 Aug 2025 14:39:58 -0500
Subject: [PATCH 8/9] Tooling: Updated `nanasess/setup-php` to v4.1.0.

---
 .github/workflows/php-lint-pr.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/php-lint-pr.yml b/.github/workflows/php-lint-pr.yml
index 1f9cc777..5c4345e9 100644
--- a/.github/workflows/php-lint-pr.yml
+++ b/.github/workflows/php-lint-pr.yml
@@ -12,7 +12,7 @@ jobs:
           fetch-depth: 0 # The blame will not work without this
 
       # PHP 8 will throw PHP Fatal error: Uncaught TypeError: vsprintf(): Argument #2 ($values) must be of type array, string given in ...
-      - uses: nanasess/setup-php@v3
+      - uses: nanasess/setup-php@v4.1.0
         with:
           php-version: '7.4'
 

From 58314e5dd478bd4786ffb3538dc4068b0140087d Mon Sep 17 00:00:00 2001
From: veryspry <ehlinger.matt@gmail.com>
Date: Wed, 13 Aug 2025 15:11:55 -0500
Subject: [PATCH 9/9] Tooling: Updated `nanasess/setup-php@` to
 `shivammathur/setup-php`.

---
 .github/workflows/php-lint-pr.yml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/php-lint-pr.yml b/.github/workflows/php-lint-pr.yml
index 5c4345e9..6396bb98 100644
--- a/.github/workflows/php-lint-pr.yml
+++ b/.github/workflows/php-lint-pr.yml
@@ -12,9 +12,11 @@ jobs:
           fetch-depth: 0 # The blame will not work without this
 
       # PHP 8 will throw PHP Fatal error: Uncaught TypeError: vsprintf(): Argument #2 ($values) must be of type array, string given in ...
-      - uses: nanasess/setup-php@v4.1.0
+      - uses: shivammathur/setup-php@v2
         with:
           php-version: '7.4'
+          tools: composer:v2
+          coverage: none
 
       - name: Install dependencies
         run: composer install --dev --prefer-dist --no-progress --no-suggest
