Add GitHub Updater support, fix bugs, and add EDD license tracking#1
Open
zackkatz wants to merge 31 commits intocode-atlantic:masterfrom
Open
Add GitHub Updater support, fix bugs, and add EDD license tracking#1zackkatz wants to merge 31 commits intocode-atlantic:masterfrom
zackkatz wants to merge 31 commits intocode-atlantic:masterfrom
Conversation
Add `GitHub Plugin URI` and `Primary Branch` headers to enable automatic plugin updates via the Git Updater plugin. Also fill in missing plugin metadata (Description, Version, License, Requires PHP, Requires at least) and correct the Plugin URI to point to the current repository.
The classmap autoload entry references the vendor-prefixed directory, but the directory wasn't tracked in git, causing composer to fail with "Could not scan for classes inside vendor-prefixed". Track the directory via .gitkeep so it exists on fresh clones.
…e methods The register() method hooked camelCase method names (e.g., addEventTrackingFilterOptions) but the actual methods use snake_case (e.g., add_event_tracking_filter_options). This caused a fatal TypeError on every page load where FluentCRM triggers these filters.
Security fixes: - Add authentication to REST endpoint (require manage_options capability) - Add date parameter validation to prevent malformed input - Sanitize $prop_name in SQL queries to prevent SQL injection - Use bound parameters for all whereRaw LIKE queries - Sanitize $_GET params before forwarding in SmartLink redirects Bug fixes: - Remove stray break in not_contains filter that skipped remaining filters - Fix wrong variable check ($item_value → $trimmed_values) in UpdateContactPropertyAction::formatCustomFieldValues - Fix trailing ?/& appended to redirect URLs when no query params exist - Remove empty switch statement (dead code from incomplete implementation) Cleanup: - Remove hardcoded debug email (daniel@code-atlantic.com) from event tracking - Remove no-op gettingAction() override in RandomWaitTimeAction - Remove dead code: commented-out hook, unused add_custom_dashboard_metrics(), placeholder register_custom_report/render_custom_report (Subscriber::all() memory bomb) - Remove Carbon dependency from REST endpoint (unnecessary) - Prefix remaining global functions with customcrm_ to avoid collisions
- Add AutomationConditions class that registers event tracking and automation completion condition groups in FluentCRM's funnel condition block (fixes MAR-8 and MAR-9) - Add FixDripMergeTags migration to convert Drip merge tags to FluentCRM equivalents in already-imported campaigns and funnel sequences (fixes MAR-12)
- AutomationConditions: return $result instead of true to preserve prior filter results in condition chain - FixDripMergeTags: guard against preg_replace returning null which would wipe email content - FixDripMergeTags: add LIKE guard to funnel sequences query to avoid full table scan
- AutomationConditions: unknown operators now fail safe instead of silently passing - FixDripMergeTags: campaign_emails query now checks for inline_postal_address and account.name tags (matching campaigns query) - FixDripMergeTags: campaign_emails loop now tracks stats (updated, skipped, errors) for complete reporting
Hook into edd_sl_activate_license to record an event in fc_event_tracking so funnel conditions can check "has performed: Activated license key".
New "EDD Licenses" condition group lets funnels check if a contact has an active license for a specific product via the edd_licenses table.
…elease No runtime composer dependencies exist, so replace vendor/autoload.php with a lightweight spl_autoload_register. Add GitHub Actions workflow that zips and creates a release on tag push.
Allows injecting arbitrary CSS into all outgoing FluentCRM emails via a new admin page (FluentCRM > Custom CSS) with a CodeMirror editor. - New CustomEmailCSS class handles admin page, save, and email injection - CSS injected before </head> after all template defaults for natural priority - Sanitizes input against XSS vectors (expression(), @import, javascript:, etc.) - Accessible: labeled textarea, role="alert" on notices, translatable strings - Uses WordPress CodeMirror (wp_enqueue_code_editor) in CSS mode
- Auto-append !important to every CSS declaration at injection time so custom styles override inline styles and template !important rules - Strip existing !important before re-adding to prevent doubling - Fix CodeMirror not loading: check $_GET['page'] instead of hook suffix which varies depending on how FluentCRM registers its parent menu - Update admin page description to reflect !important behavior
The "Has active license" condition was a binary yes/no that matched both active and inactive statuses. Automations needed finer control to distinguish between specific license states. - Replace yes/no with multi-select: Valid, Active, Inactive, Expired, Disabled - "Valid" maps to active+inactive (non-expired, non-revoked) - Add mapLicenseOptionToStatuses() for clean status resolution - Backward-compatible: old yes/no values auto-convert to new format - Guard against empty status arrays in whereIn queries
Multiple potential issues found during code review needed correcting to prevent edge-case bugs and improve security hardening. - SmartLinkHandler: use map_deep() for nested array sanitization - EddLicenseActivationTracker: check $customer->id not truthy $customer - UpdateContactPropertyAction: filter empty strings after trim - FixDripMergeTags: track stats for funnel sequence updates/skips/errors - CustomEmailCSS: fix wp_die() signature, null-coalesce preg_replace, prevent style tag breakout - Main plugin: validate dates with checkdate(), include full day in whereBetween ranges
array_merge_recursive() in getBlock() merged parent and child wait_time_amount into an array (['', 1]) instead of overwriting. When setDelayInSeconds() multiplied this by 60, PHP threw "Unsupported operand types: array * int", failing every fluentcrm_scheduled_every_minute_tasks cron run. - Replace array_merge_recursive with array_replace_recursive - Add defensive numeric casting in setDelayInSeconds() Fixes WEBSITE-135
- Add early bail-out in setDelayInSeconds() for non-random sequences - Add numeric type guards in savingAction() before arithmetic - Point GitHub Plugin URI to GravityKit fork (active development repo) - Set Primary Branch to feature/github-updater-headers (production branch)
…time Fix: array * int error blocking all FluentCRM automations
Covers architecture, field mapping, execution flow, error handling, settings management, and custom field auto-creation. First provider implementation will be People Data Labs (PDL).
12-task plan covering DTOs, provider abstraction, PDL implementation, FluentCRM action block, settings, custom fields, and registration.
…t DTOs Normalized data transfer objects for enrichment providers: error codes with retryable flag, person fields mapping to subscriber/custom columns, and company fields mapping to native Company columns and meta JSON.
Defines the provider contract: getSlug, getName, enrichPerson, enrichCompany, getSettingsFields, validateSettings, and the abstract mapError hook. The concrete httpGet helper wraps wp_remote_get and returns a normalized array or EnrichmentError on failure.
…chmentFields utilities - FreeEmailDetector: static domain check with filterable domain list via custom_crm/free_email_domains hook - EnrichmentSettings: static CRUD over wp_options with per-provider storage, active provider tracking, and base64/wp_encrypt API key encryption - EnrichmentFields: auto-creates 16 FluentCRM custom fields in the Enrichment group; uses a daily transient to avoid repeated DB reads
Use aes-256-cbc with WordPress AUTH_KEY as the encryption key. Falls back to base64 obfuscation if OpenSSL is unavailable.
Orchestration layer that registers as a FluentCRM automation action, provides settings UI, and coordinates person/company enrichment flow with configurable scope, data behavior, and company handling modes.
- Prefix unused callback params with underscore - Use strpos() instead of str_contains() for PHP 7.4 compat - Qualify fluentCrmLog() with global namespace
Convert all property @var comments from single-line to multi-line format, add short descriptions to EnrichmentError constants and properties, add missing @param tags to PDLProvider methods, and add short description to the constructor docblock to satisfy PHPCS Generic.Commenting and Squiz.Commenting rules. Zero PHPCS errors remain.
- Normalize filtered free email domains to lowercase - Require OpenSSL for encryption, return empty string on failure - Handle decrypt failures gracefully (return empty, don't leak ciphertext) - Warn when AUTH_KEY is missing (weak fallback key) - Guard company_enriched hook against null company - Escape LIKE wildcards in company website lookup - Handle preg_replace null returns in normalizeDomain
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
GitHub Updater support
GitHub Plugin URIandPrimary Branchheaders to enable automatic plugin updates via Git UpdaterComposer fix
vendor-prefixed/.gitkeepto fix composer classmap scan error on fresh clonesFatal error fix
JSONEventTrackingHandler::register()where all hook callbacks referenced non-existent camelCase methods instead of the actual snake_case methodsSecurity fixes
/fluent-crm/v1/list-growthREST endpoint (requiremanage_optionscapability)$prop_namein JSON_EXTRACT SQL queries to prevent SQL injectionwhereRawLIKE queries (was using string interpolation)$_GETparams before forwarding in SmartLink redirectsBug fixes
breakinnot_containsfilter handler that silently skipped all remaining filters$item_value→$trimmed_values) inUpdateContactPropertyAction::formatCustomFieldValues?or&appended to redirect URLs when no query params existswitchstatement (dead code from incomplete implementation)EDD license activation tracking
EddLicenseActivationTrackerclass hooks intoedd_sl_activate_licenseto record a FluentCRM event (license_activated) when a customer activates their license keyEDD license status condition
edd_licensestable foractive/inactivestatusCleanup
daniel@code-atlantic.com) from event trackinggettingAction()override inRandomWaitTimeActionadd_custom_dashboard_metrics(), placeholderregister_custom_report/render_custom_report(Subscriber::all()memory issue)customcrm_to avoid namespace collisionsTest plan
?/&/fluent-crm/v1/list-growthendpoint returns 401 for unauthenticated requestscomposer installon a fresh clone and confirm no classmap scan errorfc_event_trackinggets alicense_activatedrow