set_basename( false, __FILE__ ); } else { // DO NOT REMOVE THIS IF — essential for the function_exists() call above. if ( !function_exists( 'answerrails_fs' ) ) { /** * Freemius SDK accessor (#95). Snippet taken VERBATIM from the * dashboard SDK Integration page (product 35635, 2026-08-10) with * ONE deliberate divergence: the require path is ours — the SDK is * vendored at includes/lib/vendor/freemius/ (FREEMIUS_SDK_PATH_DESIGN * D1, #354, superseding DD1's includes/lib/freemius/). The `vendor` * segment is what Plugin Check's directory ignore keys on; a ROOT * vendor/freemius would be excluded from the shipped zip by * release.yml's anchored /vendor rule. Pinned SDK — see the * AGENTS.md release-checklist rider. */ function answerrails_fs() { global $answerrails_fs; if ( !isset( $answerrails_fs ) ) { // Include Freemius SDK (#354 D1 path — see accessor doc above). require_once dirname( __FILE__ ) . '/includes/lib/vendor/freemius/start.php'; // The SDK's STANDARD FREEMIUM CONFIGURATION — the snippet // Freemius's own documentation gives for a product with a // WordPress.org edition and a separately sold one, shipped // unchanged by many directory plugins. // // What it does NOT do: no value here is consulted by any // feature in this plugin. Nothing in this codebase asks the // SDK what the site has bought in order to decide what to // run, and the four values below configure the SDK's own // account and update screens, nothing else. // // AnswerRails Pro is a SEPARATE PLUGIN, downloaded from // answerrails.com; `premium_suffix` is the name the SDK gives // that download, and `has_paid_plans` tells the SDK that // download is sold. `is_org_compliant` is true because this // source also produces the WordPress.org edition — the // deployment processor generates it from here, which is also // what removes `wp_org_gatekeeper` below and the one // module-loading block in class-answerrails-plugin.php. $answerrails_fs = fs_dynamic_init( array( 'id' => '35635', 'slug' => 'answerrails', 'type' => 'plugin', 'public_key' => 'pk_55ddcf8a369e6a30b6596d56fbaf2', 'is_premium' => false, 'premium_suffix' => '(Pro)', 'has_addons' => false, 'has_paid_plans' => true, 'is_org_compliant' => true, 'menu' => array( 'slug' => 'answerrails', 'support' => false, ), 'is_live' => true, ) ); } return $answerrails_fs; } // Init Freemius. answerrails_fs(); /** * Opt-in screen copy (#95 — D2 Option A, customised). * The CLAIMS are fixed here for the #101 consistency set: names * Freemius and the exact data categories, never claims or implies * "no external calls" (AI providers are called on every grounded * turn regardless of opt-in state), states skippability plainly, * no invented numbers, no "anonymous" claim (a site URL is * identifying). Final wording lands with solicitor-reviewed #101 * text. Same message on install and update: the categories are * identical either way. */ function answerrails_fs_connect_message( $message, $user_first_name, $product_title, $user_login, $site_link, $freemius_link ) { return sprintf( '%1$s

%2$s

%3$s', esc_html__( 'Help improve AnswerRails — your choice.', 'answerrails' ), esc_html__( 'Opt in to share diagnostic data with Freemius, the licensing platform AnswerRails is built on: your site address, WordPress and PHP versions, and plugin activation events. This helps us support your configuration and know which WordPress versions to test. No visitor conversations, no knowledge-base content, and no chat data are ever included.', 'answerrails' ), esc_html__( 'Skip this and AnswerRails works exactly the same.', 'answerrails' ) ); } answerrails_fs()->add_filter( 'connect_message', 'answerrails_fs_connect_message', 10, 6 ); answerrails_fs()->add_filter( 'connect_message_on_update', 'answerrails_fs_connect_message', 10, 6 ); /** * Plugin icon for the SDK's screens (opt-in / activation / notices). * Without this the SDK copies its grey-plug placeholder to * includes/lib/vendor/freemius/assets/img/answerrails.png at runtime (that * path is gitignored — it is a runtime artefact either way; the SDK * copies whatever this filter returns there). The brand icon lives * in OUR assets so SDK upgrades never touch it. */ function answerrails_fs_plugin_icon() { return dirname( __FILE__ ) . '/assets/images/answerrails-icon-256.png'; } answerrails_fs()->add_filter( 'plugin_icon', 'answerrails_fs_plugin_icon' ); // Signal that the SDK was initiated. do_action( 'answerrails_fs_loaded' ); } // Define plugin constants (inside the else deliberately: during the // free↔paid swap the first-loaded build's constants win, and the // second main file never reaches this branch). define( 'ANSWERRAILS_VERSION', '1.0.1' ); define( 'ANSWERRAILS_PLUGIN_FILE', __FILE__ ); define( 'ANSWERRAILS_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); define( 'ANSWERRAILS_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); define( 'ANSWERRAILS_PLUGIN_BASENAME', plugin_basename( __FILE__ ) ); define( 'ANSWERRAILS_DIR', ANSWERRAILS_PLUGIN_DIR ); // For compatibility define( 'ANSWERRAILS_URL', ANSWERRAILS_PLUGIN_URL ); // For compatibility // LOAD CRITICAL UTILITIES IMMEDIATELY - before any class definitions require_once ANSWERRAILS_PLUGIN_DIR . 'includes/class-answerrails-utils.php'; require_once ANSWERRAILS_PLUGIN_DIR . 'includes/class-answerrails-retrieval.php'; // #92 engine resolver (depends on Utils) // Main plugin class + accessor (extracted per #95 — the // step-18 double-load must never redeclare a top-level class). require_once ANSWERRAILS_PLUGIN_DIR . 'includes/class-answerrails-plugin.php'; // Uninstall lifecycle (#127): cleanup rides the SDK's after_uninstall // action — NEVER uninstall.php. WP core gives that file absolute // precedence: it would delete the SDK's registered uninstall hook, // silencing the Freemius uninstall event and the free/premium // sibling-build guard. UninstallLifecycleTest pins both halves // (this registration present; uninstall.php absent). // Design: docs/design/UNINSTALL_LIFECYCLE_DESIGN.md (D1). require_once ANSWERRAILS_PLUGIN_DIR . 'includes/class-answerrails-uninstall.php'; answerrails_fs()->add_action( 'after_uninstall', array('AnswerRails_Uninstall', 'run') ); // Start the plugin. answerrails(); }