WP_REST_Server::READABLE, 'args' => array( 'date_format' => array( 'default' => $this->get_default_value( 'date_format' ), 'sanitize_callback' => 'sanitize_text_field', ), 'display_image' => array( 'default' => $this->get_default_value( 'display_image' ), 'sanitize_callback' => 'absint', ), 'display_description' => array( 'default' => $this->get_default_value( 'display_description' ), 'sanitize_callback' => 'absint', ), 'display_read_more' => array( 'default' => $this->get_default_value( 'display_read_more' ), 'sanitize_callback' => 'absint', ), 'read_more_label' => array( 'default' => $this->get_default_value( 'read_more_label' ), 'sanitize_callback' => 'sanitize_text_field', ), 'limit' => array( 'default' => $this->get_default_value( 'limit' ), 'sanitize_callback' => 'absint', ), 'page' => array( 'default' => $this->get_default_value( 'page' ), 'sanitize_callback' => 'absint', ), 'paginate' => array( 'default' => $this->get_default_value( 'paginate' ), 'sanitize_callback' => 'absint', ), 'paginate_label_next' => array( 'default' => $this->get_default_value( 'paginate_label_next' ), 'sanitize_callback' => 'sanitize_text_field', ), 'paginate_label_prev' => array( 'default' => $this->get_default_value( 'paginate_label_prev' ), 'sanitize_callback' => 'sanitize_text_field', ), 'link_color' => array( 'default' => $this->get_default_value( 'link_color' ), 'sanitize_callback' => 'sanitize_text_field', ), ), 'callback' => function ( $request ) { return rest_ensure_response( $this->render_ajax( $request ) ); }, // No authentication required, as this is on the frontend site. 'permission_callback' => '__return_true', ) ); } /** * Enqueues scripts for this Gutenberg Block in the editor and frontend views. * * @since 1.9.7.6 */ public function enqueue_scripts() { // Get ConvertKit Settings. $settings = new ConvertKit_Settings(); // Enqueue frontend JS. convertkit_enqueue_frontend_js(); // Define variables. wp_localize_script( 'convertkit-js', 'convertkit_broadcasts', array( // REST API URL endpoint. 'ajax_url' => rest_url( 'kit/v1/broadcasts' ), // Whether debugging is enabled. 'debug' => $settings->debug_enabled(), ) ); } /** * Enqueues styles for this Gutenberg Block in the editor and frontend views. * * @since 1.9.7.4 */ public function enqueue_styles() { convertkit_enqueue_frontend_css(); } /** * Returns this block's programmatic name, excluding the convertkit- prefix. * * @since 1.9.7.4 */ public function get_name() { /** * This will register as: * - a shortcode, with the name [convertkit_broadcasts]. * - a Gutenberg block, with the name convertkit/broadcasts. */ return 'broadcasts'; } /** * Returns this block's title. * * @since 3.1.1 */ public function get_title() { return __( 'Kit Broadcasts', 'convertkit' ); } /** * Returns this block's plural title. * * @since 3.4.0 * * @return string */ public function get_title_plural() { return __( 'Kit Broadcasts', 'convertkit' ); } /** * Returns this block's icon. * * @since 3.1.1 */ public function get_icon() { return 'resources/backend/images/block-icon-broadcasts.svg'; } /** * Returns this block's Title, Icon, Categories, Keywords and properties. * * @since 1.9.7.4 */ public function get_overview() { // Fetch Posts. $posts = new ConvertKit_Resource_Posts( 'output_broadcasts' ); $settings = new ConvertKit_Settings(); return array( 'title' => $this->get_title(), 'description' => __( 'Displays a list of your Kit broadcasts.', 'convertkit' ), 'icon' => $this->get_icon(), 'category' => 'convertkit', 'keywords' => array( __( 'ConvertKit', 'convertkit' ), __( 'Kit', 'convertkit' ), __( 'Broadcasts', 'convertkit' ), __( 'Posts', 'convertkit' ), ), // Function to call when rendering as a block or a shortcode on the frontend web site. 'render_callback' => array( $this, 'render' ), // Shortcode: TinyMCE / QuickTags Modal Width and Height. 'modal' => array( 'width' => 650, 'height' => 455, ), // Shortcode: Include a closing [/shortcode] tag when using TinyMCE or QuickTag Modals. 'shortcode_include_closing_tag' => false, // Gutenberg: Block Icon in Editor. 'gutenberg_icon' => convertkit_get_file_contents( CONVERTKIT_PLUGIN_PATH . '/resources/backend/images/block-icon-broadcasts.svg' ), // Gutenberg: Example image showing how this block looks when choosing it in Gutenberg. 'gutenberg_example_image' => CONVERTKIT_PLUGIN_URL . 'resources/backend/images/block-example-broadcasts.png', // Help descriptions, displayed when no Access Token / resources exist and this block/shortcode is added. 'no_access_token' => array( 'notice' => __( 'Not connected to Kit.', 'convertkit' ), 'link' => convertkit_get_setup_wizard_plugin_link(), 'link_text' => __( 'Click here to connect your Kit account.', 'convertkit' ), 'instruction_text' => __( 'Connect your Kit account at Settings > Kit, and then refresh this page to configure broadcasts to display.', 'convertkit' ), ), 'no_resources' => array( 'notice' => __( 'No broadcasts exist in Kit.', 'convertkit' ), 'link' => convertkit_get_new_broadcast_url(), 'link_text' => __( 'Click here to send your first broadcast.', 'convertkit' ), 'instruction_text' => __( 'Add a broadcast to your Kit account, and then refresh this page to configure broadcasts to display.', 'convertkit' ), ), // Whether an API Key exists in the Plugin, and are the required resources (broadcasts) available. // If no API Key is specified in the Plugin's settings, render the "No API Key" output. 'has_access_token' => $settings->has_access_and_refresh_token(), 'has_resources' => $posts->exist(), ); } /** * Returns this block's Attributes * * @since 1.9.7.4 */ public function get_attributes() { return array( // Block attributes. 'display_grid' => array( 'type' => 'boolean', 'default' => $this->get_default_value( 'display_grid' ), ), 'display_order' => array( 'type' => 'string', 'default' => $this->get_default_value( 'display_order' ), ), 'date_format' => array( 'type' => 'string', 'default' => $this->get_default_value( 'date_format' ), ), 'display_image' => array( 'type' => 'boolean', 'default' => $this->get_default_value( 'display_image' ), ), 'display_description' => array( 'type' => 'boolean', 'default' => $this->get_default_value( 'display_description' ), ), 'display_read_more' => array( 'type' => 'boolean', 'default' => $this->get_default_value( 'display_read_more' ), ), 'read_more_label' => array( 'type' => 'string', 'default' => $this->get_default_value( 'read_more_label' ), ), 'limit' => array( 'type' => 'number', 'default' => $this->get_default_value( 'limit' ), ), 'page' => array( 'type' => 'number', 'default' => $this->get_default_value( 'page' ), ), 'paginate' => array( 'type' => 'boolean', 'default' => false, ), 'paginate_label_prev' => array( 'type' => 'string', 'default' => $this->get_default_value( 'paginate_label_prev' ), ), 'paginate_label_next' => array( 'type' => 'string', 'default' => $this->get_default_value( 'paginate_label_next' ), ), // get_supports() style, color and typography attributes. 'style' => array( 'type' => 'object', ), 'backgroundColor' => array( 'type' => 'string', ), 'textColor' => array( 'type' => 'string', ), 'fontSize' => array( 'type' => 'string', ), // Always required for Gutenberg. 'is_gutenberg_example' => array( 'type' => 'boolean', 'default' => false, ), ); } /** * Returns this block's supported built-in Attributes. * * @since 1.9.7.4 * * @return array Supports */ public function get_supports() { return array( 'className' => true, 'color' => array( 'link' => true, 'background' => true, 'text' => true, ), 'typography' => array( 'fontSize' => true, 'lineHeight' => true, ), 'spacing' => array( 'margin' => true, 'padding' => true, ), ); } /** * Returns this block's Fields * * @since 1.9.7.4 * * @return bool|array */ public function get_fields() { return array( 'display_grid' => array( 'label' => __( 'Display as grid', 'convertkit' ), 'type' => 'toggle', 'description' => __( 'If enabled, displays broadcasts in a grid, instead of a list.', 'convertkit' ), ), 'display_order' => array( 'label' => __( 'Display order', 'convertkit' ), 'type' => 'select', 'values' => array( 'date-broadcast' => __( 'Date, Broadcast', 'convertkit' ), 'broadcast-date' => __( 'Broadcast, Date', 'convertkit' ), ), ), 'date_format' => array( 'label' => __( 'Date format', 'convertkit' ), 'type' => 'select', 'values' => array( 'F j, Y' => date_i18n( 'F j, Y', strtotime( 'now' ) ), 'Y-m-d' => date_i18n( 'Y-m-d', strtotime( 'now' ) ), 'm/d/Y' => date_i18n( 'm/d/Y', strtotime( 'now' ) ), 'd/m/Y' => date_i18n( 'd/m/Y', strtotime( 'now' ) ), ), ), 'display_image' => array( 'label' => __( 'Display images', 'convertkit' ), 'type' => 'toggle', ), 'display_description' => array( 'label' => __( 'Display descriptions', 'convertkit' ), 'type' => 'toggle', ), 'display_read_more' => array( 'label' => __( 'Display read more links', 'convertkit' ), 'type' => 'toggle', ), 'read_more_label' => array( 'label' => __( 'Read more label', 'convertkit' ), 'type' => 'text', 'description' => __( 'The label to display for the "read more" link below each broadcast.', 'convertkit' ), 'display_if' => array( 'key' => 'display_read_more', 'value' => 1, ), ), 'limit' => array( 'label' => __( 'Number of posts', 'convertkit' ), 'type' => 'number', 'min' => 1, 'max' => 999, 'step' => 1, ), 'paginate' => array( 'label' => __( 'Display pagination', 'convertkit' ), 'type' => 'toggle', 'description' => __( 'If the number of broadcasts exceeds the "Number of posts" settings above, previous/next pagination links will be displayed.', 'convertkit' ), ), 'paginate_label_prev' => array( 'label' => __( 'Newer posts label', 'convertkit' ), 'type' => 'text', 'description' => __( 'The label to display for the link to newer broadcasts.', 'convertkit' ), 'display_if' => array( 'key' => 'paginate', 'value' => 1, ), ), 'paginate_label_next' => array( 'label' => __( 'Older posts label', 'convertkit' ), 'type' => 'text', 'description' => __( 'The label to display for the link to older broadcasts.', 'convertkit' ), 'display_if' => array( 'key' => 'paginate', 'value' => 1, ), ), // These fields will only display on the shortcode, and are deliberately not registered in get_attributes(), // because Gutenberg will register its own color pickers for link, background and text. 'link_color' => array( 'label' => __( 'Link color', 'convertkit' ), 'type' => 'color', ), 'background_color' => array( 'label' => __( 'Background color', 'convertkit' ), 'type' => 'color', ), 'text_color' => array( 'label' => __( 'Text color', 'convertkit' ), 'type' => 'color', ), ); } /** * Returns this block's UI panels / sections. * * @since 1.9.7.4 * * @return bool|array */ public function get_panels() { return array( 'general' => array( 'label' => __( 'General', 'convertkit' ), 'fields' => array( 'display_grid', 'display_order', 'date_format', 'display_image', 'display_description', 'display_read_more', 'read_more_label', ), ), 'pagination' => array( 'label' => __( 'Pagination', 'convertkit' ), 'fields' => array( 'limit', 'paginate', 'paginate_label_prev', 'paginate_label_next', ), ), 'styles' => array( 'label' => __( 'Styles', 'convertkit' ), 'fields' => array( 'link_color', 'background_color', 'text_color', ), ), ); } /** * Returns this block's Default Values * * @since 1.9.7.4 * * @return array */ public function get_default_values() { return array( 'display_grid' => false, 'display_order' => 'date-broadcast', 'date_format' => 'F j, Y', 'display_image' => false, 'display_description' => false, 'display_read_more' => false, 'read_more_label' => __( 'Read more', 'convertkit' ), 'limit' => 10, 'paginate' => false, 'paginate_label_prev' => __( 'Previous', 'convertkit' ), 'paginate_label_next' => __( 'Next', 'convertkit' ), 'link_color' => '', 'background_color' => '', 'text_color' => '', // Built-in Gutenberg block attributes. 'style' => '', 'backgroundColor' => '', 'textColor' => '', // Not output as a block option, but stores the page requested by the user if using pagination without JS. 'page' => $this->get_page(), ); } /** * Returns the block's output, based on the supplied configuration attributes. * * @since 1.9.7.4 * * @param array $atts Block / Shortcode / Page Builder Module Attributes. * @return string */ public function render( $atts ) { // Parse attributes, defining fallback defaults if required // and moving some attributes (such as Gutenberg's styles), if defined. $atts = $this->sanitize_and_declare_atts( $atts ); // Setup Settings class. $settings = new ConvertKit_Settings(); // Fetch Posts. $posts = new ConvertKit_Resource_Posts( 'output_broadcasts' ); // If no Posts exist, bail. if ( ! $posts->exist() ) { if ( $settings->debug_enabled() ) { return ''; } return ''; } // Build HTML. if ( $this->is_block_editor_request() ) { // For the block editor, don't include compiled CSS classes and styles, // as the block editor will add these to the parent container. // Otherwise the block will render incorrectly with double padding, double margins etc. $html = $this->build_html( $posts, $atts, true, array( 'convertkit-' . $this->get_name(), ) ); } else { $html = $this->build_html( $posts, $atts, true, $this->get_css_classes(), $this->get_css_styles( $atts ) ); } /** * Filter the block's content immediately before it is output. * * @since 1.9.7.4 * * @param string $html ConvertKit Broadcasts HTML. * @param array $atts Block Attributes. */ $html = apply_filters( 'convertkit_block_broadcasts_render', $html, $atts ); return $html; } /** * Returns the block's output, based on the supplied configuration attributes, * when requested via AJAX. * * @since 1.9.7.6 * * @param WP_REST_Request $request The REST request. * @return string */ public function render_ajax( $request ) { // Build attributes array. $atts = array( 'date_format' => $request->get_param( 'date_format' ), 'display_image' => $request->get_param( 'display_image' ), 'display_description' => $request->get_param( 'display_description' ), 'display_read_more' => $request->get_param( 'display_read_more' ), 'read_more_label' => $request->get_param( 'read_more_label' ), 'limit' => $request->get_param( 'limit' ), 'page' => $request->get_param( 'page' ), 'paginate' => $request->get_param( 'paginate' ), 'paginate_label_next' => $request->get_param( 'paginate_label_next' ), 'paginate_label_prev' => $request->get_param( 'paginate_label_prev' ), 'link_color' => $request->get_param( 'link_color' ), ); // Parse attributes, defining fallback defaults if required // and moving some attributes (such as Gutenberg's styles), if defined. $atts = $this->sanitize_and_declare_atts( $atts ); // Setup Settings class. $settings = new ConvertKit_Settings(); // Fetch Posts. $posts = new ConvertKit_Resource_Posts( 'output_broadcasts' ); // If no Posts exist, bail. if ( ! $posts->exist() ) { if ( $settings->debug_enabled() ) { return ''; } return ''; } // Build HTML. $html = $this->build_html( $posts, $atts, false ); /** * Filter the block's inner content immediately before it is output by AJAX, * which occurs when pagination was clicked. * * @since 1.9.7.6 * * @param string $html ConvertKit Broadcasts HTML. * @param array $atts Block Attributes. */ $html = apply_filters( 'convertkit_block_broadcasts_render_ajax', $html, $atts ); return $html; } /** * Returns a HTML list of ConvertKit broadcasts, honoring the supplied * attribute's current requested page and limit. * * @since 1.9.7.4 * * @param ConvertKit_Resource_Posts $posts ConvertKit Posts Resource class. * @param array $atts Block attributes. * @param bool $include_container Include container div in HTML. * @param array $css_classes CSS classes to apply to block. * @param array $css_styles CSS inline styles to apply to block. * @return string */ private function build_html( $posts, $atts, $include_container = true, $css_classes = array(), $css_styles = array() ) { // Get paginated subset of Posts. $broadcasts = $posts->get_paginated_subset( $atts['page'], $atts['limit'] ); // Define a nonce to ensure requests made for paginated broadcasts are protected against e.g. CSRF attacks. $nonce = wp_create_nonce( 'convertkit-broadcasts' ); // Define HTML string. $html = ''; // Include container, if required. if ( $include_container ) { $html .= '