public function for_post($type, $name = false) { if (!$this->needed_components_loaded()) { return false; } global $WPV_settings; $option = sanitize_text_field(sprintf('views_template_for_%s', $type)); // already has an content template if (isset($WPV_settings[$option]) && is_numeric($WPV_settings[$option]) && $WPV_settings[$option] > 0) { return $WPV_settings[$option]; } if (!$name) { $type_object = get_post_type_object($type); $name = sprintf(__('Template for %s', 'types'), $type_object->labels->name); } $name = $this->validate_name($name); if (!$name) { return false; } $ct = WPV_Content_Template::create($name); $ct_post = get_post($ct->id); if ($ct_post === null) { return false; } $WPV_settings[$option] = $ct_post->ID; $WPV_settings->save(); $posts = get_posts('post_type=' . $type . '&post_status=any&posts_per_page=-1&fields=ids'); foreach ($posts as $id) { $ct = get_post_meta($id, '_views_template', true); if (empty($ct)) { update_post_meta($id, '_views_template', $ct_post->ID); } } return $ct_post->ID; }
/** * Creates a content template for a given post type * * @param $type * @param bool|string $name Name for the Content Template * * @return bool * @since 2.0 */ public function for_post($type, $name = false) { // abort if any needed dependency is not available if (!$this->needed_components_loaded()) { return false; } global $WPV_settings; // option key for Views Content Templates is "views_template_for_{post-type-name}" $option = sanitize_text_field(sprintf('views_template_for_%s', $type)); // already has an content template if (isset($WPV_settings[$option]) && is_numeric($WPV_settings[$option]) && $WPV_settings[$option] > 0) { return $WPV_settings[$option]; } // create name if not given if (!$name) { $type_object = get_post_type_object($type); $name = sprintf(__('Template for %s', 'types'), $type_object->labels->name); } $name = $this->validate_name($name); // abort if name not valid (shouldn't happen, see validate_name()) if (!$name) { return false; } // create template $ct = WPV_Content_Template::create($name); $ct_post = get_post($ct->id); if ($ct_post === null) { return false; } $WPV_settings[$option] = $ct_post->ID; $WPV_settings->save(); // get all posts of post type to assign the new content template $posts = get_posts('post_type=' . $type . '&post_status=any&posts_per_page=-1&fields=ids'); foreach ($posts as $id) { $ct = get_post_meta($id, '_views_template', true); // only assign if there is not already an assigned content template if (empty($ct)) { update_post_meta($id, '_views_template', $ct_post->ID); } } return $ct_post->ID; }
/** * Duplicate a loop template of a View and update references to it. * * @todo detailed description * * @param array $new_postmeta_values Array of postmeta of the View. * @param int $new_post_id ID of the View. * @param string $new_post_title Post title of the View. * * @return array Updated array of postmeta values of the View. */ private function duplicate_loop_template( $new_postmeta_values, $new_post_id, $new_post_title ) { // This will throw an exception if the original CT can't be accessed $original_ct = new WPV_Content_Template( $this->loop_template_id ); // Clone the Content Template acting as a Loop template $cloned_ct = $original_ct->clone_this( sprintf( __( 'Loop item in %s', 'wpv-views' ), $new_post_title ), true ); if( null == $cloned_ct ) { throw new RuntimeException( 'unable to clone loop template' ); } // Cloning was successful. // Create reference from new View to new Loop template. $new_postmeta_values[ WPV_View_Base::POSTMETA_LOOP_TEMPLATE_ID ] = $cloned_ct->id; // Create reference from new Loop template to new View. $cloned_ct->loop_output_id = $new_post_id; // Process inline Content templates if there are any. // @todo can this be done cleaner? $inline_templates = wpv_getarr( $new_postmeta_values['_wpv_layout_settings'], 'included_ct_ids', '' ); if ( !empty( $inline_templates ) ) { $inline_templates = explode( ',', $inline_templates ); // Go through all inline templates (referenced in original View) and if we find a reference // to original Loop template, we will replace it with new one. foreach ( $inline_templates as $inline_template_key => $inline_template_id ) { if ( $inline_template_id == $this->loop_template_id ) { // Replace with new Loop template. $inline_templates[ $inline_template_key ] = $cloned_ct->id; } } // Update the array of inline Content templates. $new_postmeta_values['_wpv_layout_settings']['included_ct_ids'] = implode( ',', $inline_templates ); } // Replace name of the old Loop template with new name in Loop output. $loop_output = wpv_getarr( $new_postmeta_values['_wpv_layout_settings'], 'layout_meta_html', '' ); if ( !empty( $loop_output ) ) { // Search and replace Loop template titles // todo we also need to check for slugs // todo consider allways replacing by slug, title could contain quotes at this point $new_loop_output = str_replace( sprintf( 'view_template="%s"', $original_ct->title ), sprintf( 'view_template="%s"', sanitize_text_field( $cloned_ct->title ) ), $loop_output ); // Save new value $new_postmeta_values['_wpv_layout_settings']['layout_meta_html'] = $new_loop_output; } return $new_postmeta_values; }
/** * Bind specific posts to a Content Template. * * Following POST parameters are expected: * - id: Content Template ID * - wpnonce: A valid wpv_ct_{$id}_bind_posts_by_{$user_id} nonce. * - posts_to_bind: An array of post IDs that should be bound. * * Returns a default WP json response (error/success), possibly with a debug message * on error. * * @since 1.9 */ function wpv_ct_bind_posts_callback() { // Authentication and validation if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'Untrusted user' ); } $ct_id = (int) wpv_getpost( 'id' ); $uid = get_current_user_id(); $nonce_name = "wpv_ct_{$ct_id}_bind_posts_by_{$uid}"; if ( ! wp_verify_nonce( wpv_getpost( 'wpnonce' ), $nonce_name ) ) { wp_send_json_error( "Security check ($nonce_name)" ); } $ct = WPV_Content_Template::get_instance( $ct_id ); if( null == $ct ) { wp_send_json_error( 'Invalid Content Template' ); } $posts_to_bind = wpv_getpost( 'posts_to_bind' ); if( !is_array( $posts_to_bind ) ) { wp_send_json_error( 'Invalid arguments (' . print_r( $posts_to_bind, true ) . ')' ); } // Post binding $updated = $ct->bind_posts( $posts_to_bind ); if( false === $updated ) { wp_send_json_error( 'bind_posts failed' ); } wp_send_json_success( array( 'updated' => $updated ) ); }
function wpv_admin_menu_content_template_listing_by_type_row( $sort, $page = 0 ) { global $WPV_settings, $post; $post_types_array = wpv_get_pt_tax_array(); ob_start(); if ( $sort == 'usage-single' ){ $counter = count( $post_types_array['single_post'] ); $alternate = ''; for ( $i = 0; $i < $counter; ++$i ) { $type = $post_types_array['single_post'][ $i ][0]; $label = $post_types_array['single_post'][ $i ][1]; $alternate = ' alternate' == $alternate ? '' : ' alternate'; ?> <tr id="wpv_ct_list_row_<?php echo $type; ?>" class="js-wpv-ct-list-row<?php echo $alternate; ?>"> <td class="wpv-admin-listing-col-usage post-title page-title column-title"> <span class="row-title"> <?php echo $label;?> </span> <?php $row_actions = array( "change_pt js-wpv-change-ct-assigned-to-something-popup" => sprintf( '<a href="#">%s</a>', __('Change Content Template','wpv-views') ) ); echo wpv_admin_table_row_actions( $row_actions, array( "data-pt" => 'views_template_for_' . $type ) ); ?> </td> <td class="wpv-admin-listing-col-used-title"> <ul> <?php $add_button = wpv_ct_listing_render_create_ct_button( sprintf( __( 'Create a Content Template for single %s', 'wpv-views' ), $label ), $label, array( 'single_post_types' => array( $type ) ) ); if ( isset( $WPV_settings[ 'views_template_for_' . $type ] ) && $WPV_settings[ 'views_template_for_' . $type ] != 0 ) { // There is a Content Template assigned for single posts of this type $ct_id = $WPV_settings[ 'views_template_for_' . $type ]; $ct = WPV_Content_Template::get_instance( $ct_id ); if ( null != $ct ) { printf( '<a href="%s">%s</a>', esc_url( add_query_arg( array( 'page' => WPV_CT_EDITOR_PAGE_NAME, 'ct_id' => $ct->id, 'action' => 'edit' ), admin_url( 'admin.php' ) ) ), $ct->title ); // @todo We do not need the exact number here, let's create a has_dissident_posts method instead with a LIMITed query $dissident_post_count = $ct->get_dissident_posts( $type, 'count' ); if ( $dissident_post_count > 0 ) { ?> <span class="js-wpv-apply-ct-to-cpt-single-<?php echo $type; ?>"> <?php printf( '<a class="%s" data-type="%s" data-id="%s" data-nonce="%s"> %s</a>', 'button button-small button-leveled icon-warning-sign js-wpv-apply-ct-to-all-cpt-single-dialog', $type, $ct->id, wp_create_nonce( 'work_view_template' ), sprintf( __( 'Bind %u %s ', 'wpv-views' ), $dissident_post_count, $label ) ); ?> </span> <?php } //} } else { echo $add_button; } } else { // Single posts of this type have no Content Template assigned echo $add_button; $assigned_posts_count = WPV_Content_Template_Embedded::get_posts_using_content_template_by_type( $type, 'count' ); if ( $assigned_posts_count > 0 ) { ?> <a class="button button-small js-wpv-clear-cpt-from-ct-popup" href="#" data-unclear="<?php echo $assigned_posts_count; ?>" data-slug="<?php echo $type; ?>" data-label="<?php echo htmlentities( $label, ENT_QUOTES ); ?>"> <i class="icon-unlink"></i> <?php echo sprintf( __('Clear %d %s', 'wpv-views'), $assigned_posts_count, $label ); ?> </a> <?php } } ?> </ul> </td> </tr> <?php } } else if ( $sort == 'usage-post-archives' ){ $alternate = ''; $counter = count( $post_types_array['archive_post'] ); for ( $i = 0; $i < $counter; ++$i ) { $type = $post_types_array['archive_post'][ $i ][0]; $label = $post_types_array['archive_post'][ $i ][1]; $add_button = wpv_ct_listing_render_create_ct_button( __( 'Add a new Content Template for this post type', 'wpv-views' ), $label, array( 'post_archives' => array( $type ) ) ); $alternate = ' alternate' == $alternate ? '' : ' alternate'; ?> <tr id="wpv_ct_list_row_<?php echo $type; ?>" class="js-wpv-ct-list-row<?php echo $alternate; ?>"> <td class="post-title page-title column-title"> <span class="row-title"> <?php echo $label; ?> </span> <?php $row_actions = array( "change_pt js-wpv-change-ct-assigned-to-something-popup" => sprintf( '<a href="#">%s</a>', __( 'Change Content Template', 'wpv-views' ) ) ); echo wpv_admin_table_row_actions( $row_actions, array( "data-pt" => 'views_template_archive_for_' . $type ) ); ?> </td> <td> <ul> <?php if ( isset( $WPV_settings[ 'views_template_archive_for_' . $type ] ) && $WPV_settings[ 'views_template_archive_for_' . $type ] != 0) { $post = get_post( $WPV_settings[ 'views_template_archive_for_' . $type ] ); if ( is_object( $post ) ) { wpv_ct_editor_render_link( $post->ID, esc_html( $post->post_title ) ); } else { echo $add_button; } } else { echo $add_button; } ?> </ul> </td> </tr> <?php } } else if ( $sort == 'usage-taxonomy-archives' ){ $counter = count( $post_types_array['taxonomy_post'] ); $alternate = ''; for ( $i = 0; $i < $counter; ++$i ) { $type = $post_types_array['taxonomy_post'][ $i ][0]; $label = $post_types_array['taxonomy_post'][ $i ][1]; $add_button = wpv_ct_listing_render_create_ct_button( __( 'Add a new Content Template for this taxonomy', 'wpv-views' ), $label, array( 'taxonomy_archives' => array( $type ) ) ); $alternate = ' alternate' == $alternate ? '' : ' alternate'; ?> <tr id="wpv_ct_list_row_<?php echo $type; ?>" class="js-wpv-ct-list-row<?php echo $alternate; ?>"> <td class="post-title page-title column-title"> <span class="row-title"> <?php echo $label;?> </span> <?php $row_actions = array( "change_pt js-wpv-change-ct-assigned-to-something-popup" => sprintf( '<a href="#">%s</a>', __( 'Change Content Template', 'wpv-views' ) ) ); echo wpv_admin_table_row_actions( $row_actions, array( "data-pt" => 'views_template_loop_' . $type ) ); ?> </td> <td> <ul> <?php if ( isset( $WPV_settings[ 'views_template_loop_' . $type ] ) && $WPV_settings[ 'views_template_loop_' . $type ] != 0 ) { $post = get_post( $WPV_settings['views_template_loop_' . $type] ); if ( is_object( $post ) ) { wpv_ct_editor_render_link( $post->ID, esc_html( $post->post_title ) ); } else { echo $add_button; } } else { echo $add_button; } ?> </ul> </td> </tr> <?php } } $row = ob_get_contents(); ob_end_clean(); return $row; }
/** * Clone a Content Template. * * @param string $title Title of the new CT. * @param bool $adjust_duplicate_title If true, the title might get changed in order to ensure it's uniqueness. * Otherwise, if $title is not unique, the cloning will fail. * @return null|WPV_Content_Template The cloned CT or null on failure. * * @since 1.9 */ public function clone_this( $title, $adjust_duplicate_title = true ) { // Create new CT $cloned_ct = WPV_Content_Template::create( $title, $adjust_duplicate_title ); if( null == $cloned_ct ) { return null; } // Copy postmeta $cloned_ct->defer_after_update_actions(); $postmeta_defaults = $this->get_postmeta_defaults(); foreach( $postmeta_defaults as $meta_key => $ignored_value ) { if( !in_array( $meta_key, WPV_Content_Template::$postmeta_keys_not_to_clone ) ) { $cloned_ct->update_postmeta( $meta_key, $this->get_postmeta( $meta_key ) ); } } $cloned_ct->resume_after_update_actions(); // Copy content $cloned_ct->content_raw = $this->content_raw; return $cloned_ct; }
/** * Create new Content Template and set it as this View's Loop template. * * Note that this method doesn't care about existing Loop template. That should be handled separately before it * is called. * * @param string $title Valid title for the Content Template (will be adjusted if not unique). * @param string $content Content of the CT * @throws RuntimeException * @return WPV_Content_Template Newly created CT. * @since 1.10 */ public function create_loop_template( $title, $content = '[wpv-post-link]' ) { $ct = WPV_Content_Template::create( $title, true ); if( null == $ct ) { throw new RuntimeException( 'couldn\'t create the loop template' ); } $ct->defer_after_update_actions(); // Update Loop output and content of the Loop template $ct->content = $content; $this->loop_meta_html = str_replace( '<wpv-loop>', sprintf( "<wpv-loop>\n\t\t\t[wpv-post-body view_template=\"%s\"]", $ct->title ), $this->loop_meta_html ); // Create bindings between View and Loop template $this->loop_included_ct_ids = $ct->id; $this->loop_template_id = $ct->id; $ct->loop_output_id = $this->id; $ct->resume_after_update_actions(); return $ct; }
/** * wpv_create_content_template * * Creates a new Content Template given a title and an optional suffix. * * Consider using WPV_Content_Template::create_new directly. * * @note Used by Layouts plugin. * * @param string $title * @param string $suffix * @param bool $force Whether to force the creation of the Template by incremental numbers added to the title in case it is already in use * @param string $content * * @return array { * 'success' => (int) The ID of the CT created * 'error' => (string) Error message * 'title' => (string) The title of the CT created or the one that made this fail * * @since 1.7 */ function wpv_create_content_template( $title, $suffix = '', $force = true, $content = '' ) { $real_suffix = ''; if ( ! empty( $suffix ) ) { $real_suffix = ' - ' . $suffix; } $template_title = $title . $real_suffix; $result = array(); if( $force ) { $ct = WPV_Content_Template::create( $template_title, true ); } else { if( WPV_Content_Template::is_name_used( $template_title ) ) { $result['error'] = __( 'A Content Template with that title already exists. Please use another title.', 'wpv-views' ); $result['title'] = $template_title; return $result; } $ct = WPV_Content_Template::create( $template_title, false ); } if( null == $ct ) { $return['title'] = $template_title; $return['error'] = __( 'An error occurred while creating a Content Template.', 'wpv-views' ); } else { $return['title'] = $ct->title; try { $ct->content_raw = $content; $return['success'] = $ct->id; } catch( Exception $e ) { $return['error'] = __( 'An error occurred while creating a Content Template.', 'wpv-views' ); } } return $return; }
/** * Adjust link to Content Template edit page for full Views. * * See icl_post_link for parameter description. * * @param $link * @param $post_type * @param $post_id * @param $link_purpose * @return array * * @since 1.10 */ function wpv_ct_post_link( $link, $post_type, $post_id, $link_purpose ) { global $WP_Views; if( !$WP_Views->is_embedded() && ( WPV_Content_Template_Embedded::POST_TYPE == $post_type ) && ( 'edit' == $link_purpose ) ) { // Full Views, CT edit link is requested if( !is_array( $link ) ) { $link = array(); } // If CT is trashed or non-existent, disable the link. $ct = WPV_Content_Template::get_instance( $post_id ); if( ( null == $ct ) || $ct->is_trashed ) { $link['is_disabled'] = true; } else { $link['is_disabled'] = false; $link['url'] = wpv_ct_editor_url( $post_id, false ); } } return $link; }