PluginProbe
Advanced Ads – Ad Manager & AdSense / 2.0.22
Advanced Ads – Ad Manager & AdSense v2.0.22
2.0.26 2.0.25 2.0.24 2.0.23 2.0.22 2.0.21 1.38.0 1.39.0 1.39.1 1.39.2 1.39.3 1.39.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.40.0 1.40.1 1.40.2 All 348 releases
advanced-ads / includes / class-shortcodes.php
class-shortcodes.php
228 lines 5.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Shortcodes.
4 *
5 * @package AdvancedAds
6 * @author Advanced Ads <info@wpadvancedads.com>
7 * @since 1.50.0
8 */
9
10 namespace AdvancedAds;
11
12 use AdvancedAds\Framework\Interfaces\Integration_Interface;
13
14 defined( 'ABSPATH' ) || exit;
15
16 /**
17 * Shortcodes.
18 */
19 class Shortcodes implements Integration_Interface {
20
21 /**
22 * Hook into WordPress.
23 *
24 * @return void
25 */
26 public function hooks(): void {
27 add_shortcode( 'the_ad', [ $this, 'render_ad' ] );
28 add_shortcode( 'the_ad_group', [ $this, 'render_group' ] );
29 add_shortcode( 'the_ad_placement', [ $this, 'render_placement' ] );
30 }
31
32 /**
33 * Renders an ad based on the provided attributes.
34 *
35 * @param array $atts The attributes for the ad.
36 *
37 * @return string The rendered ad.
38 */
39 public function render_ad( $atts ): string {
40 $ad = wp_advads_get_ad( absint( $atts['id'] ?? 0 ) );
41 // Early bail!!
42 if ( ! $ad ) {
43 return '';
44 }
45
46 $atts = is_array( $atts ) ? $atts : [];
47
48 // Check if there is an inline attribute with or without value.
49 if ( isset( $atts['inline'] ) || in_array( 'inline', $atts, true ) ) {
50 $atts['inline_wrapper_element'] = true;
51 }
52
53 $atts = $this->prepare_shortcode_atts( $atts );
54
55 $this->set_shortcode_atts( $ad, $atts );
56
57 return get_the_ad( $ad, '', $atts );
58 }
59
60 /**
61 * Renders a group based on the provided attributes.
62 *
63 * @param array $atts The attributes for the group.
64 *
65 * @return string The rendered group.
66 */
67 public function render_group( $atts ): string {
68 $group = wp_advads_get_group( absint( $atts['id'] ?? 0 ) );
69 // Early bail!!
70 if ( ! $group ) {
71 return '';
72 }
73
74 $atts = is_array( $atts ) ? $atts : [];
75 $atts = $this->prepare_shortcode_atts( $atts );
76
77 $this->set_shortcode_atts( $group, $atts );
78
79 return get_the_group( $group, '', $atts );
80 }
81
82 /**
83 * Renders a placement based on the provided attributes.
84 *
85 * @param array $atts The attributes for the placement.
86 *
87 * @return string The rendered placement.
88 */
89 public function render_placement( $atts ): string {
90 $placement = wp_advads_get_placement( (string) ( $atts['id'] ?? '' ) );
91 // Early bail!!
92 if ( ! $placement ) {
93 return '';
94 }
95
96 $atts = is_array( $atts ) ? $atts : [];
97 $atts = $this->prepare_shortcode_atts( $atts );
98
99 $this->set_shortcode_atts( $placement, $atts );
100
101 return get_the_placement( $placement, '', $atts );
102 }
103
104 /**
105 * Prepare shortcode attributes.
106 *
107 * @param array $atts array with strings.
108 *
109 * @return array
110 */
111 private function prepare_shortcode_atts( $atts ): array {
112 $result = [];
113
114 /**
115 * Prepare attributes by converting strings to multi-dimensional array
116 * Example: [ 'output__margin__top' => 1 ] => ['output']['margin']['top'] = 1
117 */
118 if ( ! defined( 'ADVANCED_ADS_DISABLE_CHANGE' ) || ! ADVANCED_ADS_DISABLE_CHANGE ) {
119 foreach ( $atts as $attr => $data ) {
120 // Remove the prefix (change-ad__, change-group__, change-placement__).
121 $attr = preg_replace( '/^(change-ad|change-group|change-placement)__/', '', $attr );
122 $levels = explode( '__', $attr );
123 $last = array_pop( $levels );
124
125 $cur_lvl = &$result;
126
127 foreach ( $levels as $lvl ) {
128 if ( ! isset( $cur_lvl[ $lvl ] ) ) {
129 $cur_lvl[ $lvl ] = [];
130 }
131
132 $cur_lvl = &$cur_lvl[ $lvl ];
133 }
134
135 $cur_lvl[ $last ] = $data;
136 }
137
138 $result = array_diff_key(
139 $result,
140 [
141 'id' => false,
142 'blog_id' => false,
143 'ad_args' => false,
144 ]
145 );
146 }
147
148 // Ad type: 'content' and a shortcode inside.
149 if ( isset( $atts['ad_args'] ) ) {
150 $result = array_merge( $result, $this->parse_shortcode_ad_args( $atts['ad_args'] ) );
151 }
152
153 // Flat output array for Ad.
154 if ( isset( $result['output'] ) && is_array( $result['output'] ) ) {
155 $result = array_merge( $result, $result['output'] );
156 unset( $result['output'] );
157 }
158
159 // Special cases.
160 if ( isset( $result['tracking']['link'] ) ) {
161 $result['url'] = $result['tracking']['link'];
162 unset( $result['tracking']['link'] );
163 }
164
165 if ( isset( $result['content'] ) && is_string( $result['content'] ) ) {
166 $result['content'] = $this->sanitize_shortcode_content( $result['content'] );
167 }
168
169 return $result;
170 }
171
172 /**
173 * Sanitize shortcode content override by stripping PHP payloads only.
174 *
175 * @param string $content Content override from shortcode attributes (ad_args, change-ad__, etc.).
176 *
177 * @return string
178 */
179 private function sanitize_shortcode_content( string $content ): string {
180 // Remove PHP blocks (closed or unclosed through end of string).
181 // Handle both cases.
182 // 1. closed PHP tag
183 // 2. unclosed PHP tag
184 $content = preg_replace( '/<\\?(?:php|=)?[\\s\\S]*?(?:\\x3F\\x3E|$)/i', '', $content );
185
186 return $content ? $content : '';
187 }
188
189 /**
190 * Parse and sanitize ad_args payload for shortcode rendering.
191 *
192 * @param string $ad_args Raw urlencoded ad_args value.
193 *
194 * @return array
195 */
196 private function parse_shortcode_ad_args( string $ad_args ): array {
197 $decoded_ad_args = json_decode( urldecode( $ad_args ), true );
198 if ( ! is_array( $decoded_ad_args ) ) {
199 return [];
200 }
201
202 if ( isset( $decoded_ad_args['content'] ) && is_string( $decoded_ad_args['content'] ) ) {
203 $decoded_ad_args['content'] = $this->sanitize_shortcode_content( $decoded_ad_args['content'] );
204 }
205
206 return $decoded_ad_args;
207 }
208
209 /**
210 * Set shortcode attributes.
211 *
212 * @param object $entity The entity object.
213 * @param array $atts The attributes to set for the entity.
214 *
215 * @return void
216 */
217 private function set_shortcode_atts( $entity, $atts ): void {
218 foreach ( $atts as $key => $value ) {
219 $entity->set_prop_temp( $key, $value );
220 }
221
222 // WP Security: disable PHP for shortcode renders. prevents unauthorized PHP execution.
223 if ( isset( $atts['allow_php'] ) ) {
224 $entity->set_prop_temp( 'allow_php', false );
225 }
226 }
227 }
228