diff --git a/CHANGELOG.md b/CHANGELOG.md
index a874d0f59..a6362c5f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,6 +25,7 @@
**Fixes**
+- Fixed CTA shortcode buttons rendering as plain links instead of styled buttons, with proper support for fill, outline, and text-only styles in both classic and block editor popups.
- Fixed mailto: and tel: links inside popups being incorrectly modified with tracking parameters, which broke email and phone links.
- Fixed Fluent Forms integration fatal error when using double opt-in. Closes #1094.
- Fixed Time Delay trigger settings tab displaying blank when switching from Click Trigger advanced tab. Closes #1109.
diff --git a/assets/js/src/site/styles.scss b/assets/js/src/site/styles.scss
index ed9345ac9..355e60790 100644
--- a/assets/js/src/site/styles.scss
+++ b/assets/js/src/site/styles.scss
@@ -2,6 +2,8 @@
@import "styles/partials/site/animations";
/* Popup Core Styles */
@import "styles/partials/pum_styles";
+/* CTA Shortcode Styles */
+@import "styles/partials/site/cta";
/* PM Forms */
@import "styles/partials/site/form/general";
@import "styles/partials/site/form/alignments";
diff --git a/assets/js/src/site/styles/partials/site/_cta.scss b/assets/js/src/site/styles/partials/site/_cta.scss
new file mode 100644
index 000000000..ad30c6ca1
--- /dev/null
+++ b/assets/js/src/site/styles/partials/site/_cta.scss
@@ -0,0 +1,107 @@
+/**
+ * CTA Shortcode Styles
+ *
+ * These styles ensure CTA shortcodes render correctly in both Classic and Block
+ * editor contexts. The shortcode uses block-compatible classes but needs base
+ * styles that work without block CSS loaded.
+ */
+
+/* Wrapper styles for shortcode CTA buttons. */
+.pum-cta-wrapper {
+ display: inline-block;
+ max-width: 100%;
+ width: auto;
+
+ /* Alignment classes. */
+ &.alignleft {
+ display: block;
+ text-align: left;
+ }
+
+ &.aligncenter {
+ display: block;
+ text-align: center;
+ }
+
+ &.alignright {
+ display: block;
+ text-align: right;
+ }
+
+ &.alignfull {
+ display: block;
+ width: 100%;
+
+ .pum-cta {
+ width: 100%;
+ }
+ }
+}
+
+/**
+ * Base CTA button styles - only apply within shortcode wrapper to avoid
+ * conflicts with block styles when block CSS is loaded.
+ */
+.pum-cta-wrapper .pum-cta {
+ border-radius: 9999px;
+ box-sizing: border-box;
+ cursor: pointer;
+ display: inline-block;
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+ padding: 1rem 2.25rem;
+ text-align: center;
+ text-decoration: none;
+ transition: filter 0.15s ease-in-out, background-color 0.15s ease-in-out;
+ width: auto;
+}
+
+/* Fill style (default). */
+.pum-cta-wrapper:not(.is-style-outline):not(.is-style-text-only) .pum-cta {
+ background-color: var(--wp--preset--color--contrast, #000);
+ border: none;
+ color: var(--wp--preset--color--base, #fff);
+
+ &:hover {
+ filter: brightness(0.85);
+ }
+}
+
+/* Outline style. */
+.pum-cta-wrapper.is-style-outline .pum-cta {
+ background-color: transparent;
+ border: 1px solid currentcolor;
+ color: var(--wp--preset--color--contrast, currentcolor);
+ padding: calc(1rem - 1px) calc(2.25rem - 1px);
+
+ &:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+ filter: brightness(1.05);
+ }
+}
+
+/* Text-only style. */
+.pum-cta-wrapper.is-style-text-only .pum-cta {
+ background-color: transparent;
+ border: none;
+ color: var(--wp--preset--color--contrast, currentcolor);
+ padding: 0.5rem 1rem;
+
+ &:hover {
+ text-decoration: underline;
+ }
+}
+
+/* Fallback colors when CSS custom properties are not available. */
+@supports not (color: var(--wp--preset--color--contrast)) {
+ .pum-cta-wrapper:not(.is-style-outline):not(.is-style-text-only) .pum-cta {
+ background-color: #1e1e1e;
+ color: #fff;
+ }
+
+ .pum-cta-wrapper.is-style-outline .pum-cta,
+ .pum-cta-wrapper.is-style-text-only .pum-cta {
+ color: inherit;
+ }
+}
diff --git a/classes/Shortcode/CallToAction.php b/classes/Shortcode/CallToAction.php
index 64c28ec92..689e021d7 100644
--- a/classes/Shortcode/CallToAction.php
+++ b/classes/Shortcode/CallToAction.php
@@ -201,15 +201,26 @@ public function handler( $atts, $content = null ) {
$wrapper_classes = [
'pum-cta-wrapper',
+ 'wp-block-popup-maker-cta-button',
'align' . $align,
'is-style-' . $style,
'text-only' === $atts['style'] ? 'pum-cta--button' : null,
];
+ // Build link classes, filtering out empty values.
+ $link_classes = array_filter(
+ [
+ 'pum-cta',
+ 'wp-block-popup-maker-cta-button__link',
+ 'wp-element-button',
+ $atts['extra_link_classes'],
+ ]
+ );
+
$cta_content = sprintf(
- "%s",
+ "%s",
esc_url_raw( $url ),
- esc_attr( $atts['extra_link_classes'] ),
+ esc_attr( implode( ' ', $link_classes ) ),
esc_attr( $target ),
esc_attr( $type ),
esc_html( $text )
diff --git a/packages/block-library/src/lib/cta-button/style.scss b/packages/block-library/src/lib/cta-button/style.scss
index c8e8d0673..33ce353b8 100644
--- a/packages/block-library/src/lib/cta-button/style.scss
+++ b/packages/block-library/src/lib/cta-button/style.scss
@@ -1,4 +1,4 @@
-// This variable is repeated across Button, Buttons, and Buttons editor styles.
+/* This variable is repeated across Button, Buttons, and Buttons editor styles. */
$blocks-block__margin: 0.5em;
// Use our CTA button class but maintain the same styling structure
@@ -9,9 +9,18 @@ $blocks-block__margin: 0.5em;
display: inline-block;
height: 100%;
text-align: center;
- width: 100%;
word-break: break-word;
+ /* Only use 100% width when inside the block container, not shortcode wrapper. */
+ .wp-block-popup-maker-cta-buttons & {
+ width: 100%;
+ }
+
+ /* Shortcode context: auto width (shortcode wrapper uses pum-cta-wrapper class). */
+ .pum-cta-wrapper & {
+ width: auto;
+ }
+
&.aligncenter,
&.has-text-align-center {
text-align: center;