Skip to content
Merged
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
27 changes: 25 additions & 2 deletions crumb.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Plugin Name: Crumb
* Plugin URI: https://wordpress.org/plugins/crumb/
* Description: Embeds the Crumb meeting finder widget on any page or post using a shortcode.
* Version: 1.3.1
* Version: 1.3.2
* Author: bmltenabled
* Author URI: https://bmlt.app
* License: GPL v2 or later
Expand All @@ -15,7 +15,7 @@
exit;
}

define( 'CRUMB_VERSION', '1.3.1' );
define( 'CRUMB_VERSION', '1.3.2' );

class Crumb {

Expand All @@ -40,6 +40,21 @@ class Crumb {
'bmlt_tabs' => 'list',
];

/**
* Crouton helper shortcodes with no crumb equivalent.
* Registered as empty-string stubs so pages don't show the literal shortcode
* text after crouton is deactivated.
*/
const CROUTON_NOOP_TAGS = [
'init_crouton',
'bmlt_count',
'meeting_count',
'group_count',
'service_body_names',
'root_service_body',
'bmlt_handlebar',
];

public static function get_instance(): self {
if ( null === self::$instance ) {
self::$instance = new self();
Expand Down Expand Up @@ -171,6 +186,14 @@ static function ( $atts ) use ( $view ) {
}
);
}
// Helper shortcodes with no crumb equivalent — register as empty-string stubs
// so pages don't render the literal "[bmlt_count]" text after crouton is removed.
// These do NOT trigger widget enqueue, so they're kept out of $compat_tags.
foreach ( self::CROUTON_NOOP_TAGS as $tag ) {
if ( ! shortcode_exists( $tag ) ) {
add_shortcode( $tag, '__return_empty_string' );
}
}
}

public static function crouton_compat_shortcode( $atts, string $view ): string {
Expand Down
8 changes: 7 additions & 1 deletion readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Tags: narcotics anonymous, na, meetings, bmlt, meeting finder
Requires at least: 6.0
Tested up to: 7.0
Requires PHP: 8.1
Stable tag: 1.3.1
Stable tag: 1.3.2
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html

Expand Down Expand Up @@ -124,6 +124,9 @@ The widget fetches meeting data from a BMLT server whose URL you configure in Se

== Changelog ==

= 1.3.2 =
* Extended the crouton compatibility layer to register empty-string stubs for crouton's helper shortcodes (`[bmlt_count]`, `[meeting_count]`, `[group_count]`, `[service_body_names]`, `[root_service_body]`, `[bmlt_handlebar]`, `[init_crouton]`) so pages don't render the literal shortcode text after crouton is deactivated. These have no Crumb equivalent and output nothing; the surrounding page content remains intact.

= 1.3.1 =
* Added compatibility layer for the [crouton](https://wordpress.org/plugins/crouton/) plugin. Crumb now registers `[bmlt_tabs]`, `[bmlt_map]`, `[crouton_tabs]`, and `[crouton_map]` shortcodes and renders them with the Crumb widget when crouton is not active. Shortcode attributes (`root_server`, `service_body`, `service_body_1`, `formats`, `report_update_url`) are translated automatically.
* Crumb falls back to crouton's saved settings (server URL, service body, format IDs, update URL) when the corresponding Crumb option is empty — installing and activating is enough; no page or settings edits required.
Expand Down Expand Up @@ -164,6 +167,9 @@ The widget fetches meeting data from a BMLT server whose URL you configure in Se

== Upgrade Notice ==

= 1.3.2 =
Suppresses literal `[bmlt_count]`, `[meeting_count]`, `[group_count]`, `[service_body_names]`, `[root_service_body]`, `[bmlt_handlebar]`, and `[init_crouton]` shortcode text on pages after crouton is deactivated. Safe to update.

= 1.3.1 =
Adds drop-in compatibility for the crouton plugin: crouton shortcodes (`[bmlt_tabs]`, `[bmlt_map]`, `[crouton_tabs]`, `[crouton_map]`) now render with the Crumb widget and crouton's saved settings are used as fallbacks. Safe to update.

Expand Down
50 changes: 50 additions & 0 deletions tests/test-crumb.php
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,56 @@ public function test_get_option_or_crouton_with_unmapped_key_returns_default() {
delete_option( 'bmlt_tabs_options' );
}

// -------------------------------------------------------------------------
// Crouton compatibility — no-op helper shortcodes
// -------------------------------------------------------------------------

public function test_crouton_noop_shortcodes_are_registered() {
foreach ( Crumb::CROUTON_NOOP_TAGS as $tag ) {
$this->assertTrue( shortcode_exists( $tag ), "Expected {$tag} to be registered" );
}
}

public function test_crouton_noop_shortcodes_render_empty() {
foreach ( Crumb::CROUTON_NOOP_TAGS as $tag ) {
$this->assertSame( '', do_shortcode( "[{$tag}]" ), "Expected [{$tag}] to render empty" );
}
}

public function test_crouton_noop_shortcodes_render_empty_with_attributes() {
// Attributes should be ignored; output stays empty.
$this->assertSame( '', do_shortcode( '[bmlt_count live="1"]' ) );
$this->assertSame( '', do_shortcode( '[root_service_body field="name"]' ) );
$this->assertSame( '', do_shortcode( '[bmlt_handlebar template="foo"]' ) );
}

public function test_register_crouton_shortcodes_does_not_overwrite_noop_tag() {
global $shortcode_tags;
$saved = $shortcode_tags['bmlt_count'] ?? null;
$sentinel = static function () {
return 'PRE-EXISTING';
};
remove_shortcode( 'bmlt_count' );
add_shortcode( 'bmlt_count', $sentinel );

Crumb::register_crouton_shortcodes();
$this->assertSame( 'PRE-EXISTING', do_shortcode( '[bmlt_count]' ) );

// Restore.
remove_shortcode( 'bmlt_count' );
if ( $saved ) {
$shortcode_tags['bmlt_count'] = $saved;
}
}

public function test_crouton_noop_tags_not_in_compat_tags() {
// No-op tags don't render a widget, so they shouldn't trigger script enqueue.
$compat = Crumb::compat_tags();
foreach ( Crumb::CROUTON_NOOP_TAGS as $tag ) {
$this->assertNotContains( $tag, $compat, "{$tag} should not be in compat_tags" );
}
}

public function test_crouton_shortcode_combines_attribute_and_fallback() {
// root_server from crouton fallback; service_body from shortcode att.
delete_option( 'crumb_server' );
Expand Down