| 1 |
<?php |
| 2 |
/** |
| 3 |
* ConvertKit Settings Broadcasts class. |
| 4 |
* |
| 5 |
* @package ConvertKit |
| 6 |
* @author ConvertKit |
| 7 |
*/ |
| 8 |
|
| 9 |
/** |
| 10 |
* Registers Broadcasts Settings that can be edited at Settings > ConvertKit > Broadcasts. |
| 11 |
* |
| 12 |
* @package ConvertKit |
| 13 |
* @author ConvertKit |
| 14 |
*/ |
| 15 |
class ConvertKit_Admin_Settings_Broadcasts extends ConvertKit_Settings_Base { |
| 16 |
|
| 17 |
/** |
| 18 |
* Constructor. |
| 19 |
* |
| 20 |
* @since 2.2.9 |
| 21 |
*/ |
| 22 |
public function __construct() { |
| 23 |
|
| 24 |
// Define the class that reads/writes settings. |
| 25 |
$this->settings = new ConvertKit_Settings_Broadcasts(); |
| 26 |
|
| 27 |
// Define the settings key. |
| 28 |
$this->settings_key = $this->settings::SETTINGS_NAME; |
| 29 |
|
| 30 |
// Define the programmatic name, Title and Tab Text. |
| 31 |
$this->name = 'broadcasts'; |
| 32 |
$this->title = __( 'Broadcasts', 'convertkit' ); |
| 33 |
$this->tab_text = __( 'Broadcasts', 'convertkit' ); |
| 34 |
|
| 35 |
// Identify that this is beta functionality. |
| 36 |
$this->is_beta = true; |
| 37 |
|
| 38 |
// Output notices. |
| 39 |
add_action( 'convertkit_settings_base_render_before', array( $this, 'maybe_output_notices' ) ); |
| 40 |
|
| 41 |
// Enqueue scripts and CSS. |
| 42 |
add_action( 'convertkit_admin_settings_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); |
| 43 |
add_action( 'convertkit_admin_settings_enqueue_styles', array( $this, 'enqueue_styles' ) ); |
| 44 |
|
| 45 |
parent::__construct(); |
| 46 |
|
| 47 |
$this->maybe_import_now(); |
| 48 |
|
| 49 |
} |
| 50 |
|
| 51 |
/** |
| 52 |
* Import Broadcasts now, if requested through the UI. |
| 53 |
* |
| 54 |
* @since 2.2.9 |
| 55 |
*/ |
| 56 |
private function maybe_import_now() { |
| 57 |
|
| 58 |
// Bail if nonce verification fails. |
| 59 |
if ( ! isset( $_REQUEST['_convertkit_settings_broadcasts_nonce'] ) ) { |
| 60 |
return false; |
| 61 |
} |
| 62 |
if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['_convertkit_settings_broadcasts_nonce'] ), 'convertkit-settings-broadcasts' ) ) { |
| 63 |
return false; |
| 64 |
} |
| 65 |
|
| 66 |
// Run the import task through WordPress' Cron system now. |
| 67 |
$cron = new ConvertKit_Cron(); |
| 68 |
$result = $cron->run( 'convertkit_resource_refresh_posts' ); |
| 69 |
|
| 70 |
// If an error occured, show it now. |
| 71 |
if ( is_wp_error( $result ) ) { |
| 72 |
// Redirect to Broadcasts screen. |
| 73 |
$this->redirect( 'broadcast_import_error' ); |
| 74 |
return; |
| 75 |
} |
| 76 |
|
| 77 |
// If here, the task scheduled. |
| 78 |
$this->redirect( false, 'broadcast_import_success' ); |
| 79 |
|
| 80 |
} |
| 81 |
|
| 82 |
/** |
| 83 |
* Enqueues scripts for the Settings > Broadcasts screen. |
| 84 |
* |
| 85 |
* @since 2.2.9 |
| 86 |
* |
| 87 |
* @param string $section Settings section / tab (general|tools|restrict-content|broadcasts). |
| 88 |
*/ |
| 89 |
public function enqueue_scripts( $section ) { |
| 90 |
|
| 91 |
// Bail if we're not on the Broadcasts section. |
| 92 |
if ( $section !== $this->name ) { |
| 93 |
return; |
| 94 |
} |
| 95 |
|
| 96 |
// Enqueue Select2 JS. |
| 97 |
convertkit_select2_enqueue_scripts(); |
| 98 |
|
| 99 |
// Enqueue JS. |
| 100 |
wp_enqueue_script( 'convertkit-admin-settings-conditional-display', CONVERTKIT_PLUGIN_URL . 'resources/backend/js/settings-conditional-display.js', array( 'jquery' ), CONVERTKIT_PLUGIN_VERSION, true ); |
| 101 |
|
| 102 |
} |
| 103 |
|
| 104 |
/** |
| 105 |
* Enqueues styles for the Settings > General screen. |
| 106 |
* |
| 107 |
* @since 2.2.9 |
| 108 |
* |
| 109 |
* @param string $section Settings section / tab (general|tools|restrict-content|broadcasts). |
| 110 |
*/ |
| 111 |
public function enqueue_styles( $section ) { |
| 112 |
|
| 113 |
// Bail if we're not on the Broadcasts section. |
| 114 |
if ( $section !== $this->name ) { |
| 115 |
return; |
| 116 |
} |
| 117 |
|
| 118 |
// Enqueue Select2 CSS. |
| 119 |
convertkit_select2_enqueue_styles(); |
| 120 |
|
| 121 |
} |
| 122 |
|
| 123 |
/** |
| 124 |
* Outputs success and/or error notices if required. |
| 125 |
* |
| 126 |
* @since 2.2.9 |
| 127 |
*/ |
| 128 |
public function maybe_output_notices() { |
| 129 |
|
| 130 |
// Define messages that might be displayed as a notification. |
| 131 |
$messages = array( |
| 132 |
'broadcast_import_error' => __( 'Broadcasts import failed. Please try again.', 'convertkit' ), |
| 133 |
'broadcast_import_success' => __( 'Broadcasts import started. Check the Posts screen shortly to confirm Broadcasts imported successfully.', 'convertkit' ), |
| 134 |
); |
| 135 |
|
| 136 |
// Output error notification if defined. |
| 137 |
if ( isset( $_REQUEST['error'] ) && array_key_exists( sanitize_text_field( $_REQUEST['error'] ), $messages ) ) { // phpcs:ignore WordPress.Security.NonceVerification |
| 138 |
$this->output_error( $messages[ sanitize_text_field( $_REQUEST['error'] ) ] ); // phpcs:ignore WordPress.Security.NonceVerification |
| 139 |
} |
| 140 |
|
| 141 |
// Output success notification if defined. |
| 142 |
if ( isset( $_REQUEST['success'] ) && array_key_exists( sanitize_text_field( $_REQUEST['success'] ), $messages ) ) { // phpcs:ignore WordPress.Security.NonceVerification |
| 143 |
$this->output_success( $messages[ sanitize_text_field( $_REQUEST['success'] ) ] ); // phpcs:ignore WordPress.Security.NonceVerification |
| 144 |
} |
| 145 |
|
| 146 |
} |
| 147 |
|
| 148 |
/** |
| 149 |
* Registers settings fields for this section. |
| 150 |
* |
| 151 |
* @since 2.2.9 |
| 152 |
*/ |
| 153 |
public function register_fields() { |
| 154 |
|
| 155 |
// Initialize classes that will be used. |
| 156 |
$posts = new ConvertKit_Resource_Posts( 'cron' ); |
| 157 |
|
| 158 |
// Define description for the 'Enabled' setting. |
| 159 |
// If enabled, include the next scheduled date and time the Plugin will import broadcasts. |
| 160 |
// If the next scheduled timestamp is 1, the event is running now. |
| 161 |
$enabled_description = ''; |
| 162 |
if ( $this->settings->enabled() && $posts->get_cron_event_next_scheduled() && $posts->get_cron_event_next_scheduled() > 1 ) { |
| 163 |
$enabled_description = sprintf( |
| 164 |
'%s %s', |
| 165 |
esc_html__( 'Broadcasts will next import at approximately ', 'convertkit' ), |
| 166 |
// The cron event's next scheduled timestamp is always in UTC. |
| 167 |
// Display it converted to the WordPress site's timezone. |
| 168 |
get_date_from_gmt( |
| 169 |
gmdate( 'Y-m-d H:i:s', $posts->get_cron_event_next_scheduled() ), |
| 170 |
get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) |
| 171 |
) |
| 172 |
); |
| 173 |
} |
| 174 |
|
| 175 |
add_settings_field( |
| 176 |
'enabled', |
| 177 |
__( 'Enable Automatic Import', 'convertkit' ), |
| 178 |
array( $this, 'enable_callback' ), |
| 179 |
$this->settings_key, |
| 180 |
$this->name, |
| 181 |
array( |
| 182 |
'name' => 'enabled', |
| 183 |
'label_for' => 'enabled', |
| 184 |
'label' => __( 'Enables automatic publication of public ConvertKit Broadcasts as WordPress Posts.', 'convertkit' ), |
| 185 |
'description' => $enabled_description, |
| 186 |
) |
| 187 |
); |
| 188 |
|
| 189 |
// Render import button if the feature is enabled. |
| 190 |
if ( $this->settings->enabled() && $posts->get_cron_event_next_scheduled() ) { |
| 191 |
add_settings_field( |
| 192 |
'import_button', |
| 193 |
'', |
| 194 |
array( $this, 'import_button_callback' ), |
| 195 |
$this->settings_key, |
| 196 |
$this->name |
| 197 |
); |
| 198 |
} |
| 199 |
|
| 200 |
add_settings_field( |
| 201 |
'post_status', |
| 202 |
__( 'Status', 'convertkit' ), |
| 203 |
array( $this, 'post_status_callback' ), |
| 204 |
$this->settings_key, |
| 205 |
$this->name, |
| 206 |
array( |
| 207 |
'name' => 'post_status', |
| 208 |
'label_for' => 'post_status', |
| 209 |
'description' => __( 'The WordPress Post status to assign imported broadcasts to.', 'convertkit' ), |
| 210 |
) |
| 211 |
); |
| 212 |
|
| 213 |
add_settings_field( |
| 214 |
'author_id', |
| 215 |
__( 'Author', 'convertkit' ), |
| 216 |
array( $this, 'author_id_callback' ), |
| 217 |
$this->settings_key, |
| 218 |
$this->name, |
| 219 |
array( |
| 220 |
'name' => 'author_id', |
| 221 |
'label_for' => 'author_id', |
| 222 |
'description' => __( 'The WordPress User to set as the author for WordPress Posts created from imported broadcasts.', 'convertkit' ), |
| 223 |
) |
| 224 |
); |
| 225 |
|
| 226 |
add_settings_field( |
| 227 |
'category_id', |
| 228 |
__( 'Category', 'convertkit' ), |
| 229 |
array( $this, 'category_callback' ), |
| 230 |
$this->settings_key, |
| 231 |
$this->name, |
| 232 |
array( |
| 233 |
'name' => 'category_id', |
| 234 |
'label_for' => 'category_id', |
| 235 |
'description' => __( 'The category to assign imported broadcasts to.', 'convertkit' ), |
| 236 |
) |
| 237 |
); |
| 238 |
|
| 239 |
add_settings_field( |
| 240 |
'import_thumbnail', |
| 241 |
__( 'Include Thumbnail', 'convertkit' ), |
| 242 |
array( $this, 'import_thumbnail_callback' ), |
| 243 |
$this->settings_key, |
| 244 |
$this->name, |
| 245 |
array( |
| 246 |
'name' => 'import_thumbnail', |
| 247 |
'label_for' => 'import_thumbnail', |
| 248 |
'label' => __( 'If enabled, the Broadcast\'s thumbnail will be used as the WordPress Post\'s featured image.', 'convertkit' ), |
| 249 |
'description' => '', |
| 250 |
) |
| 251 |
); |
| 252 |
|
| 253 |
add_settings_field( |
| 254 |
'published_at_min_date', |
| 255 |
__( 'Earliest Date', 'convertkit' ), |
| 256 |
array( $this, 'date_callback' ), |
| 257 |
$this->settings_key, |
| 258 |
$this->name, |
| 259 |
array( |
| 260 |
'name' => 'published_at_min_date', |
| 261 |
'label_for' => 'published_at_min_date', |
| 262 |
'description' => __( 'The earliest date to import broadcasts from, based on the broadcast\'s published date and time.', 'convertkit' ), |
| 263 |
) |
| 264 |
); |
| 265 |
|
| 266 |
add_settings_field( |
| 267 |
'enabled_export', |
| 268 |
__( 'Enable Export Actions', 'convertkit' ), |
| 269 |
array( $this, 'enable_export_callback' ), |
| 270 |
$this->settings_key, |
| 271 |
$this->name, |
| 272 |
array( |
| 273 |
'name' => 'enabled_export', |
| 274 |
'label_for' => 'enabled_export', |
| 275 |
'label' => __( 'Displays actions in WordPress to create draft broadcasts from existing WordPress posts.', 'convertkit' ), |
| 276 |
) |
| 277 |
); |
| 278 |
|
| 279 |
add_settings_field( |
| 280 |
'no_styles', |
| 281 |
__( 'Disable Styles', 'convertkit' ), |
| 282 |
array( $this, 'no_styles_callback' ), |
| 283 |
$this->settings_key, |
| 284 |
$this->name, |
| 285 |
array( |
| 286 |
'name' => 'no_styles', |
| 287 |
'label_for' => 'no_styles', |
| 288 |
'description' => __( 'Removes inline styles and layout when importing broadcasts and exporting posts.', 'convertkit' ), |
| 289 |
) |
| 290 |
); |
| 291 |
|
| 292 |
} |
| 293 |
|
| 294 |
/** |
| 295 |
* Prints help info for this section |
| 296 |
* |
| 297 |
* @since 2.2.9 |
| 298 |
*/ |
| 299 |
public function print_section_info() { |
| 300 |
|
| 301 |
?> |
| 302 |
<span class="convertkit-beta-label"><?php esc_html_e( 'Beta', 'convertkit' ); ?></span> |
| 303 |
<p class="description"><?php esc_html_e( 'Defines whether public broadcasts created in ConvertKit should automatically be published on this site as WordPress Posts, and whether to enable options to create draft ConvertKit Broadcasts from WordPress Posts.', 'convertkit' ); ?></p> |
| 304 |
<?php |
| 305 |
|
| 306 |
} |
| 307 |
|
| 308 |
|
| 309 |
/** |
| 310 |
* Returns the URL for the ConvertKit documentation for this setting section. |
| 311 |
* |
| 312 |
* @since 2.2.9 |
| 313 |
* |
| 314 |
* @return string Documentation URL. |
| 315 |
*/ |
| 316 |
public function documentation_url() { |
| 317 |
|
| 318 |
return 'https://help.convertkit.com/en/articles/2502591-the-convertkit-wordpress-plugin'; |
| 319 |
|
| 320 |
} |
| 321 |
|
| 322 |
/** |
| 323 |
* Renders the input for the Enable setting. |
| 324 |
* |
| 325 |
* @since 2.2.9 |
| 326 |
* |
| 327 |
* @param array $args Setting field arguments (name,description). |
| 328 |
*/ |
| 329 |
public function enable_callback( $args ) { |
| 330 |
|
| 331 |
// Output field. |
| 332 |
echo $this->get_checkbox_field( // phpcs:ignore WordPress.Security.EscapeOutput |
| 333 |
$args['name'], |
| 334 |
'on', |
| 335 |
$this->settings->enabled(), // phpcs:ignore WordPress.Security.EscapeOutput |
| 336 |
$args['label'], // phpcs:ignore WordPress.Security.EscapeOutput |
| 337 |
$args['description'] // phpcs:ignore WordPress.Security.EscapeOutput |
| 338 |
); |
| 339 |
|
| 340 |
} |
| 341 |
|
| 342 |
/** |
| 343 |
* Renders the import button. |
| 344 |
* |
| 345 |
* @since 2.2.9 |
| 346 |
*/ |
| 347 |
public function import_button_callback() { |
| 348 |
|
| 349 |
// Define link to import Broadcasts now. |
| 350 |
$import_url = add_query_arg( |
| 351 |
array( |
| 352 |
'page' => '_wp_convertkit_settings', |
| 353 |
'tab' => 'broadcasts', |
| 354 |
'_convertkit_settings_broadcasts_nonce' => wp_create_nonce( 'convertkit-settings-broadcasts' ), |
| 355 |
), |
| 356 |
'options-general.php' |
| 357 |
); |
| 358 |
|
| 359 |
echo '<a href="' . esc_url( $import_url ) . '" class="button button-secondary enabled">' . esc_html__( 'Import now', 'convertkit' ) . '</a>'; |
| 360 |
|
| 361 |
} |
| 362 |
|
| 363 |
/** |
| 364 |
* Renders the input for the status setting. |
| 365 |
* |
| 366 |
* @since 2.3.4 |
| 367 |
* |
| 368 |
* @param array $args Setting field arguments (name,description). |
| 369 |
*/ |
| 370 |
public function post_status_callback( $args ) { |
| 371 |
|
| 372 |
// Build field. |
| 373 |
$select_field = $this->get_select_field( |
| 374 |
$args['name'], |
| 375 |
$this->settings->post_status(), |
| 376 |
get_post_statuses(), |
| 377 |
$args['description'], |
| 378 |
array( |
| 379 |
'enabled', |
| 380 |
'convertkit-select2', |
| 381 |
) |
| 382 |
); |
| 383 |
|
| 384 |
// Output field. |
| 385 |
echo '<div class="convertkit-select2-container">' . $select_field . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput |
| 386 |
|
| 387 |
} |
| 388 |
|
| 389 |
/** |
| 390 |
* Renders the input for the author setting. |
| 391 |
* |
| 392 |
* @since 2.3.9 |
| 393 |
* |
| 394 |
* @param array $args Setting field arguments (name,description). |
| 395 |
*/ |
| 396 |
public function author_id_callback( $args ) { |
| 397 |
|
| 398 |
// Build field. |
| 399 |
$select_field = wp_dropdown_users( |
| 400 |
array( |
| 401 |
'echo' => false, |
| 402 |
'selected' => $this->settings->author_id(), |
| 403 |
'include_selected' => true, |
| 404 |
'name' => $this->settings_key . '[' . $args['name'] . ']', |
| 405 |
'id' => $this->settings_key . '_' . $args['name'], |
| 406 |
'class' => 'enabled convertkit-select2', |
| 407 |
) |
| 408 |
); |
| 409 |
|
| 410 |
// Output field. |
| 411 |
echo '<div class="convertkit-select2-container">' . $select_field . '</div>' . $this->get_description( $args['description'] ); // phpcs:ignore WordPress.Security.EscapeOutput |
| 412 |
|
| 413 |
} |
| 414 |
|
| 415 |
/** |
| 416 |
* Renders the input for the category setting. |
| 417 |
* |
| 418 |
* @since 2.2.9 |
| 419 |
* |
| 420 |
* @param array $args Setting field arguments (name,description). |
| 421 |
*/ |
| 422 |
public function category_callback( $args ) { |
| 423 |
|
| 424 |
// Build field. |
| 425 |
$select_field = wp_dropdown_categories( |
| 426 |
array( |
| 427 |
'show_option_none' => __( 'None', 'convertkit' ), |
| 428 |
'echo' => 0, |
| 429 |
'hierarhical' => 1, |
| 430 |
'name' => $this->settings_key . '[' . $args['name'] . ']', |
| 431 |
'id' => $this->settings_key . '_' . $args['name'], |
| 432 |
'class' => 'convertkit-select2 enabled', |
| 433 |
'selected' => $this->settings->category_id(), |
| 434 |
'taxonomy' => 'category', |
| 435 |
'hide_empty' => false, |
| 436 |
) |
| 437 |
); |
| 438 |
|
| 439 |
// Output field. |
| 440 |
echo '<div class="convertkit-select2-container">' . $select_field . '</div>' . $this->get_description( $args['description'] ); // phpcs:ignore WordPress.Security.EscapeOutput |
| 441 |
|
| 442 |
} |
| 443 |
|
| 444 |
/** |
| 445 |
* Renders the input for the Import Thumbnail setting. |
| 446 |
* |
| 447 |
* @since 2.4.1 |
| 448 |
* |
| 449 |
* @param array $args Setting field arguments (name,description). |
| 450 |
*/ |
| 451 |
public function import_thumbnail_callback( $args ) { |
| 452 |
|
| 453 |
// Output field. |
| 454 |
echo $this->get_checkbox_field( // phpcs:ignore WordPress.Security.EscapeOutput |
| 455 |
$args['name'], |
| 456 |
'on', |
| 457 |
$this->settings->import_thumbnail(), // phpcs:ignore WordPress.Security.EscapeOutput |
| 458 |
$args['label'], // phpcs:ignore WordPress.Security.EscapeOutput |
| 459 |
$args['description'], // phpcs:ignore WordPress.Security.EscapeOutput |
| 460 |
array( |
| 461 |
'enabled', |
| 462 |
) |
| 463 |
); |
| 464 |
|
| 465 |
} |
| 466 |
|
| 467 |
/** |
| 468 |
* Renders the input for the date setting. |
| 469 |
* |
| 470 |
* @since 2.2.9 |
| 471 |
* |
| 472 |
* @param array $args Setting field arguments (name,description). |
| 473 |
*/ |
| 474 |
public function date_callback( $args ) { |
| 475 |
|
| 476 |
// Output field. |
| 477 |
echo $this->get_date_field( // phpcs:ignore WordPress.Security.EscapeOutput |
| 478 |
$args['name'], |
| 479 |
esc_attr( $this->settings->published_at_min_date() ), |
| 480 |
$args['description'], // phpcs:ignore WordPress.Security.EscapeOutput |
| 481 |
array( |
| 482 |
'enabled', |
| 483 |
) |
| 484 |
); |
| 485 |
|
| 486 |
} |
| 487 |
|
| 488 |
/** |
| 489 |
* Renders the input for the Enable Export setting. |
| 490 |
* |
| 491 |
* @since 2.4.0 |
| 492 |
* |
| 493 |
* @param array $args Setting field arguments (name,description). |
| 494 |
*/ |
| 495 |
public function enable_export_callback( $args ) { |
| 496 |
|
| 497 |
// Output field. |
| 498 |
echo $this->get_checkbox_field( // phpcs:ignore WordPress.Security.EscapeOutput |
| 499 |
$args['name'], |
| 500 |
'on', |
| 501 |
$this->settings->enabled_export(), // phpcs:ignore WordPress.Security.EscapeOutput |
| 502 |
$args['label'] // phpcs:ignore WordPress.Security.EscapeOutput |
| 503 |
); |
| 504 |
|
| 505 |
} |
| 506 |
|
| 507 |
/** |
| 508 |
* Renders the input for the No Styles setting. |
| 509 |
* |
| 510 |
* @since 2.2.9 |
| 511 |
* |
| 512 |
* @param array $args Setting field arguments (name,description). |
| 513 |
*/ |
| 514 |
public function no_styles_callback( $args ) { |
| 515 |
|
| 516 |
// Output field. |
| 517 |
echo $this->get_checkbox_field( // phpcs:ignore WordPress.Security.EscapeOutput |
| 518 |
$args['name'], |
| 519 |
'on', |
| 520 |
$this->settings->no_styles(), // phpcs:ignore WordPress.Security.EscapeOutput |
| 521 |
$args['description'] // phpcs:ignore WordPress.Security.EscapeOutput |
| 522 |
); |
| 523 |
|
| 524 |
} |
| 525 |
|
| 526 |
/** |
| 527 |
* Sanitizes the settings prior to being saved. |
| 528 |
* |
| 529 |
* @since 2.4.1 |
| 530 |
* |
| 531 |
* @param array $settings Submitted Settings Fields. |
| 532 |
* @return array Sanitized Settings with Defaults |
| 533 |
*/ |
| 534 |
public function sanitize_settings( $settings ) { |
| 535 |
|
| 536 |
// If the 'Include Thumbnail' setting isn't checked, it won't be included |
| 537 |
// in the array of settings, and the defaults will enable this. |
| 538 |
// Therefore, if the setting doesn't exist, set it to blank. |
| 539 |
if ( ! array_key_exists( 'import_thumbnail', $settings ) ) { |
| 540 |
$settings['import_thumbnail'] = ''; |
| 541 |
} |
| 542 |
|
| 543 |
// Merge settings with defaults. |
| 544 |
$settings = wp_parse_args( $settings, $this->settings->get_defaults() ); |
| 545 |
|
| 546 |
// Return settings to be saved. |
| 547 |
return $settings; |
| 548 |
|
| 549 |
} |
| 550 |
|
| 551 |
} |
| 552 |
|
| 553 |
// Bootstrap. |
| 554 |
add_action( |
| 555 |
'convertkit_admin_settings_register_sections', |
| 556 |
function ( $sections ) { |
| 557 |
|
| 558 |
$sections['broadcasts'] = new ConvertKit_Admin_Settings_Broadcasts(); |
| 559 |
return $sections; |
| 560 |
|
| 561 |
} |
| 562 |
); |
| 563 |
|