Skip to content

Merge main into trunk#151

Closed
RCheesley wants to merge 31 commits intotrunkfrom
main
Closed

Merge main into trunk#151
RCheesley wants to merge 31 commits intotrunkfrom
main

Conversation

@RCheesley
Copy link
Member

No description provided.

DogByteMarketing and others added 30 commits May 28, 2025 00:40
Updated: Distignore to exclude additional development files
Updated: Readme version and also pulled the latest trunk readme
Added: Contributor
Removed: Deprecated plugin version header
Updated: Tests to use new Utils\Options class
Updated: Readme version
Added: Translation file wp-mautic.pot to make generating translations easier
Updated: Exception punctuation
Bugfix: console.warn triggering error
Removed: Duplicate distignore entry.
Updated: Shortcode init method tabbing
Updated: Spelling for wpmautic_focus_shortcode method comment
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Updated: Version
Copilot AI review requested due to automatic review settings February 26, 2026 17:14
@RCheesley RCheesley closed this Feb 26, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR represents a major architectural refactoring of the WP Mautic plugin, migrating from a procedural, function-based codebase to an object-oriented structure with PSR-4 namespacing and Composer autoloading. The plugin version is bumped from 2.4.3 to 2.5.1, with WordPress compatibility updated to 6.8.

Changes:

  • Refactored entire codebase from procedural functions to OOP classes with Mautic\WP_Mautic namespace
  • Introduced Composer autoloading with PSR-4 standard
  • Restructured code into logical class hierarchy (Backend, Frontend, Utils)
  • Updated tracking image fallback from boolean to tri-state string option ('0', '1', '2')
  • Added new contributor and updated version information

Reviewed changes

Copilot reviewed 17 out of 30 changed files in this pull request and generated 20 comments.

Show a summary per file
File Description
wpmautic.php Main plugin file refactored to use namespace and minimal bootstrap code
includes/classes/* New OOP class structure for dependency loading, frontend/backend functionality
vendor/composer/* Generated Composer autoloader files for PSR-4 autoloading
vendor/autoload.php Composer autoloader entry point
tests/OptionsTest.php Updated tests to use new Options::get() static method
shortcodes.php Removed (functionality moved to Frontend/Shortcodes class)
options.php Removed (functionality moved to Backend/Admin class)
readme.txt Updated version, WordPress compatibility, and contributor information
languages/wp-mautic.pot Generated translation template with new string references
composer.json Added PSR-4 autoload configuration
.gitignore Modified to include vendor/composer directory in version control
.github/workflows/* Removed dry-run flags to enable actual deployments
.distignore Expanded to exclude development dependencies from distribution

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +9 to +43
/**
* Retrieve one of the wpmautic options but sanitized
*
* @param string $option Option name to be retrieved (base_url, script_location).
* @param mixed $default Default option value return if not exists.
*
* @return string
*
* @throws InvalidArgumentException Thrown when the option name is not given.
*/
public static function get( $option, $default = null ) {
$options = get_option( 'wpmautic_options' );

switch ( $option ) {
case 'script_location':
return ! isset( $options[ $option ] ) ? 'header' : $options[ $option ];

case 'fallback_activated':
// Return saved value or default to '0' (Disabled)
return isset( $options[ $option ] ) ? $options[ $option ] : '0';

case 'track_logged_user':
return isset( $options[ $option ] ) ? (bool) $options[ $option ] : false;

default:
if ( ! isset( $options[ $option ] ) ) {
if ( isset( $default ) ) {
return $default;
}

throw new InvalidArgumentException( __('You must give a valid option name!', 'wp-mautic') );
}
return $options[ $option ];
}
}
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

Inconsistent indentation: This class uses 2-space indentation instead of tabs as required by WordPress Coding Standards. All methods and properties should be reformatted to use tabs for consistency.

Suggested change
/**
* Retrieve one of the wpmautic options but sanitized
*
* @param string $option Option name to be retrieved (base_url, script_location).
* @param mixed $default Default option value return if not exists.
*
* @return string
*
* @throws InvalidArgumentException Thrown when the option name is not given.
*/
public static function get( $option, $default = null ) {
$options = get_option( 'wpmautic_options' );
switch ( $option ) {
case 'script_location':
return ! isset( $options[ $option ] ) ? 'header' : $options[ $option ];
case 'fallback_activated':
// Return saved value or default to '0' (Disabled)
return isset( $options[ $option ] ) ? $options[ $option ] : '0';
case 'track_logged_user':
return isset( $options[ $option ] ) ? (bool) $options[ $option ] : false;
default:
if ( ! isset( $options[ $option ] ) ) {
if ( isset( $default ) ) {
return $default;
}
throw new InvalidArgumentException( __('You must give a valid option name!', 'wp-mautic') );
}
return $options[ $option ];
}
}
/**
* Retrieve one of the wpmautic options but sanitized
*
* @param string $option Option name to be retrieved (base_url, script_location).
* @param mixed $default Default option value return if not exists.
*
* @return string
*
* @throws InvalidArgumentException Thrown when the option name is not given.
*/
public static function get( $option, $default = null ) {
$options = get_option( 'wpmautic_options' );
switch ( $option ) {
case 'script_location':
return ! isset( $options[ $option ] ) ? 'header' : $options[ $option ];
case 'fallback_activated':
// Return saved value or default to '0' (Disabled)
return isset( $options[ $option ] ) ? $options[ $option ] : '0';
case 'track_logged_user':
return isset( $options[ $option ] ) ? (bool) $options[ $option ] : false;
default:
if ( ! isset( $options[ $option ] ) ) {
if ( isset( $default ) ) {
return $default;
}
throw new InvalidArgumentException( __('You must give a valid option name!', 'wp-mautic') );
}
return $options[ $option ];
}
}

Copilot uses AI. Check for mistakes.
}

return '<script type="text/javascript" ' . sprintf(
'src="%s/form/generate.js?id=%s"',
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The async attribute has been removed from the form embed script tag. Line 83 in the new code no longer includes 'async' while the old shortcodes.php had 'async' in the script tag. This change could impact page load performance as the script will now block rendering. Consider whether this was intentional or if the async attribute should be preserved.

Suggested change
'src="%s/form/generate.js?id=%s"',
'src="%s/form/generate.js?id=%s" async',

Copilot uses AI. Check for mistakes.
# Steps can also provide arguments, so this configures 10up's action to also generate a zip file.
with:
dry-run: true
generate-zip: true
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The removal of 'dry-run: true' from the deployment workflow means that deployments will now actually execute instead of being simulated. This is a significant operational change that could lead to unintended deployments if this workflow is triggered accidentally. Ensure that proper branch protection rules and approval processes are in place before merging this change.

Suggested change
generate-zip: true
generate-zip: true
dry-run: true

Copilot uses AI. Check for mistakes.
@@ -11,8 +11,6 @@ jobs:
- uses: actions/checkout@master
- name: WordPress.org plugin asset/readme update
uses: 10up/action-wordpress-plugin-asset-update@stable
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The removal of 'dry-run: true' from the asset update workflow means that asset updates will now actually be pushed to WordPress.org instead of being simulated. This operational change should be carefully coordinated to ensure it doesn't cause unintended updates to the WordPress.org plugin repository.

Suggested change
uses: 10up/action-wordpress-plugin-asset-update@stable
uses: 10up/action-wordpress-plugin-asset-update@stable
with:
dry-run: true

Copilot uses AI. Check for mistakes.
Comment on lines +33 to +53


/**
* Init
*
* @return void
*/
public function init() {
$this->load_dependencies();
}

/**
* Load dependencies
*
* @return void
*/
public function load_dependencies() {
$dependency_loader = new Dependency_Loader();
$dependency_loader->init();
}

Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

Inconsistent indentation: This class uses 2-space indentation for methods and properties, while WordPress Coding Standards require tabs or 4-space indentation. All methods in this class (lines 35-52) should follow the same indentation standard used throughout the WordPress ecosystem.

Suggested change
/**
* Init
*
* @return void
*/
public function init() {
$this->load_dependencies();
}
/**
* Load dependencies
*
* @return void
*/
public function load_dependencies() {
$dependency_loader = new Dependency_Loader();
$dependency_loader->init();
}
/**
* Init
*
* @return void
*/
public function init() {
$this->load_dependencies();
}
/**
* Load dependencies
*
* @return void
*/
public function load_dependencies() {
$dependency_loader = new Dependency_Loader();
$dependency_loader->init();
}

Copilot uses AI. Check for mistakes.
Comment on lines +27 to +29
// Return saved value or default to '0' (Disabled)
return isset( $options[ $option ] ) ? $options[ $option ] : '0';

Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The return type and behavior of the fallback_activated option has changed from boolean to string without proper migration handling. Previously, this returned true/false (line 27 in old code returned boolean), but now returns string '0', '1', or '2'. This breaking change could cause issues for existing users who have boolean values stored in their database. A migration strategy should be implemented to convert existing boolean values to the new string format.

Suggested change
// Return saved value or default to '0' (Disabled)
return isset( $options[ $option ] ) ? $options[ $option ] : '0';
// Normalize and migrate legacy values to string representation ('0', '1', or '2').
$value = isset( $options[ $option ] ) ? $options[ $option ] : null;
// Handle legacy boolean values (from older versions) and normalize to strings.
if ( is_bool( $value ) ) {
$value = $value ? '1' : '0';
$options[ $option ] = $value;
update_option( 'wpmautic_options', $options );
} elseif ( $value === 'true' || $value === 'false' ) {
// Handle possible stringified booleans from legacy storage.
$value = ( $value === 'true' ) ? '1' : '0';
$options[ $option ] = $value;
update_option( 'wpmautic_options', $options );
}
// Ensure the value is one of the expected string states; default to '0' if not.
if ( $value === null || ! in_array( (string) $value, array( '0', '1', '2' ), true ) ) {
$value = '0';
$options[ $option ] = $value;
update_option( 'wpmautic_options', $options );
}
return $value;

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +222
class Enqueue {

/**
* Init
*
* @return void
*/
public function init() {
$this->enqueue();
}

/**
* Enqueue scripts and styles
*
* @return void
*/
public function enqueue() {
$this->enqueue_scripts();
}

/**
* Enqueue scripts
*
* @return void
*/
public function enqueue_scripts() {
$script_location = Options::get( 'script_location' );
$fallback = Options::get( 'fallback_activated', false );

if ('0' === $fallback || '1' === $fallback) {
if ( 'header' === $script_location ) {
add_action( 'wp_head', array( $this, 'wpmautic_inject_script' ) );
} else {
add_action( 'wp_footer', array( $this, 'wpmautic_inject_script' ) );
}

if ( 'disabled' !== $script_location && '1' === $fallback ) {
add_action( 'wp_footer', array( $this, 'wpmautic_inject_noscript' ) );
}
} elseif ('2' === $fallback) {
add_action( 'wp_footer', array( $this, 'wpmautic_inject_tracking_pixel' ) );
}
}

/**
* Writes Tracking JS to the HTML source
*
* @return void
*/
public function wpmautic_inject_script() {
// Load the Mautic tracking library mtc.js if it is not disabled.
$base_url = $this->wpmautic_base_script();
$script_location = Options::get( 'script_location' );
$attrs = $this->wpmautic_get_tracking_attributes();
?>
<script type="text/javascript" >
function wpmautic_send(){
if ('undefined' === typeof mt) {
if (console !== undefined) {
console.warn('<?php echo esc_js( __( 'WPMautic: mt not defined. Did you load mtc.js?', 'wp-mautic' ) ); ?>');
}
return false;
}
// Add the mt('send', 'pageview') script with optional tracking attributes.
mt('send', 'pageview'<?php echo count( $attrs ) > 0 ? ', ' . wp_json_encode( $attrs ) : ''; ?>);
}

<?php
// Mautic is not configured, or user disabled automatic tracking on page load (GDPR).
if ( ! empty( $base_url ) && 'disabled' !== $script_location ) :
?>
(function(w,d,t,u,n,a,m){w['MauticTrackingObject']=n;
w[n]=w[n]||function(){(w[n].q=w[n].q||[]).push(arguments)},a=d.createElement(t),
m=d.getElementsByTagName(t)[0];a.async=1;a.src=u;m.parentNode.insertBefore(a,m)
})(window,document,'script','<?php echo esc_url( $base_url ); ?>','mt');

wpmautic_send();
<?php
endif;
?>
</script>
<?php
}

/**
* Writes Tracking image fallback to the HTML source
* This is a separated function because <noscript> tags are not allowed in header !
*
* @return void
*/
public function wpmautic_inject_noscript() {
$base_url = Options::get( 'base_url', '' );
if ( empty( $base_url ) ) {
return;
}

$url_query = $this->wpmautic_get_url_query();
$payload = rawurlencode( base64_encode( serialize( $url_query ) ) );
?>
<noscript>
<img src="<?php echo esc_url( $base_url ); ?>/mtracking.gif?d=<?php echo esc_attr( $payload ); ?>" style="display:none;" alt="<?php echo esc_attr__( 'Mautic Tags', 'wp-mautic' ); ?>" />
</noscript>
<?php
}

/**
* Writes Tracking image fallback to the HTML source
* This is a separated function because <noscript> tags are not allowed in header !
*
* @return void
*/
public function wpmautic_inject_tracking_pixel() {
$base_url = Options::get( 'base_url', '' );
if ( empty( $base_url ) ) {
return;
}

$url_query = $this->wpmautic_get_url_query();
$payload = rawurlencode( base64_encode( serialize( $url_query ) ) );
?>
<img src="<?php echo esc_url( $base_url ); ?>/mtracking.gif?d=<?php echo esc_attr( $payload ); ?>" style="display:none;" alt="<?php echo esc_attr__( 'Mautic Tags', 'wp-mautic' ); ?>" />
<?php
}

/**
* Generate the mautic script URL to be used outside of the plugin when
* necessary
*
* @return string
*/
private function wpmautic_base_script() {
$base_url = Options::get( 'base_url', '' );
if ( empty( $base_url ) ) {
return;
}

return $base_url . '/mtc.js';
}

/**
* Builds and returns additional data for URL query
*
* @return array
*/
private function wpmautic_get_url_query() {
global $wp;
$current_url = add_query_arg( $wp->query_string, '', home_url( $wp->request ) );

$attrs = $this->wpmautic_get_tracking_attributes();

$attrs['language'] = get_locale();
$attrs['page_url'] = $current_url;
$attrs['page_title'] = function_exists( 'wp_get_document_title' )
? wp_get_document_title()
: wp_title( '&raquo;', false );
$attrs['referrer'] = function_exists( 'wp_get_raw_referer' )
? wp_get_raw_referer()
: null;
if ( false === $attrs['referrer'] ) {
$attrs['referrer'] = $current_url;
}

return $attrs;
}

/**
* Create custom query parameters to be injected inside tracking
*
* @return array
*/
private function wpmautic_get_tracking_attributes() {
$attrs = $this->wpmautic_get_user_query();

/**
* Update / add data to be sent within Mautic tracker
*
* Default data only contains the 'language' key but every added key to the
* array will be sent to Mautic.
*
* @since 2.1.0
*
* @param array $attrs Attributes to be filters, default ['language' => get_locale()]
*/
return apply_filters( 'wpmautic_tracking_attributes', $attrs );
}

/**
* Extract logged user information to be sent within Mautic tracker
*
* @return array
*/
private function wpmautic_get_user_query() {
$attrs = array();

if (
true === Options::get( 'track_logged_user', false ) &&
is_user_logged_in()
) {
$current_user = wp_get_current_user();
$attrs['email'] = $current_user->user_email;
$attrs['firstname'] = $current_user->user_firstname;
$attrs['lastname'] = $current_user->user_lastname;

// Following Mautic fields has to be created manually and the fields must match these names.
$attrs['wp_user'] = $current_user->user_login;
$attrs['wp_alias'] = $current_user->display_name;
$attrs['wp_registration_date'] = date(
'Y-m-d',
strtotime( $current_user->user_registered )
);
}

return $attrs;
}

} No newline at end of file
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

Inconsistent indentation throughout the class: This class uses 2-space indentation instead of the WordPress Coding Standards requirement of tabs or 4 spaces. All methods and properties (lines 9-221) should be reformatted to follow WordPress indentation standards for consistency with the WordPress ecosystem.

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +237
class Shortcodes {

/**
* Init
*
* @return void
*/
public function init() {
add_shortcode('mautic', array($this, 'wpmautic_shortcode'));

// Backward compatibilities.
add_shortcode('mauticcontent', array($this, 'wpmautic_dwc_shortcode'));
add_shortcode('mauticvideo', array($this, 'wpmautic_video_shortcode'));
add_shortcode('mauticform', array($this, 'wpmautic_form_shortcode'));
add_shortcode('mautictags', array($this, 'wpmautic_tags_shortcode'));
add_shortcode('mauticfocus', array($this, 'wpmautic_focus_shortcode'));
}

/**
* Handle mautic shortcode. Must include a type attribute.
*
* @param array $atts Shortcode attributes.
* @param string|null $content Default content to be displayed.
*
* @return string
*/
public function wpmautic_shortcode( $atts, $content = null ) {
$default = shortcode_atts(
array(
'type' => null,
),
$atts
);

switch ( $default['type'] ) {
case 'form':
return $this->wpmautic_form_shortcode( $atts );
case 'content':
return $this->wpmautic_dwc_shortcode( $atts, $content );
case 'video':
return $this->wpmautic_video_shortcode( $atts );
case 'tags':
return $this->wpmautic_tags_shortcode( $atts );
case 'focus':
return $this->wpmautic_focus_shortcode( $atts );
}

return false;
}

/**
* Handle mauticform shortcode
* example: [mautic type="form" id="1"]
*
* @param array $atts Shortcode attributes.
*
* @return string
*/
public function wpmautic_form_shortcode( $atts ) {
$base_url = Options::get( 'base_url', '' );
if ( '' === $base_url ) {
return false;
}

$atts = shortcode_atts(
array(
'id' => '',
),
$atts
);

if ( empty( $atts['id'] ) ) {
return false;
}

return '<script type="text/javascript" ' . sprintf(
'src="%s/form/generate.js?id=%s"',
esc_url( $base_url ),
esc_attr( $atts['id'] )
) . '></script>';
}

/**
* Dynamic content shortcode handling
* example: [mautic type="content" slot="slot_name"]Default Content[/mautic]
*
* @param array $atts Shortcode attributes.
* @param string|null $content Default content to be displayed.
*
* @return string
*/
public function wpmautic_dwc_shortcode( $atts, $content = null ) {
$atts = shortcode_atts(
array(
'slot' => '',
),
$atts,
'mautic'
);

return sprintf(
'<div class="mautic-slot" data-slot-name="%s">%s</div>',
esc_attr( $atts['slot'] ),
wp_kses( $content, wp_kses_allowed_html( 'post' ) )
);
}

/**
* Video shortcode handling
* example: [mautic type="video" gate-time="15" form-id="1" src="https://www.youtube.com/watch?v=QT6169rdMdk"]
*
* @param array $atts Shortcode attributes.
*
* @return string
*/
public function wpmautic_video_shortcode( $atts ) {
$atts = shortcode_atts(
array(
'gate-time' => 15,
'form-id' => '',
'src' => '',
'video-type' => '',
'mautic-video' => 'true',
'width' => 640,
'height' => 360,
),
$atts
);

if ( empty( $atts['src'] ) ) {
return __( 'You must provide a video source. Add a src="URL" attribute to your shortcode. Replace URL with the source url for your video.', 'wp-mautic' );
}

if ( empty( $atts['form-id'] ) && 'true' !== $atts['mautic-video'] ) {
return __( 'You must provide a mautic form id. Add a form-id="#" attribute to your shortcode. Replace # with the id of the form you want to use.', 'wp-mautic' );
}

if ( preg_match( '/^.*((youtu.be)|(youtube.com))\/((v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))?\??v?=?([^#\&\?]*).*/', $atts['src'] ) ) {
$atts['video-type'] = 'youtube';
}
if ( preg_match( '/^.*(vimeo\.com\/)((channels\/[A-z]+\/)|(groups\/[A-z]+\/videos\/))?([0-9]+)/', $atts['src'] ) ) {
$atts['video-type'] = 'vimeo';
}
if ( strtolower( substr( $atts['src'], -3 ) ) === 'mp4' ) {
$atts['video-type'] = 'mp4';
}

if ( empty( $atts['video-type'] ) ) {
return __( 'Please define a valid video type with video-type="#".', 'wp-mautic' );
}

return sprintf(
'<video height="%1$s" width="%2$s"' . ( empty( $atts['form-id'] ) ? '' : ' data-form-id="%3$s"' ) . ' data-gate-time="%4$s" data-mautic-video="%5$s">' .
'<source type="video/%6$s" src="%7$s" />' .
'</video>',
esc_attr( $atts['height'] ),
esc_attr( $atts['width'] ),
esc_attr( $atts['form-id'] ),
esc_attr( $atts['gate-time'] ),
esc_attr( $atts['mautic-video'] ),
esc_attr( $atts['video-type'] ),
esc_attr( $atts['src'] )
);
}

/**
* Handle mautic tags by WordPress shortcodes
* example: [mautic type="tags" values="addtag,-removetag"]
*
* @param array $atts Shortcode attributes.
*
* @return string
*/
public function wpmautic_tags_shortcode( $atts ) {
$base_url = Options::get( 'base_url', '' );
if ( '' === $base_url ) {
return false;
}

$atts = shortcode_atts(
array(
'values' => '',
),
$atts
);

if ( empty( $atts['values'] ) ) {
return false;
}

return sprintf(
'<img src="%s/mtracking.gif?tags=%s" alt="%s" style="display:none;" />',
esc_url( $base_url ),
esc_attr( $atts['values'] ),
esc_attr__( 'Mautic Tags', 'wp-mautic' )
);
}

/**
* Handle mautic focus items on WordPress Page
* example: [mautic type="focus" id="1"]
*
* @param array $atts Shortcode attributes.
*
* @return string
*/
public function wpmautic_focus_shortcode( $atts ) {
$base_url = Options::get( 'base_url', '' );
if ( '' === $base_url ) {
return false;
}

$atts = shortcode_atts(
array(
'id' => '',
),
$atts
);

if ( empty( $atts['id'] ) ) {
return false;
}

return '<script type="text/javascript" ' . sprintf(
'src="%s/focus/%s.js"',
esc_url( $base_url ),
esc_attr( $atts['id'] )
) . ' async="async"></script>';
}

} No newline at end of file
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

Inconsistent indentation throughout the class: This class uses 2-space indentation instead of tabs or 4 spaces as required by WordPress Coding Standards. All methods and properties should be reformatted to follow WordPress indentation conventions for consistency.

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +296
class Admin {

/**
* Init
*
* @return void
*/
public function init() {
add_action('admin_menu', array($this, 'wpmautic_settings'));
add_action('admin_init', array($this, 'wpmautic_admin_init'));
add_filter('plugin_action_links_' . plugin_basename(VPMAUTIC_PLUGIN_FILE), array($this, 'wpmautic_plugin_actions'), 10, 2);
}

/**
* Declare option page
*/
public function wpmautic_settings() {
add_options_page(
__( 'WP Mautic Settings', 'wp-mautic' ),
__( 'WPMautic', 'wp-mautic' ),
'manage_options',
'wpmautic',
array($this, 'wpmautic_options_page')
);
}

/**
* HTML for the Mautic option page
*/
public function wpmautic_options_page() {
?>
<div>
<h2><?php esc_html_e( 'WP Mautic', 'wp-mautic' ); ?></h2>
<p><?php esc_html_e( 'Add Mautic tracking capabilities to your website.', 'wp-mautic' ); ?></p>
<form action="options.php" method="post">
<?php settings_fields( 'wpmautic' ); ?>
<?php do_settings_sections( 'wpmautic' ); ?>
<?php submit_button(); ?>
</form>
<h3><?php esc_html_e( 'Shortcode Examples:', 'wp-mautic' ); ?></h3>
<ul>
<li><?php esc_html_e( 'Mautic Form Embed:', 'wp-mautic' ); ?> <code>[mautic type="form" id="1"]</code></li>
<li><?php esc_html_e( 'Mautic Dynamic Content:', 'wp-mautic' ); ?> <code>[mautic type="content" slot="slot_name"]<?php esc_html_e( 'Default Text', 'wp-mautic' ); ?>[/mautic]</code></li>
</ul>
<h3><?php esc_html_e( 'Quick Links', 'wp-mautic' ); ?></h3>
<ul>
<li>
<a href="https://github.com/mautic/mautic-wordpress#mautic-wordpress-plugin" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Plugin docs', 'wp-mautic' ); ?></a>
</li>
<li>
<a href="https://github.com/mautic/mautic-wordpress/issues" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Plugin support', 'wp-mautic' ); ?></a>
</li>
<li>
<a href="https://mautic.org" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Mautic project', 'wp-mautic' ); ?></a>
</li>
<li>
<a href="http://docs.mautic.org/" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Mautic docs', 'wp-mautic' ); ?></a>
</li>
<li>
<a href="https://www.mautic.org/community/" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Mautic forum', 'wp-mautic' ); ?></a>
</li>
</ul>
</div>
<?php
}


/**
* Define admin_init hook logic
*/
public function wpmautic_admin_init() {
register_setting( 'wpmautic', 'wpmautic_options', array($this, 'wpmautic_options_validate') );

add_settings_section(
'wpmautic_main',
__( 'Main Settings', 'wp-mautic' ),
array($this, 'wpmautic_section_text'),
'wpmautic'
);

add_settings_field(
'wpmautic_base_url',
__( 'Mautic URL', 'wp-mautic' ),
array($this, 'wpmautic_base_url'),
'wpmautic',
'wpmautic_main'
);
add_settings_field(
'wpmautic_script_location',
__( 'Tracking script location', 'wp-mautic' ),
array($this, 'wpmautic_script_location'),
'wpmautic',
'wpmautic_main'
);
add_settings_field(
'wpmautic_fallback_activated',
__( 'Tracking image', 'wp-mautic' ),
array($this, 'wpmautic_fallback_activated'),
'wpmautic',
'wpmautic_main'
);
add_settings_field(
'wpmautic_track_logged_user',
__( 'Logged user', 'wp-mautic' ),
array($this, 'wpmautic_track_logged_user'),
'wpmautic',
'wpmautic_main'
);
}

/**
* Section text
*/
public function wpmautic_section_text() {
}

/**
* Define the input field for Mautic base URL
*/
public function wpmautic_base_url() {
$url = Options::get( 'base_url', '' );

?>
<input
id="wpmautic_base_url"
name="wpmautic_options[base_url]"
size="40"
type="text"
placeholder="https://..."
value="<?php echo esc_url_raw( $url, array( 'http', 'https' ) ); ?>"
/>
<?php
}

/**
* Define the input field for Mautic script location
*/
public function wpmautic_script_location() {
$position = Options::get( 'script_location', '' );
$allowed_tags = array(
'br' => array(),
'code' => array(),
);

?>
<fieldset id="wpmautic_script_location">
<label>
<input
type="radio"
name="wpmautic_options[script_location]"
value="header"
<?php
if ( 'footer' !== $position && 'disabled' !== $position ) :
?>
checked<?php endif; ?>
/>
<?php echo wp_kses( __( 'Added in the <code>wp_head</code> action.<br/>Inserts the tracking code before the <code>&lt;head&gt;</code> tag; can be slightly slower since page load is delayed until all scripts in <code><head></code> are loaded and processed.', 'wp-mautic' ), $allowed_tags ); ?>
</label>
<br/>
<label>
<input
type="radio"
name="wpmautic_options[script_location]"
value="footer"
<?php
if ( 'footer' === $position ) :
?>
checked<?php endif; ?>
/>
<?php echo wp_kses( __( 'Embedded within the <code>wp_footer</code> action.<br/>Inserts the tracking code before the <code>&lt;/body&gt;</code> tag; slightly better for performance but may track less reliably if users close the page before the script has loaded.', 'wp-mautic' ), $allowed_tags ); ?>
</label>
<br />
<label>
<input
type="radio"
name="wpmautic_options[script_location]"
value="disabled"
<?php
if ( 'disabled' === $position ) :
?>
checked<?php endif; ?>
/>
<?php echo wp_kses( __( 'Visitor will not be tracked when rendering the page. Use this option to comply with GDPR regulations. If the visitor accept cookies you must execute the <code>wpmautic_send()</code> JavaScript function to start tracking.', 'wp-mautic' ), $allowed_tags ); ?>
<br/>
<?php echo wp_kses( __( 'However when using shortcodes, a tracking cookie will be added everytime even when tracking is disabled. This is because loading a Mautic resource (javascript or image) generate that cookie.', 'wp-mautic' ), $allowed_tags ); ?>
</label>
</fieldset>
<?php
}


/**
* Define the input field for Mautic fallback flag
*/
public function wpmautic_fallback_activated() {
$flag = Options::get( 'fallback_activated', false );
$allowed_tags = array(
'br' => array(),
'code' => array(),
);

?>
<select id="wpmautic_fallback_activated" name="wpmautic_options[fallback_activated]">
<option value="0" <?php selected( $flag, '0' ); ?>><?php esc_html_e( 'Disabled', 'wp-mautic' ); ?></option>
<option value="1" <?php selected( $flag, '1' ); ?>><?php esc_html_e( 'Only When JavaScript is Disabled', 'wp-mautic' ); ?></option>
<option value="2" <?php selected( $flag, '2' ); ?>><?php esc_html_e( 'Replace mtc.js', 'wp-mautic' ); ?></option>
</select>
<br />
<label for="wpmautic_fallback_activated">
<?php echo wp_kses( __( 'Use "Replace mtc.js" if you want to use the tracking pixel as the default and only way to track even if JavaScript is enabled/disabled.', 'wp-mautic' ), $allowed_tags ); ?>
<br />
<?php echo wp_kses( __( 'Be warned, that the tracking image will always generate a cookie on the user browser side. If you want to control cookies and comply to GDPR, you must use JavaScript instead.', 'wp-mautic' ), $allowed_tags ); ?>
</label>
<?php
}

/**
* Define the input field for Mautic logged user tracking flag
*/
public function wpmautic_track_logged_user() {
$flag = Options::get( 'track_logged_user', false );

?>
<input
id="wpmautic_track_logged_user"
name="wpmautic_options[track_logged_user]"
type="checkbox"
value="1"
<?php
if ( true === $flag ) :
?>
checked<?php endif; ?>
/>
<label for="wpmautic_track_logged_user">
<?php esc_html_e( 'Track user information for logged-in users', 'wp-mautic' ); ?>
</label>
<?php
}

/**
* Validate base URL input value
*
* @param array $input Input data.
* @return array
*/
public function wpmautic_options_validate( $input ) {
$options = get_option( 'wpmautic_options' );

$input['base_url'] = isset( $input['base_url'] )
? trim( $input['base_url'], " \t\n\r\0\x0B/" )
: '';

$options['base_url'] = esc_url_raw( trim( $input['base_url'], " \t\n\r\0\x0B/" ) );
$options['script_location'] = isset( $input['script_location'] )
? trim( $input['script_location'] )
: 'header';
if ( ! in_array( $options['script_location'], array( 'header', 'footer', 'disabled' ), true ) ) {
$options['script_location'] = 'header';
}

if ( isset( $input['fallback_activated'] ) && in_array( $input['fallback_activated'], array( '0', '1', '2' ), true ) ) {
$options['fallback_activated'] = sanitize_text_field($input['fallback_activated']);
} else {
$options['fallback_activated'] = '0'; // Default to disabled
}

return $options;
}

/**
* Settings Link in the ``Installed Plugins`` page
*
* @param array $links array of plugin action links.
*
* @return array
*/
public function wpmautic_plugin_actions( $links ) {
if ( function_exists( 'admin_url' ) ) {
$settings_link = sprintf(
'<a href="%s">%s</a>',
admin_url( 'options-general.php?page=wpmautic' ),
__( 'Settings', 'wp-mautic' )
);
// Add the settings link before other links.
array_unshift( $links, $settings_link );
}
return $links;
}

} No newline at end of file
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

Inconsistent indentation: The class uses mixed indentation with both tabs and spaces. Lines 15-17 use tabs, while other parts use 2-space indentation. WordPress Coding Standards require consistent use of tabs for indentation. The entire class should be reformatted to use tabs consistently.

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +26

/**
* Init
*
* @return void
*/
public function init() {
$this->load_admin();
}

/**
* Load Admin
*
* @return void
*/
public function load_admin() {
$admin = new Admin();
$admin->init();
}
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

Inconsistent indentation: This class uses 2-space indentation instead of tabs as required by WordPress Coding Standards. All methods and properties should be reformatted to use tabs for consistency.

Suggested change
/**
* Init
*
* @return void
*/
public function init() {
$this->load_admin();
}
/**
* Load Admin
*
* @return void
*/
public function load_admin() {
$admin = new Admin();
$admin->init();
}
/**
* Init
*
* @return void
*/
public function init() {
$this->load_admin();
}
/**
* Load Admin
*
* @return void
*/
public function load_admin() {
$admin = new Admin();
$admin->init();
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants