* @return void */ public function __construct() { // Register the shortcode add_shortcode( 'affilizz-publication', array( $this, 'display' ) ); // Ajax actions add_action( 'wp_ajax_affilizz_render_shortcode', array( $this, 'render_shortcode' ) ); add_action( 'wp_ajax_affilizz_save_shortcode', array( $this, 'save_shortcode' ) ); // Add the shortcode to the list of editable shortcodes add_filter( 'affilizz_editable_shortcodes', array( $this, 'add_editable_shortcode' ) ); } /** * Returns a unique ID for the shortcode. * @author Affilizz * @return Array The list of editable shortcodes. */ public static function get_unique_id() { return substr( str_replace( '0.', '', base_convert( wp_rand() / mt_getrandmax(), 10, 36 ) ), 0, 9 ); } private function request_value( $key, $default = '' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Centralized shortcode AJAX request accessor; callers sanitize based on expected shape. return isset( $_REQUEST[ $key ] ) ? wp_unslash( $_REQUEST[ $key ] ) : $default; } private function request_text( $key, $default = '' ) { return sanitize_text_field( $this->request_value( $key, $default ) ); } /** * Ajax action, save in WordPress options the attributes of a shortcode. * @author Affilizz * @return void */ public function save_shortcode() { global $wpdb; $id = $this->request_text( 'id' ); if ( isset( $id ) && ! empty( $id ) ) { // And update the database table $affilizz_channel = $this->request_text( 'publication_channel_id' ); if ( empty( $affilizz_channel ) ) { $affilizz_channel = get_option( 'affilizz_channel' ); } $publication_id = $this->request_text( 'publication_id' ); if ( empty( $publication_id ) ) { $publication_id = ''; } $publication_content_id = $this->request_text( 'publication_content_id' ); if ( empty( $publication_content_id ) ) { $publication_content_id = ''; } $publication_name = $this->request_text( 'publication_name' ); if ( empty( $publication_name ) ) { $publication_name = ''; } $user_id = $this->request_text( 'user' ); if ( empty( $user_id ) ) { $user_id = get_current_user_id(); } $post_id = $this->request_text( 'post' ); if ( empty( $post_id ) ) { $post_id = 0; } $publication_contents = $this->request_text( 'publication_contents', '{}' ); if ( empty( $publication_contents ) ) { $publication_contents = '{}'; } $group = $this->request_text( 'group', '0' ) === '1'; if ( empty( $group ) ) { $group = false; } \Affilizz\Install::create_table(); global $wpdb; $table = $wpdb->prefix . ( \Affilizz\Core::get_publications_database_table() ); $common_insert_values = array( 'publication_id' => $publication_id, 'publication_channel_id' => $affilizz_channel, 'user_id' => $user_id, 'post_id' => $post_id, ); if ( ! empty( $publication_name ) ) { $common_insert_values['publication_name'] = $publication_name; } $inserted_ids = array(); if ( $group ) { $insert_values = array_merge( $common_insert_values, array( 'id' => $id, 'publication_contents' => $publication_contents, ) ); // Upsert the data // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom plugin table upsert for shortcode state. $result = $wpdb->update( $table, $insert_values, array( 'id' => $id ) ); if ( false === $result || $result < 1 ) { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Custom plugin table upsert fallback for shortcode state. $result = $wpdb->insert( $table, $insert_values ); } if ( $result !== false && $result > 0 ) { $inserted_ids[] = $id; } } else { foreach ( json_decode( $publication_contents, true ) as $index => $publication_content ) { $id = ( $index == 0 ? $id : self::get_unique_id() ); $insert_values = array_merge( $common_insert_values, array( 'id' => $id, 'publication_contents' => wp_json_encode( array( $publication_content ) ), ) ); // Upsert the data // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom plugin table upsert for shortcode state. $result = $wpdb->update( $table, $insert_values, array( 'id' => $id ) ); if ( false === $result || $result < 1 ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Custom plugin table upsert fallback for shortcode state. $result = $wpdb->insert( $table, $insert_values ); } if ( $result !== false && $result > 0 ) { $inserted_ids[] = $id; } } } } echo wp_json_encode( array_merge( array( 'result' => $result, 'inserted_ids' => $inserted_ids, ), $insert_values ), false ); die(); } /** * Ajax action, save in WordPress options the attributes of a shortcode. * @author Affilizz * @return void */ public function render_shortcode() { $cache = $this->request_text( 'cache', 1 ); echo wp_json_encode( array( 'cache' => $cache, 'render' => do_shortcode( '[affilizz-publication cache="' . intval( $cache ) . '" id="' . esc_attr( sanitize_key( $this->request_value( 'id' ) ) ) . '"]' ), ) ); die(); } /** * Composes the render of every publication content in the publication : the webcomponent tags, or in hybrid mode * their stored SSR fragments (never fetched during the render, see \Affilizz\Util\Fragments). * @author Affilizz * @param $affilizz_publication_id The database ID for the publication. * @param $cache Unused since 1.18.0 (it selected the render of the former SSR mode), kept for compatibility. * @param $with_scripts Unused since 1.18.0, kept for compatibility. * @return String The render of the publication contents. */ public function get_publication_render( $affilizz_publication_id, $cache = true, $with_scripts = false ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed, VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Parameters kept for backward compatibility. // If we do not have publication contents selected, return an empty string $publication_object = \Affilizz\Util\Publications::get( $affilizz_publication_id ); if ( empty( $publication_object ) || empty( $publication_object->publication_contents ) ) { return ''; } $publication_contents = json_decode( ( (object) $publication_object )->publication_contents ); $components = \Affilizz\Util\Fragments::get_components( $publication_contents ); // In hybrid mode, use the stored fragments (the editors build their own tags in the administration) $fragments = array(); $locale = ''; if ( ! is_admin() && 'hybrid' === \Affilizz\Core::get_current_rendering_mode( $affilizz_publication_id ) ) { $post_id = (int) get_the_ID(); $fragments = \Affilizz\Util\Fragments::get_instance()->get_fragments( $components, $post_id > 0 ? $post_id : (int) $publication_object->post_id ); // The bare tags render in the fragments' locale : the first widget of a page sets it for all $locale = sprintf( ' custom-locale="%s"', esc_attr( \Affilizz\Util\Fragments::get_widget_locale() ) ); } // Compose the render with webcomponents $render = ''; foreach ( $publication_contents as $publication_content ) { if ( isset( $fragments[ $publication_content->id ] ) ) { $render .= $fragments[ $publication_content->id ]; continue; } $render .= ( 'deal' === $components[ $publication_content->id ] ) ? sprintf( '', $publication_content->id, $locale ) : sprintf( '', $publication_content->id, $locale ); } $render = apply_filters( 'affilizz_publication_content_render', $render ); return $render; } /** * Displays the shortcode template inside the content of the page. * @author Affilizz * @param $attributes The shortcode parameters array. * @param $content The content in which to replace the shortcode, if supplied. * @return String The generated markup. */ public function display( $attributes = array(), $content = '' ) { // Added in 1.15.0 : Allow users to define contexts in which to not process // (Original cause : Timber themes using do_shortcodes in PostPreview / PostExcerpt) $should_display = apply_filters( 'affilizz_should_do_shortcodes', true ); if ( ! $should_display ) { return ''; } do_action( 'before_affilizz_publication_shortcode_output' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Kept for backward compatibility with existing integrations. $cache = ( isset( $attributes['cache'] ) && $attributes['cache'] == '0' ) ? false : true; $result = ( isset( $attributes['id'] ) ) ? $this->get_publication_render( $attributes['id'], $cache ) : ''; if ( empty( $result ) && is_admin() ) { return '
' . esc_html__( 'This publication does not exist in the database. It was either deleted, or its ID does not exist.', 'affilizz' ) . '
'; } do_action( 'after_affilizz_publication_shortcode_output' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Kept for backward compatibility with existing integrations. return $result; } /** * Adds the shortcode to the list of editable shortcodes. * @author Affilizz * @param $shortcodes The list of editable shortcodes. * @return Array The list of editable shortcodes. */ public function add_editable_shortcode( $shortcodes ) { $shortcodes[] = 'affilizz-publication'; return $shortcodes; } }