Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,8 @@
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": "never"
}
},
"search.exclude": {
"**/pro__premium_only": false
}
}
6 changes: 3 additions & 3 deletions interactions.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* Author URI: http://gambit.ph
* License: GPLv2 or later
* Text Domain: interactions
* Version: 1.3.0
* Version: 1.3.2
*
* @fs_premium_only /freemius.php, /freemius/
*/
Expand All @@ -18,7 +18,7 @@
}

defined( 'INTERACT_BUILD' ) || define( 'INTERACT_BUILD', 'free' );
defined( 'INTERACT_VERSION' ) || define( 'INTERACT_VERSION', '1.3.0' );
defined( 'INTERACT_VERSION' ) || define( 'INTERACT_VERSION', '1.3.2' );
defined( 'INTERACT_FILE' ) || define( 'INTERACT_FILE', __FILE__ );

/**
Expand All @@ -31,8 +31,8 @@ function interact_on_activation() {
// Run migration if version not set or outdated
if ( ! $saved_version || version_compare( $saved_version, INTERACT_VERSION, '<' ) ) {
do_action( 'interact/on_plugin_update', $saved_version, INTERACT_VERSION );
update_option( 'interact_plugin_version', INTERACT_VERSION );
}
update_option( 'interact_plugin_version', INTERACT_VERSION );
}
}
register_activation_hook( __FILE__, 'interact_on_activation' );
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "interactions",
"version": "1.3.0",
"version": "1.3.2",
"description": "Make your blocks interactive! Effortlessly set triggers that do actions",
"author": "Benjamin Intal of Gambit",
"private": true,
Expand Down
53 changes: 35 additions & 18 deletions readme.txt
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
=== Interactions ===
=== Interactions - Create Interactive Experiences in the Block Editor ===
Contributors: bfintal, gambitph
Tags: interaction, interactivity, trigger, blocks, gutenberg
Requires at least: 6.6.4
Tested up to: 6.8.3
Requires at least: 6.7.4
Tested up to: 6.9
Requires PHP: 8.0
Stable tag: 1.3.0
Stable tag: 1.3.2
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Add animations and interactivity to your blocks. Choose from ready-made effects like scroll & hover in the Interactions Library, or build your own.

== Description ==

**Interactions – WordPress Animations, Effects & Functionality for Gutenberg Blocks**
**Interactions – WordPress Animations, Interactive Experiences for Gutenberg Blocks**

Want to make your website feel alive and interactive? **Interactions** is the easiest way to add animations, effects, interactivity, and functional features to WordPress — directly inside the block editor.
[Visit our website](https://wpinteractions.com) to learn more about how Interactions work.

Want to make your website feel alive and interactive? **Interactions** is the easiest way to add animations, effects, interactivity, and functional features to WordPress — directly inside the block editor. Check our [samples page here](https://wpinteractions.com/samples/) to see a glimpse of what type of interactions you can create.

You don't need coding skills or complex tools. With Interactions, you can:

- **Pick from the Interactions Library** – A collection of pre-built animations and effects (like images that move upon scrolling down the page, buttons that glow when hovered, and more). Just click and apply.
- **Build your own custom effects** – Use a simple **Trigger → Action** system. Example: "On scroll → Fade in block", or "On click → Play video".
- **Add functional features** – Securely update post data, handle form submissions, display user info, copy text to clipboard, and more without coding.
- **Pick from the [Interactions Library](https://docs.wpinteractions.com/article/744-how-to-use-interactions-library)** – A collection of pre-built animations and effects (like images that move upon scrolling down the page, buttons that glow when hovered, and more). Just click and apply. [Learn more](https://docs.wpinteractions.com/article/744-how-to-use-interactions-library)
- **Build your own custom effects** – Use a simple **Trigger → Action** system. Example: "On scroll → Fade in block", or "On click → Play video". [Learn more](https://docs.wpinteractions.com/article/577-what-is-wp-interactions-and-how-does-it-work)
- **Add functional features** – Securely update post data, handle form submissions, display user info, copy text to clipboard, and more without coding. [Learn more](https://docs.wpinteractions.com/category/729-interactions)

Whether you want subtle hover effects, attention-grabbing story-telling animations, playful micro-interactions, or powerful functional features, Interactions makes it possible.
Whether you want subtle hover effects, attention-grabbing story-telling animations, playful micro-interactions, or powerful functional features, [Interactions](https://wpinteractions.com) makes it possible.

### 🚀 Features

Create custom interactions easily with a simple Trigger → Action builder. Features include:

Create [custom interactions](https://docs.wpinteractions.com/article/571-what-are-interactions) easily with a simple Trigger → Action builder. Features include:

**Animations & Visual Effects:**

Expand Down Expand Up @@ -70,6 +71,8 @@ Create custom interactions easily with a simple Trigger → Action builder. Feat

### 💎 What's in Premium?

[Check our pricing page](https://wpinteractions.com/pricing/) to learn more about what's in Interactions premium.

**Advanced Interactions:**

- **Scroll Strength** – Measure scroll intensity
Expand Down Expand Up @@ -98,6 +101,11 @@ Create custom interactions easily with a simple Trigger → Action builder. Feat
- **Regular Updates** – New features and improvements
- **Commercial License** – Use in client projects

**Source Code:**

The source code for this plugin is available on GitHub:
https://github.com/gambitph/Interactions

== Installation ==

1. Install “Interactions” from the WordPress Plugin Directory, or upload it to `/wp-content/plugins/interactions/`.
Expand Down Expand Up @@ -133,23 +141,32 @@ The free version includes basic animations and interactions. Premium adds advanc

== Screenshots ==

1. Interaction Library – Pre-built animations and effects.
1. Adding from the Interaction Library – Pre-built animations and effects.
2. Advanced trigger and action timeline builder – Create custom interactions with flexible logic and multiple steps.
3. Interaction Library contents – Pre-built animations and effects.

== Source ==

The source code for this plugin is available on GitHub:
https://github.com/gambitph/Interactions
== Upgrade Notice ==

== Changelog ==

= 1.3.2 =

* Fixed: Added restrictions for users without unfiltered_html capabilities
* Fixed: Added additional input sanitization

= 1.3.1 =

* Fixed: Updated readme info
* Fixed: Updated long name in the plugins page
* Fixed: License activation issue

= 1.3.0 =

* New: Interaction library
* New: Initial release in the WordPress Plugin Directory!
* New: Block name field is now searchable #70
* New: Import / export functionality #71
* New: Box shadow action #81
* New: 3D Rotate - new transform origin option
* Fixed: Hover interaction glitches when hovering too fast #9
* Fixed: On enter viewport doesn't always trigger when on mobile #23
* Fixed: Confetti action - selecting window will no longer show a display target warning message #74
Expand Down
10 changes: 10 additions & 0 deletions scripts/package.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,16 @@ async function packagePlugin() {
}
}

// Rename interactions.php to plugin.php for premium builds only
if ( IS_PREMIUM_BUILD ) {
const oldPath = path.join( BUILD_DIR, 'interactions.php' )
const newPath = path.join( BUILD_DIR, 'plugin.php' )
if ( fs.existsSync( oldPath ) ) {
fs.renameSync( oldPath, newPath )
console.log( '📝 Renamed interactions.php to plugin.php for premium build' )
}
}
Comment on lines +315 to +323
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for premium build references and related configuration
echo "=== Searching for premium build references ==="
rg -i "premium" scripts/package.js | head -20

echo ""
echo "=== Searching for Freemius or updater references ==="
rg -i "freemius|updater|basename" . | head -30

echo ""
echo "=== Searching for interactions.php references ==="
rg "interactions\.php" . --type js --type json --type php | head -30

echo ""
echo "=== Searching for plugin.php references ==="
rg "plugin\.php" . --type js --type json --type php | head -30

echo ""
echo "=== Checking for build output/distribution config ==="
rg -i "build|dist|package" . --type json -l | head -10

Repository: gambitph/Interactions

Length of output: 5119


🏁 Script executed:

#!/bin/bash
# Check package.json for build scripts and context
echo "=== package.json build scripts ==="
cat package.json | head -50

echo ""
echo "=== Looking for migration or update handling ==="
rg -i "migrate|upgrade|basename.*change|plugin.*main.*file" . --type php --type js | head -20

echo ""
echo "=== Check the full context around the rename in package.js ==="
sed -n '300,330p' scripts/package.js

Repository: gambitph/Interactions

Length of output: 5171


Rename from interactions.php to plugin.php breaks existing premium upgrade path and Freemius tracking

The rename creates a breaking change for existing premium installations. Previous premium releases have the plugin activated as interactions/interactions.php, but after this change, the main file becomes interactions/plugin.php.

Freemius tracks the plugin by plugin_basename($this->plugin_main_file), which will now return interactions/plugin.php instead of interactions/interactions.php. On upgrade, WordPress will have both files present—the old active file and the new main file—but Freemius and the plugin action links hook will reference the new basename, causing:

  • License verification to fail or become confused
  • Plugin action links not to appear correctly
  • Update checks to not recognize the existing installation

Either add a migration strategy (deactivate and reactivate the plugin during upgrade), document this as a breaking change requiring manual re-activation, or reconsider if renaming to plugin.php is necessary for the premium build.

🤖 Prompt for AI Agents
In scripts/package.js around lines 315-323, renaming interactions.php to
plugin.php breaks existing premium upgrade paths and Freemius tracking; instead
of renaming, change the build step to preserve interactions.php for backward
compatibility and also add the new plugin.php entrypoint: copy interactions.php
to plugin.php (do not delete the original) or create a small wrapper
interactions.php that loads/require_once plugin.php so
plugin_basename($this->plugin_main_file) still returns
interactions/interactions.php and existing installs continue to be recognized;
ensure both files are included in the BUILD_DIR and update the log message
accordingly.


console.log( '📁 Copying source directories...' )
// Pass isSrcRoot = true for the top-level src folder
copyDir( 'src', path.join( BUILD_DIR, 'src' ), true )
Expand Down
32 changes: 32 additions & 0 deletions src/action-types/abstract-action-type.php
Original file line number Diff line number Diff line change
Expand Up @@ -256,5 +256,37 @@ public function initilize_action( $action, $animation_data ) {

return $action;
}

/**
* Sanitizes the action's value before saving.
*
* Override this in a child class to implement specific sanitization.
*
* @param mixed $value The action value to sanitize.
* @return mixed The sanitized action value.
*/
public function sanitize_data_for_saving( $value ) {
// By default, no sanitization is applied.
return $value;
}

/**
* Remove any `expression(...)` and `javascript:` content from a CSS style string for security.
*
* @param string $string
* @return string
*/
public function sanitize_style_value( $string ) {
if ( ! is_string( $string ) ) {
return $string;
}
// Remove all expression(...) (case-insensitive).
$string = preg_replace( '/expression\s*\((?:[^\(\)]|(?R))*\)/i', '', $string );

// Remove all javascript: URIs (case-insensitive).
$string = preg_replace( '/javascript\s*:/i', '', $string );

return $string;
}
}
}
5 changes: 5 additions & 0 deletions src/action-types/class-action-type-background-color.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public function initialize() {

// return parent::initilize_action( $action, $animation_data );
// }

public function sanitize_data_for_saving( $value ) {
$value['color'] = $this->sanitize_style_value( $value['color'] );
return $value;
}
Comment on lines +56 to +59
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard $value['color'] access to avoid notices on malformed data

As with the CSS rule action, the use of sanitize_style_value is appropriate, but directly indexing $value['color'] assumes structure that might not always hold (filters, bad data, etc.), leading to PHP warnings.

A small defensive tweak keeps behavior while hardening against bad input:

-		public function sanitize_data_for_saving( $value ) {
-			$value['color'] = $this->sanitize_style_value( $value['color'] );
-			return $value;
-		}
+		public function sanitize_data_for_saving( $value ) {
+			if ( is_array( $value ) && isset( $value['color'] ) ) {
+				$value['color'] = $this->sanitize_style_value( $value['color'] );
+			}
+
+			return $value;
+		}

This matches the defensive style used in other action types while preserving the new sanitization.

🤖 Prompt for AI Agents
In src/action-types/class-action-type-background-color.php around lines 56 to
59, the code directly indexes $value['color'] which can trigger PHP notices if
$value is not an array or lacks the 'color' key; update the method to
defensively check that $value is an array and that 'color' exists (e.g. isset or
array_key_exists) before passing it to sanitize_style_value, and ensure the
function returns a sensible default (unchanged $value or null) when the key is
absent to preserve behavior without emitting warnings.

}

interact_add_action_type( 'backgroundColor', 'Interact_Action_Type_Background_Color' );
Expand Down
5 changes: 5 additions & 0 deletions src/action-types/class-action-type-background-image.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public function initialize() {

$this->has_dynamic = false;
}

public function sanitize_data_for_saving( $value ) {
$value['image'] = $this->sanitize_style_value( $value['image'] );
return $value;
}
Comment on lines +37 to +40
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add null checks before accessing array keys.

Lines 38 accesses $value['image'] without verifying that $value is an array or that the key exists. This will generate PHP notices if the key is not present.

Apply this diff for consistency with other sanitization methods:

 	public function sanitize_data_for_saving( $value ) {
-		$value['image'] = $this->sanitize_style_value( $value['image'] );
+		if ( is_array( $value ) && isset( $value['image'] ) ) {
+			$value['image'] = $this->sanitize_style_value( $value['image'] );
+		}
 		return $value;
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public function sanitize_data_for_saving( $value ) {
$value['image'] = $this->sanitize_style_value( $value['image'] );
return $value;
}
public function sanitize_data_for_saving( $value ) {
if ( is_array( $value ) && isset( $value['image'] ) ) {
$value['image'] = $this->sanitize_style_value( $value['image'] );
}
return $value;
}
🤖 Prompt for AI Agents
In src/action-types/class-action-type-background-image.php around lines 37 to
40, add null/structure checks before accessing $value['image']; currently the
code accesses the key directly which can raise notices if $value is not an array
or the key is missing. Update the method to first verify that $value is an array
(or cast to one) and that the 'image' key exists (or use isset) before calling
$this->sanitize_style_value, e.g. return early if $value is not an array or
lacks 'image', otherwise sanitize $value['image'] and return the array; follow
the same pattern used by other sanitize methods for consistency.

}

interact_add_action_type( 'backgroundImage', 'Interact_Action_Type_Background_Image' );
Expand Down
5 changes: 5 additions & 0 deletions src/action-types/class-action-type-css-rule.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public function initialize() {
],
];
}

public function sanitize_data_for_saving( $value ) {
$value['value'] = $this->sanitize_style_value( $value['value'] );
return $value;
}
Comment on lines +44 to +47
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add defensive checks before accessing $value['value']

The sanitization logic is good, but accessing $value['value'] without checking its shape can trigger PHP notices if $value isn’t an array or the key is missing (e.g., corrupted data, custom filters).

To match the more defensive pattern used in other action types (e.g., text color, redirect), you can guard the access:

-		public function sanitize_data_for_saving( $value ) {
-			$value['value'] = $this->sanitize_style_value( $value['value'] );
-			return $value;
-		}
+		public function sanitize_data_for_saving( $value ) {
+			if ( is_array( $value ) && isset( $value['value'] ) ) {
+				$value['value'] = $this->sanitize_style_value( $value['value'] );
+			}
+
+			return $value;
+		}

This keeps the sanitization behavior while avoiding runtime warnings on unexpected input shapes.

🤖 Prompt for AI Agents
In src/action-types/class-action-type-css-rule.php around lines 44 to 47, the
code directly accesses $value['value'] which can trigger PHP notices if $value
is not an array or the key is missing; add defensive checks before accessing the
key (e.g., if not is_array($value) return $value as-is; if the 'value' key is
not set, either set it to a safe default or return $value unchanged), then only
call $this->sanitize_style_value($value['value']) when the key exists; finally
return the (possibly modified) $value.

}

interact_add_action_type( 'cssRule', 'Interact_Action_Type_Css_Rule' );
Expand Down
23 changes: 23 additions & 0 deletions src/action-types/class-action-type-display.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,29 @@ public function initialize() {
$this->has_duration = false;
$this->has_easing = false;
}

public function sanitize_data_for_saving( $value ) {
if ( is_array( $value ) && isset( $value['display'] ) ) {
$allowed_values = [
'block',
'none',
'inline',
'inline-block',
'flex',
'inline-flex',
'grid',
'inline-grid',
'initial',
'inherit',
'revert',
'unset',
];
if ( ! in_array( $value['display'], $allowed_values, true ) ) {
$value['display'] = 'block';
}
}
return $value;
}
}

interact_add_action_type( 'display', 'Interact_Action_Type_Display' );
Expand Down
15 changes: 15 additions & 0 deletions src/action-types/class-action-type-move.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ public function initialize() {

$this->has_dynamic = false;
}

public function sanitize_data_for_saving( $value ) {
// Ensure x, y, z are sanitized as numeric (including negatives and decimals), otherwise set to null (but leave blank as is)
foreach ( [ 'x', 'y', 'z' ] as $key ) {
if ( isset( $value[ $key ] ) && $value[ $key ] !== '' ) {
// Allow negative/positive/decimal
if ( is_numeric( $value[ $key ] ) ) {
$value[ $key ] = $value[ $key ] + 0; // Cast to int or float
} else {
$value[ $key ] = null;
}
}
}
return $value;
}
}

interact_add_action_type( 'move', 'Interact_Action_Type_Move' );
Expand Down
11 changes: 11 additions & 0 deletions src/action-types/class-action-type-opacity.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ public function initialize() {

$this->has_dynamic = false;
}

public function sanitize_data_for_saving( $value ) {
if ( is_array( $value ) && isset( $value['opacity'] ) ) {
if ( is_numeric( $value['opacity'] ) ) {
$value['opacity'] = $value['opacity'] + 0;
} else {
$value['opacity'] = null;
}
}
return $value;
}
}

interact_add_action_type( 'opacity', 'Interact_Action_Type_Opacity' );
Expand Down
11 changes: 11 additions & 0 deletions src/action-types/class-action-type-redirect-to-url.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ public function initialize() {
$this->has_easing = false;
$this->has_preview = false;
}

public function sanitize_data_for_saving( $value ) {
if ( is_array( $value ) && isset( $value['url'] ) ) {
if ( is_string( $value['url'] ) ) {
$value['url'] = esc_url( $value['url'] );
} else {
$value['url'] = null;
}
}
return $value;
}
}

interact_add_action_type( 'redirectToUrl', 'Interact_Action_Type_Redirect_To_Url' );
Expand Down
31 changes: 31 additions & 0 deletions src/action-types/class-action-type-rotate.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,37 @@ public function initialize() {

$this->has_dynamic = false;
}

public function sanitize_data_for_saving( $value ) {
if ( is_array( $value ) && isset( $value['rotate'] ) ) {
if ( is_numeric( $value['rotate'] ) ) {
$value['rotate'] = $value['rotate'] + 0;
} else {
$value['rotate'] = null;
}
}

if ( is_array( $value ) && isset( $value['transformOrigin'] ) ) {
$allowed_transform_origins = [
'center',
'top',
'right',
'bottom',
'left',
'top left',
'top right',
'bottom left',
'bottom right',
'custom',
];
if ( ! in_array( $value['transformOrigin'], $allowed_transform_origins, true ) ) {
$value['transformOrigin'] = 'center';
}
}

$value['customTransformOrigin'] = $this->sanitize_style_value( $value['customTransformOrigin'] );
return $value;
}
Comment on lines +67 to +96
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add null check before accessing array key.

Line 94 accesses $value['customTransformOrigin'] without verifying the key exists. This will generate a PHP notice if the key is not present.

Apply this diff to add the check:

 		if ( is_array( $value ) && isset( $value['transformOrigin'] ) ) {
 			$allowed_transform_origins = [
 				'center',
 				'top',
 				'right',
 				'bottom',
 				'left',
 				'top left',
 				'top right',
 				'bottom left',
 				'bottom right',
 				'custom',
 			];
 			if ( ! in_array( $value['transformOrigin'], $allowed_transform_origins, true ) ) {
 				$value['transformOrigin'] = 'center';
 			}
 		}
 
-		$value['customTransformOrigin'] = $this->sanitize_style_value( $value['customTransformOrigin'] );
+		if ( isset( $value['customTransformOrigin'] ) ) {
+			$value['customTransformOrigin'] = $this->sanitize_style_value( $value['customTransformOrigin'] );
+		}
 		return $value;
🤖 Prompt for AI Agents
In src/action-types/class-action-type-rotate.php around lines 67 to 96, the code
accesses $value['customTransformOrigin'] on line 94 without verifying the key
exists; update the logic to check that $value is an array and that the
'customTransformOrigin' key exists (use isset or array_key_exists) before
calling $this->sanitize_style_value on it, and if the key is missing set
$value['customTransformOrigin'] to null (or a safe default) so no PHP notice is
raised.

}

interact_add_action_type( 'rotate', 'Interact_Action_Type_Rotate' );
Expand Down
18 changes: 18 additions & 0 deletions src/action-types/class-action-type-scale.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,24 @@ public function initialize() {

$this->has_dynamic = false;
}

public function sanitize_data_for_saving( $value ) {
if ( is_array( $value ) && isset( $value['x'] ) ) {
if ( is_numeric( $value['x'] ) ) {
$value['x'] = $value['x'] + 0;
} else {
$value['x'] = null;
}
}
if ( is_array( $value ) && isset( $value['y'] ) ) {
if ( is_numeric( $value['y'] ) ) {
$value['y'] = $value['y'] + 0;
} else {
$value['y'] = null;
}
}
return $value;
}
}

interact_add_action_type( 'scale', 'Interact_Action_Type_Scale' );
Expand Down
Loading