/**
     * Create a new WordPress Archive.
     *
     * If the query mode is set to "layouts-loop", also automatically create new Loop template.
     *
     * @param string $title New WPA title. Must be unique and valid (see validate_title()).
     * @param array $args (
     *          @type array $view_settings View settings that should override the default ones. Optional.
     *          @type array $loop_settings Loop settings that should override the default ones. Optional.
     *          @type bool $forbid_loop_template Never create a Loop template for this View. Optional, default is false.
     *     )
     *
     * @return WPV_WordPress_Archive New WPA object.
     *
     * @throws InvalidArgumentException
     * @throws RuntimeException
     * @throws WPV_RuntimeExceptionWithMessage
     *
     * @note overriding default Views settings and layout settings must provide complete data when the element is an
     * array, because it overrides them all. For example, $args['settings']['pagination'] can not override just the
     * "postsper page" options: it must provide a complete pagination implementation. This might change and be corrected
     * in the future, keeping backwards compatibility.
     *
     * @since 1.10
     */
    public static function create( $title, $args ) {

        $wpa_id = WPV_View_Base::create_post( $title );

        $wpa = new WPV_WordPress_Archive( $wpa_id );

        $wpa->defer_after_update_actions();

        // Construct default View settings and Loop settings
        $view_settings = wpv_getarr( $args, 'view_settings', array() );

        $query_mode = wpv_getarr( $view_settings, WPV_View_Base::VIEW_SETTINGS_QUERY_MODE, 'archive', array( 'archive', 'layouts-loop' ) );
        $view_settings[ WPV_View_Base::VIEW_SETTINGS_QUERY_MODE ] = $query_mode;
        $is_layouts_loop = ( 'layouts-loop' == $query_mode );

        $view_settings_default = wpv_wordpress_archives_defaults( 'view_settings' );
        $view_settings = wp_parse_args( $view_settings, $view_settings_default );

        $wpa->update_postmeta( WPV_View_Base::POSTMETA_VIEW_SETTINGS, $view_settings );

        $loop_settings_default = wpv_wordpress_archives_defaults( 'view_layout_settings' );

        // Modify default loop output for Layouts loop
        if ( $is_layouts_loop ) {
            $loop_settings_default[ WPV_View_Base::LOOP_SETTINGS_META_HTML ] = str_replace(
                "[/wpv-items-found]",
                "[wpv-archive-pager-prev-page]\n"
                . "\t\t[wpml-string context=\"wpv-views\"]Older posts[/wpml-string]\n"
                . "\t[/wpv-archive-pager-prev-page]\n"
                . "\t[wpv-archive-pager-next-page]\n"
                . "\t\t[wpml-string context=\"wpv-views\"]Newer posts[/wpml-string]\n"
                . "\t[/wpv-archive-pager-next-page]\n"
                . "\t[/wpv-items-found]",
                $loop_settings_default[ WPV_View_Base::LOOP_SETTINGS_META_HTML ]
            );
        }

        $loop_settings = wpv_getarr( $args, 'loop_settings', array() );
        $loop_settings = wp_parse_args( $loop_settings, $loop_settings_default );

        $wpa->update_postmeta( WPV_View_Base::POSTMETA_LOOP_SETTINGS, $loop_settings );

        // Create Loop template for Layouts loop
        $forbid_loop_template = wpv_getarr( $args, 'forbid_loop_template', false );
        if( ! $forbid_loop_template && $is_layouts_loop ) {

            $ct_title = sprintf( '%s - %s', $title, __( 'loop item', 'wpv-views' ) );
            $ct_content = sprintf(
                "<h1>[wpv-post-title]</h1>\n[wpv-post-body view_template=\"None\"]\n[wpv-post-featured-image]\n%s",
                sprintf(__('Posted by %s on %s', 'wpv-views'), '[wpv-post-author]', '[wpv-post-date]' )
            );
            $wpa->create_loop_template( $ct_title, $ct_content );
        }


        $wpa->resume_after_update_actions();

        return $wpa;
    }
function wpv_admin_content_template_listing_name() {

	$mod_url = array( // array of URL modifiers
		'orderby' => '',
		'order' => '',
		's' => '',
		'items_per_page' => '',
		'paged' => '',
		'status' => ''
	);

	$wpv_args = array(
		'post_type' => 'view-template',
		'posts_per_page' => WPV_ITEMS_PER_PAGE,
		'order' => 'ASC',
		'orderby' => 'title',
		'post_status' => 'publish'
	);

	// Apply post_status coming from the URL parameters.
    $post_status = wpv_getget( 'status', 'publish', array( 'publish', 'trash' ) );
	$wpv_args['post_status'] = $post_status;
	$mod_url['status'] = $post_status;
    $the_other_post_status = ( 'publish' == $post_status ) ? 'trash' : 'publish';

	if ( isset( $_GET["s"] ) && '' != $_GET["s"] ) {
		$wpv_args = wpv_modify_wpquery_for_search( $_GET["s"], $wpv_args );
		$mod_url['s'] = sanitize_text_field( $_GET["s"] );
	}

	if ( isset( $_GET["items_per_page"] ) && '' != $_GET["items_per_page"] ) {
		$wpv_args['posts_per_page'] = (int) $_GET["items_per_page"];
		$mod_url['items_per_page'] = (int) $_GET["items_per_page"];
	}

	if ( isset( $_GET["orderby"] ) && '' != $_GET["orderby"] ) {
		$wpv_args['orderby'] = sanitize_text_field($_GET["orderby"]);
		$mod_url['orderby'] = sanitize_text_field($_GET["orderby"]);
		if ( isset( $_GET["order"] ) && '' != $_GET["order"] ) {
			$wpv_args['order'] = sanitize_text_field($_GET["order"]);
			$mod_url['order'] = sanitize_text_field($_GET["order"]);
		}
	}

	if ( isset( $_GET["paged"] ) && '' != $_GET["paged"]) {
		$wpv_args['paged'] = (int) $_GET["paged"];
		$mod_url['paged'] = (int) $_GET["paged"];
	}

    // Build a query for the other post status. We're interested only in post count
    $other_post_status_args = $wpv_args;
    $other_post_status_args['post_status'] = $the_other_post_status;
    $other_post_status_args['fields'] = 'ids';

    // All querying must be done between those two switch_lang() calls otherwise CT translations
    // will be also (wrongly) included.
    global $sitepress;

    $default_language = '';
    if( isset( $sitepress ) ) {
        //changes to the default language
        $default_language = $sitepress->get_default_language();
        $sitepress->switch_lang( $default_language );
    }

	$query = new WP_Query( $wpv_args );

    $other_post_status_query = new WP_Query( $other_post_status_args );

    if( isset( $sitepress ) ) {
        //changes to the current language
        $sitepress->switch_lang( ICL_LANGUAGE_CODE );
    }

    // Number of posts that are being displayed.
    $wpv_count_posts = $query->post_count;

    // Total number of posts matching the query.
    $wpv_found_posts = $query->found_posts;

    // to hold the number of Views in each status
    $ct_counts_by_post_status = array(
        $post_status => $wpv_found_posts,
        $the_other_post_status => $other_post_status_query->found_posts
    );

    // True if some content templates (even those not matching current query) exist.
    $some_posts_exist = ( $ct_counts_by_post_status['publish'] > 0 || $ct_counts_by_post_status['trash'] > 0 );

	$active_nondefault_languages = array();
	$add_translation_icon = '';
	$edit_translation_icon = '';

	$are_cts_translatable = WPV_Content_Template_Embedded::is_translatable();
    if( $are_cts_translatable ) {
        $active_languages = apply_filters( 'wpml_active_languages', array() );

        // just remove the default language
        $active_nondefault_languages = $active_languages;
        unset( $active_nondefault_languages[ $default_language ] );

        // store urls to add/edit translaton icons
        if( defined( 'ICL_PLUGIN_URL' ) ) {
            $add_translation_icon = ICL_PLUGIN_URL . '/res/img/add_translation.png';
            $edit_translation_icon = ICL_PLUGIN_URL . '/res/img/edit_translation.png';
        }
    }

	?>

	<?php
		if ( $some_posts_exist ) {
			?>
			<ul class="subsubsub" style="clear:both"><!-- links to lists WPA in different statuses -->
				<li>
					<?php
						$is_plain_publish_current_status = ( $wpv_args['post_status'] == 'publish' && !isset( $_GET["s"] ) );
						printf(
								'<a href="%s" %s>%s</a> (%s) | ',
								esc_url( add_query_arg(
										array( 'page' => 'view-templates', 'status' => 'publish' ),
										admin_url( 'admin.php' ) ) ),
								$is_plain_publish_current_status ?  ' class="current" ' : '',
								__( 'Published', 'wpv-views' ),
								$ct_counts_by_post_status['publish'] );

					?>
				</li>
				<li>
					<?php
						$is_plain_trash_current_status = ( $wpv_args['post_status'] == 'trash' && !isset( $_GET["s"] ) );
						printf(
								'<a href="%s" %s>%s</a> (%s)',
								esc_url( add_query_arg(
										array( 'page' => 'view-templates', 'status' => 'trash' ),
										admin_url( 'admin.php' ) ) ),
								$is_plain_trash_current_status ?  ' class="current" ' : '',
								__( 'Trash', 'wpv-views' ),
								$ct_counts_by_post_status['trash'] );
					?>
				</li>
			</ul>

			<?php
		} else {
			// No post exist at all
			?>
			<p class="wpv-view-not-exist">
			<?php _e('Content Templates let you design single pages.','wpv-views'); ?>
			</p>
			<p class="add-new-view">
				<button class="button js-add-new-content-template"
				data-target="<?php echo esc_url( add_query_arg( array( 'action' => 'wpv_ct_create_new' ), admin_url( 'admin-ajax.php' ) ) ); ?>">
					<i class="icon-plus"></i><?php _e('Add new Content Template','wpv-views') ?>
				</button>
			</p><?php
		}

        // A nonce for CT action - used for individual as well as for bulk actions.
        // It will have a value only if some posts exist.
        $ct_action_nonce = '';

		if( $some_posts_exist ) {

			$ct_action_nonce = wp_create_nonce( 'wpv_view_listing_actions_nonce' );
			
			// === Render "tablenav" section (Bulk actions and Search box) ===
			echo '<div class="tablenav top">';

			if( $wpv_count_posts > 0 ) {
		
				// Prepare to render bulk actions dropdown.
				if( 'publish' == $wpv_args['post_status'] ) {
					$bulk_actions = array( 'trash' => __( 'Move to trash', 'wpv-views' ) );
				} else {
					$bulk_actions = array(
							'restore-from-trash' => __( 'Restore from trash', 'wpv-views' ),
							'delete' => __( 'Delete permanently', 'wpv-views' ) );
				}

				$bulk_actions_args = array( 'data-viewactionnonce' => $ct_action_nonce );
				$bulk_actions_class = 'js-wpv-ct-listing-bulk-action';

				echo wpv_admin_table_bulk_actions( $bulk_actions, $bulk_actions_class, $bulk_actions_args, 'top' );
			}

			// Show search box
			if ( $wpv_found_posts > 0 ) {
				?>
				<div class="alignright">
					<form id="posts-filter" action="" method="get">
						<p class="search-box">
							<label class="screen-reader-text" for="post-search-input"><?php _e('Search Views:', 'wpv-views') ?></label>
							<?php $search_term = isset( $_GET["s"] ) ? urldecode( sanitize_text_field($_GET["s"]) ) : ''; ?>
							<input type="search" id="ct-post-search-input" name="s" value="<?php echo $search_term; ?>">
							<input type="submit" name="" id="ct-search-submit" class="button" value="<?php echo htmlentities( __('Search Content Templates', 'wpv-views'), ENT_QUOTES ); ?>">
							<input type="hidden" name="paged" value="1" />
						</p>
					</form>
				</div>
				<?php
			}
			
			echo '</div>'; // End of tablenav section
			
		}

		if ( $wpv_count_posts == 0 && $some_posts_exist ) {
			// No posts are displayed, but some exist
			if ( isset( $_GET["s"] ) && '' != $_GET["s"] ) {
				if ( $wpv_args['post_status'] == 'trash' ) {
					// Searching in trash
					?>
					<div class="wpv-views-listing views-empty-list">
						<p>
							<?php
								printf(
										'<p>%s</p><p><a class="button-secondary" href="%s">%s</a></p>',
										__( 'No Content Templates in trash matched your criteria.', 'wpv-views' ),
										wpv_maybe_add_query_arg(
												array(
														'page' => 'view-templates',
														'orderby' => $mod_url['orderby'],
														'order' => $mod_url['order'],
														'items_per_page' => $mod_url['items_per_page'],
														'paged' => '1',
														'status' => 'trash' ),
												admin_url( 'admin.php' ) ),
										__( 'Return', 'wpv-views' ) );
							?>
						</p>
					</div>
					<?php
				} else {
					// Normal search
					?>
					<div class="wpv-views-listing views-empty-list">
						<p>
							<?php
								printf(
										'<p>%s</p><p><a class="button-secondary" href="%s">%s</a></p>',
										__( 'No Content Templates matched your criteria.', 'wpv-views' ),
										wpv_maybe_add_query_arg(
												array(
														'page' => 'view-templates',
														'orderby' => $mod_url['orderby'],
														'order' => $mod_url['order'],
														'items_per_page' => $mod_url['items_per_page'],
														'paged' => '1' ),
												admin_url( 'admin.php' ) ),
										__( 'Return', 'wpv-views' ) );
							?>
						</p>
					</div>
					<?php
				}
			} else {
				if ( $wpv_args['post_status'] == 'trash' ) {
					// No items in trash
					?>
					<div class="wpv-views-listing views-empty-list">
						<p>
							<?php
								printf(
										'<p>%s</p><p><a class="button-secondary" href="%s">%s</a></p>',
										__( 'No Content Templates in trash.', 'wpv-views' ),
										wpv_maybe_add_query_arg(
												array(
														'page' => 'view-templates',
														'orderby' => $mod_url['orderby'],
														'order' => $mod_url['order'],
														'items_per_page' => $mod_url['items_per_page'],
														'paged' => '1' ),
												admin_url( 'admin.php' ) ),
										__( 'Return', 'wpv-views' ) );
							?>
						</p>
					</div>
					<?php
				} else {
					?>
					<p class="wpv-view-not-exist">
						<?php _e('Content Templates let you design single pages.','wpv-views'); ?>
					</p>
					<p class="add-new-view">
						<button class="button js-add-new-content-template"
								data-target="<?php echo esc_url( add_query_arg( array( 'action' => 'wpv_ct_create_new' ), admin_url( 'admin-ajax.php' ) ) ); ?>">
							<i class="icon-plus"></i><?php _e( 'Add new Content Template', 'wpv-views') ?>
						</button>
					</p>
					<?php
				}
			}
			
		} else if ( $wpv_count_posts != 0 ) {
			// We have some results to display.
			
			global $wpdb;

			?>
			
			<table class="wpv-views-listing widefat">

			<!-- section for: sort by name -->
				<thead>
					<?php
						/* To avoid code duplication, table header is stored in output buffer and echoed twice - within
						 * thead and tfoot tags. */
						ob_start();
					?>
					<tr>
						<th class="wpv-admin-listing-col-bulkactions check-column">
							<input type="checkbox" />
						</th>
						<?php
							$column_active = '';
							$column_sort_to = 'ASC';
							$column_sort_now = 'ASC';
							$status = '';
							if ( $wpv_args['orderby'] === 'title' ) {
								$column_active = ' views-list-sort-active';
								$column_sort_to = ( $wpv_args['order'] === 'ASC' ) ? 'DESC' : 'ASC';
								$column_sort_now = $wpv_args['order'];
							}
							if ( isset($_GET['status']) && $_GET['status'] == 'trash' ){
								$status = 'trash';
							}
						?>
						<th class="wpv-admin-listing-col-title">
							<?php
								printf(
										'<a href="%s" class="%s" data-orderby="title">%s <i class="%s"></i></a>',
										wpv_maybe_add_query_arg(
												array(
														'page' => 'view-templates',
														'status' => $status,
														'orderby' => 'title',
														'order' => $column_sort_to,
														's' => $mod_url['s'],
														'items_per_page' => $mod_url['items_per_page'],
														'paged' => $mod_url['paged'] ),
												admin_url( 'admin.php' ) ),
										'js-views-list-sort views-list-sort ' . $column_active,
										__( 'Title', 'wpv-views' ),
										( 'DESC'  === $column_sort_now ) ? 'icon-sort-by-alphabet-alt' : 'icon-sort-by-alphabet' );
							?>
						</th>
                        <?php
                            if( $are_cts_translatable ) {
                                $flag_images = array();

                                foreach( $active_nondefault_languages as $language_info ) {
                                    $flag_images[] = sprintf(
                                        '<img style="padding: 2px;" src="%s" title="%s" alt="%s" />',
                                        $language_info['country_flag_url'],
                                        $language_info['translated_name'],
                                        $language_info['code']
                                    );
                                }
                                if( empty( $flag_images ) ) {
                                    $translation_column_header = __( 'Translations', 'wpv-views' );
                                } else {
                                    $translation_column_header = implode( '', $flag_images );
                                }

                                printf( '<th>%s</th>', $translation_column_header );
                            }
                        ?>
						<th class="wpv-admin-listing-col-usage js-wpv-col-two"><?php _e('Used on','wpv-views') ?></th>
						<?php
							$column_active = '';
							$column_sort_to = 'DESC';
							$column_sort_now = 'DESC';
							if ( $wpv_args['orderby'] === 'date' ) {
								$column_active = ' views-list-sort-active';
								$column_sort_to = ( $wpv_args['order'] === 'ASC' ) ? 'DESC' : 'ASC';
								$column_sort_now = $wpv_args['order'];
							}
						?>
						<th class="wpv-admin-listing-col-date">
							<?php
								printf(
										'<a href="%s" class="%s" data-orderby="date">%s <i class="%s"></i></a>',
										wpv_maybe_add_query_arg(
												array(
														'page' => 'view-templates',
														'status' => $status,
														'orderby' => 'date',
														'order' => $column_sort_to,
														's' => $mod_url['s'],
														'items_per_page' => $mod_url['items_per_page'],
														'paged' => $mod_url['paged'] ),
												admin_url( 'admin.php' ) ),
										'js-views-list-sort views-list-sort ' . $column_active,
										__( 'Date', 'wpv-views' ),
										( 'DESC'  === $column_sort_now ) ? 'icon-sort-by-attributes-alt' : 'icon-sort-by-attributes' );
							?>
						</th>
					</tr>
					<?php
						// Get table header from output buffer and stop buffering
						$table_header = ob_get_contents();
						ob_end_clean();

						echo $table_header;
					?>
				</thead>
				<tfoot>
					<?php
						echo $table_header;
					?>
				</tfoot>

				<tbody class="js-wpv-views-listing-body">
					<?php
					$alternate = '';
					while ( $query->have_posts() ) :
						$query->the_post();
						$post = get_post( get_the_id() );
						$template_id = $post->ID;
                        $ct = WPV_Content_Template::get_instance( $template_id );
						$wpv_content_template_decription  = get_post_meta( $template_id, '_wpv-content-template-decription', true );
						$layout_loop_template_for_view_id = get_post_meta( $template_id, '_view_loop_id', true );
						$alternate = ( ' alternate' == $alternate ) ? '' : ' alternate';
						?>
						<tr id="wpv_ct_list_row_<?php echo $template_id; ?>" class="js-wpv-ct-list-row<?php echo $alternate; ?>">
							<th class="wpv-admin-listing-col-bulkactions check-column">
								<?php
									if ( empty( $layout_loop_template_for_view_id ) ) {
										printf( '<input type="checkbox" value="%s" name="view[]" />', $template_id );
									}
								?>
							</th>
							<td class="wpv-admin-listing-col-title post-title page-title column-title">
								<span class="row-title">
									<?php
										if ( $wpv_args['post_status'] == 'trash' ) {
											echo esc_html( $post->post_title );
										} else {
                                            wpv_ct_editor_render_link( $template_id, esc_html( $post->post_title ) );
										}
									?>
								</span>
								<?php
									if ( ! empty( $wpv_content_template_decription ) ) {
										?>
										<p class="desc">
											<?php echo nl2br( $wpv_content_template_decription )?>
										</p>
										<?php
									}
									/* Generate and show row actions.
									 * Note that we want to add also 'simple' action names to the action list because
									 * they get echoed as a class of the span tag and get styled from WordPress core css
									 * accordingly (e.g. trash in different colour than the rest) */
									$row_actions = array();
									$asigned_count = $wpdb->get_var(
										$wpdb->prepare(
											"SELECT COUNT(post_id) FROM {$wpdb->postmeta} JOIN {$wpdb->posts} p 
											WHERE meta_key = '_views_template' 
											AND meta_value = %s
											AND post_id = p.ID 
											AND p.post_status NOT IN ('auto-draft') 
											AND p.post_type != 'revision'",
											$template_id
										)
									);
									if ( 'publish' == $wpv_args['post_status'] ) {
										$row_actions['edit'] = sprintf(
												'<a href="%s">%s</a>',
												esc_url( add_query_arg(
														array( 'page' => WPV_CT_EDITOR_PAGE_NAME, 'ct_id' => $template_id ),
														admin_url( 'admin.php' ) ) ),
												__( 'Edit', 'wpv-views' ) );
										if ( empty( $layout_loop_template_for_view_id ) ) {
											$row_actions['change js-wpv-ct-change-usage-popup'] = sprintf( '<a href="#">%s</a>', __( 'Change template usage', 'wpv-views' ) );
										}
										$row_actions['duplicate js-list-ct-action-duplicate'] = sprintf( '<a href="#">%s</a>', __( 'Duplicate', 'wpv-views' ) );
										if ( empty( $layout_loop_template_for_view_id ) ) {
											$row_actions['trash js-wpv-ct-action-trash'] = sprintf( '<a href="#">%s</a>', __( 'Move to trash', 'wpv-views' ) );
										}
									} else if ( 'trash' == $wpv_args['post_status'] ) {
										$row_actions['restore-from-trash js-wpv-ct-action-restore-from-trash'] = sprintf( '<a href="#">%s</a>', __( 'Restore from trash', 'wpv-views' ) );
										$row_actions['delete js-list-ct-action-delete'] = sprintf( '<a href="#">%s</a>', __( 'Delete', 'wpv-views' ) );
									}

									echo wpv_admin_table_row_actions( $row_actions,	array(
												"data-ct-id" => $template_id,
												"data-postcount" => $asigned_count,
												"data-ct-name" => htmlentities( $post->post_title, ENT_QUOTES ),
												"data-viewactionnonce" => $ct_action_nonce,
												// Used by the "duplicate" action
												"data-msg" => htmlentities( __( 'Enter new title','wpv-views'), ENT_QUOTES ) 
											)
										);
								?>
							</td>
                            <?php
                                if( $are_cts_translatable ) {
                                    echo '<td>';
                                    $ct_translations = $ct->wpml_translations;

                                    foreach( $active_nondefault_languages as $language_info ) {
                                        $translation = wpv_getarr( $ct_translations, $language_info['code'], null );

                                        if( null == $translation ) {
											$translation_text = __( 'Add translation', 'wpv-views' );
											$translation_icon = $add_translation_icon;
                                        } else {
											$translation_text = __( 'Edit translation', 'wpv-views' );
											$translation_icon = $edit_translation_icon;
                                        }

										$translation_editor_link = $ct->get_wpml_tm_link( $language_info['code'] );
										if( null != $translation_editor_link ) {
											printf(
												'<a style="padding: 2px;" href="%s"><img alt="%s" src="%s" title="%s" /></a>',
												$translation_editor_link,
												$language_info['code'],
												$translation_icon,
												$translation_text
											);
										} else {
											/** @noinspection CssInvalidFunction */
											/** @noinspection CssUnknownProperty */
											printf(
												'<span style="padding: 2px">
													<img alt="%s" src="%s" title="%s" style="-webkit-filter: grayscale(100%%); filter: grayscale(100%%)"/>
												</span>',
												$language_info['code'],
												$translation_icon,
												__( 'WPML Translation Management must be active for this link to work.', 'wpv-view' )
											);
										}
                                    }

                                    echo '</td>';
                                }
                            ?>
							<td class="wpv-admin-listing-col-usage">
								<?php echo wpv_content_template_used_for_list( $template_id ); ?>
							</td>
							<td class="wpv-admin-listing-col-date">
								<?php echo get_the_time( get_option( 'date_format' ), $template_id ); ?>
							</td>
						</tr>
						<?php
					endwhile;
					?>
				</tbody>
			</table>

			<div class="tablenav bottom">
				<?php
					echo wpv_admin_table_bulk_actions( $bulk_actions, $bulk_actions_class, $bulk_actions_args, 'bottom' );
				?>
			</div>


			<p class="add-new-view">
				<button class="button js-add-new-content-template"
						data-target="<?php echo esc_url( add_query_arg( array( 'action' => 'wpv_ct_create_new' ), admin_url( 'admin-ajax.php' ) ) ); ?>">
					<i class="icon-plus"></i><?php _e( 'Add new Content Template','wpv-views' ) ?>
				</button>
			</p>

			<?php
		}

		wpv_admin_listing_pagination( 'view-templates', $wpv_found_posts, $wpv_args["posts_per_page"], $mod_url );

		// Render dialog templates.
		wpv_render_ct_listing_dialog_templates_arrangeby_name();
}
 /**
  * Print column headers.
  */
 protected function print_column_headers()
 {
     $columns = $this->get_column_info();
     /* Get the current 'orderby' URL parameter. Obtain it either from $_GET or from column definitions (if there is
      * a pre-sorted column). If items aren't ordered, it will be an empty string. */
     $current_orderby = wpv_getget('orderby', '');
     if ('' == $current_orderby) {
         // Try to get information from column definitions.
         $current_orderby_column = $this->get_presorted_column();
         $current_orderby = $columns[$current_orderby_column]['orderby'];
         $is_presorted = '' != $current_orderby;
     } else {
         $is_presorted = false;
         $current_orderby_column = $this->get_column_slug_by_orderby($current_orderby);
     }
     // Get the current 'order' URL parameter from $_GET or from column definitions. Defaults to 'ASC' if both methods fail.
     $current_order = wpv_getget('order', '', array('ASC', 'DESC'));
     if ('' == $current_order) {
         if ($is_presorted) {
             $current_order = wpv_getarr($columns[$current_orderby_column], 'default_order', 'ASC', array('ASC', 'DESC'));
         } else {
             $current_order = 'ASC';
         }
     }
     $reverse_order = 'ASC' == $current_order ? 'DESC' : 'ASC';
     // URL that will be used to build sorting links. All URL parameters except 'paged' and 'last_page' will be preserved.
     $current_url = set_url_scheme('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
     $current_url = esc_url(remove_query_arg(array('paged', 'last_page'), $current_url));
     // Print table header cell for each column
     foreach ($columns as $column_slug => $column) {
         $class = array("column-{$column_slug}");
         $is_sortable = wpv_getarr($column, 'is_sortable', false);
         if ($is_sortable) {
             // Sortable column
             // URL 'orderby' parameter for this column
             $column_orderby = wpv_getarr($column, 'orderby', '');
             if ($column_orderby == $current_orderby) {
                 // We're sorting by this column. Build link to reverse order.
                 $new_order = $reverse_order;
                 $new_orderby = $current_orderby;
                 // Append to the title according to current order.
                 $title_order = wpv_getarr($column, 'ASC' == $current_order ? 'title_asc' : 'title_desc', '');
             } else {
                 // Not sorting by this column. Build link to sort by this column, ascending.
                 $new_order = 'ASC';
                 $new_orderby = $column_orderby;
                 $title_order = '';
             }
             $title = sprintf('<a href="%s">%s%s</a>', esc_url(add_query_arg(array('order' => $new_order, 'orderby' => $new_orderby), $current_url)), wpv_getarr($column, 'title', $column_slug), $title_order);
         } else {
             // Non-sortable column, just print the title text.
             $title = wpv_getarr($column, 'title', $column_slug);
         }
         printf('<th scope="col" class="%s">%s</th>', join(' ', $class), $title);
     }
 }
예제 #4
0
 /**
  * Modify edit URLs for Content Templates on Translation Queue in WPML Translation Management.
  *
  * For CT, return URL to CT edit page.
  *
  * @param string $edit_url Current edit URL
  * @param string $content_type For posts, this will be post_{$post_type}.
  * @param int $element_id Post ID if the element is a post.
  *
  * @return string Edit URL.
  *
  * @since 1.10
  */
 public function wpml_document_edit_item_url_ct( $edit_url, $content_type, $element_id ) {
     if ( 'post_' . WPV_Content_Template_Embedded::POST_TYPE == $content_type ) {
         if ( $element_id ) {
             $link = apply_filters( 'icl_post_link', array(), WPV_Content_Template_Embedded::POST_TYPE, $element_id, 'edit' );
             $url = wpv_getarr( $link, 'url' );
             $is_disabled = wpv_getarr( $link, 'is_disabled', false );
             if( $is_disabled ) {
                 $edit_url = ''; // todo check if this works well
             } else if( !empty( $url ) ) {
                 $edit_url = $url;
             }
         }
     }
     
     return $edit_url;
 }
/**
 * Safely retrieve a key from $_GET variable.
 *
 * This is a wrapper for wpv_get_from_array(). See that for more information.
 *
 * @param string $key See wpv_getarr().
 * @param mixed $default See wpv_getarr().
 * @param null|array $valid See wpv_getarr().
 *
 * @return mixed See wpv_getarr().
 *
 * @since 1.8
 */
function wpv_getget( $key, $default = '', $valid = null ) {
    return wpv_getarr( $_GET, $key, $default, $valid );
}
    /**
     * This is a simplified version of wpv_prepare_view_listing_query().
     *
     * Please look up the original function description in order to understand what it does and why.
     *
     * It is equivalent to wpv_prepare_view_listing_query( $view_query_mode, 'publish', array(), false, array() ),
     * with few minor differences:
     *     1. Returned array contains only published_count and post__in keys.
     *     2. Trashed posts are omitted entirely (which makes the query a little bit lighter).
     *     3. For Views settings we don't call $WP_Views->get_views_settings(), which is available only in full version.
     *         Instead we rely on _wpv_settings being present and already containing the 'view-query-mode' key.
     *         According to how this is being accessed in Views embedded now, it shouldn't be a problem.
     *
     * @param $view_query_mode string View query mode. @see wpv_prepare_view_listing_query().
     *
     * @return array @see wpv_prepare_view_listing_query().
     *
     * @since 1.8
     */
    private function prepare_view_listing_query( $view_query_mode ) {
        global $wpdb;

        /* Queries rows with post id and value of _wpv_settings meta (or null if
         * it doesn't exist, notice the LEFT JOIN). */
        $query = "SELECT ID AS id, postmeta.meta_value AS view_settings
			FROM {$wpdb->posts} AS posts
				LEFT JOIN {$wpdb->postmeta} AS postmeta
				ON ( posts.ID = postmeta.post_id AND postmeta.meta_key = '_wpv_settings' )
			WHERE ( posts.post_type = 'view' AND post_status = 'publish' )";
        $views = $wpdb->get_results( $query );

        $post_in = array();

        // Ensure $view_query_mode is an array
        if( !is_array( $view_query_mode ) ) {
            $view_query_mode = array( $view_query_mode );
        }

        /* For each result we need to determine if it's a View or a WPA. If it's what we want, decide by
         * it's post_status which counter to increment and whether to include into post__in (that means possible result
         * in the final listing query). */
        foreach( $views as $view ) {

            // Prepare the value of _wpv_settings postmeta in the same way get_post_meta( ..., ..., true ) would.
            $view_settings = ( null == $view->view_settings ) ? null: maybe_unserialize( $view->view_settings );

            $this_view_query_mode = wpv_getarr( $view_settings, 'view-query-mode', '' );

            // It is the right kind of View?
            if ( in_array( $this_view_query_mode, $view_query_mode ) ) {

                // This is a possible result of the final listing query
                $post_in[] = $view->id;
            }
        }

        $total_count = count( $post_in );

        // If there are no results, we don't want any post to match anything in post__in.
        if( count( $post_in ) == 0 ) {
            $post_in[] = 0;
        }

        $ret = array(
            'published_count' => $total_count,
            'post__in' => $post_in );

        return $ret;
    }
예제 #7
0
    /**
     * Generate Bootstrap grid View layout.
     *
     * @see generate_view_loop_output()
     *
     * @param array $fields Array of fields to be used inside this layout.
     * @param array $args Additional arguments (expected: bootstrap_column_count, bootstrap_version, add_container,
     *     add_row_class, render_individual_columns).
     *
     * @return null|array Null on error (missing bootstrap version), otherwise the array:
     *     array (
     *         @type string $loop_template Loop Output code.
     *         @type string $ct_content Content of the Content Template or an empty string if it's not being used.
     *     )
     *
     * @since 1.10
     */
    private static function generate_bootstrap_grid_layout( $fields, $args ) {

        $column_count = $args['bootstrap_column_count'];

        // Fail if we don't have valid bootstrap version
        $bootstrap_version = wpv_getarr( $args, 'bootstrap_version', 'undefined', array( 2, 3 ) );
        if( 'undefined' == $bootstrap_version ) {
            return null;
        }

        $indent = $args['use_loop_template'] ? "" : "\t\t\t\t";
        $field_codes = WPV_View_Base::generate_field_codes( $fields, $indent );

        // Prevent division by zero
        if( $column_count < 1 ) {
            return null;
        }

        $column_offset = 12 / $column_count;

        $output = '';

        // Row style and cols class for bootstrap 2
        $row_style = ( $bootstrap_version == 2 ) ? ' row-fluid' : '';
        $col_style = ( $bootstrap_version == 2 ) ? 'span' : 'col-sm-';
        $col_class = $col_style . $column_offset;

        // Add row class (optional for bootstrap 2)
        $row_class = ( $args['add_row_class'] || ( 3 == $bootstrap_version ) ) ? 'row' : '';

        if( $args['use_loop_template'] ) {
            $ct_content = $field_codes;
            $loop_item = "<div class=\"$col_class\">[wpv-post-body view_template=\"{$args['loop_template_title']}\"]</div>";
        } else {
            $ct_content = '';
            $loop_item = "<div class=\"$col_class\">\n$field_codes\n\t\t\t</div>";
        }

        if( $args['add_container'] ) {
            $output .= "\t<div class=\"container\">\n";
        }

        $output .= "\t<wpv-loop wrap=\"{$column_count}\" pad=\"true\">\n";

        // If the first column is also a last column, close the div tag.
        $ifone = ( 1 == $column_count ) ? "\n\t\t</div>" : '';

        if( $args['render_individual_columns'] ) {
            // Render items for each column.
            $output .=
                "\t\t[wpv-item index=1]\n"
                . "\t\t<div class=\"{$row_class} {$row_style}\">\n"
                . "\t\t\t$loop_item$ifone\n";
            for( $i = 2; $i < $column_count; ++$i ) {
                $output .=
                    "\t\t[wpv-item index=$i]\n" .
                    "\t\t\t$loop_item\n";
            }
        } else {
            // Render compact HTML
            $output .=
                "\t\t[wpv-item index=1]\n"
                . "\t\t<div class=\"{$row_class} {$row_style}\">\n"
                . "\t\t\t$loop_item$ifone\n"
                . "\t\t[wpv-item index=other]\n"
                . "\t\t\t$loop_item\n";
        }

        // Render item for last column.
        if ( $column_count > 1) {
            $output .=
                "\t\t[wpv-item index=$column_count]\n"
                . "\t\t\t$loop_item\n"
                . "\t\t</div>\n";
        }

        // Padding items
        $output .=
            "\t\t[wpv-item index=pad]\n"
            . "\t\t\t<div class=\"{$col_class}\"></div>\n"
            . "\t\t[wpv-item index=pad-last]\n"
            . "\t\t\t<div class=\"{$col_class}\"></div>\n"
            . "\t\t</div>\n"
            . "\t</wpv-loop>\n\t";

        if ( $args['add_container'] ) {
            $output .= "</div>\n\t";
        }

        return array(
            'loop_template' => $output,
            'ct_content' => $ct_content );
    }
    /**
     * Render the listing page.
     *
     * Use decorators (which MUST be all provided by child classes) to render the page. The logic is the same for
     * all embedded listings.
     */
    function display() {

        $args = $this->get_args();

        // Open page, show the title
        $this->page_decorator->render_page_start();
        $this->title_decorator->render_title( wpv_getarr( $args, 'search', '' ) );

        // If there are some items, render a table. Otherwise render a "no items" message.
        if( $this->item_provider_decorator->has_items( $args ) ) {
            $this->search_form_decorator->render_search_form( $args );
            $items = $this->item_provider_decorator->get_items( $args );
            $this->table_decorator->render_table( $items, $args );
        } else {
            $this->noitems_decorator->render_no_items_content( $args );
        }

        // Pagination
        $this->pagination_decorator->render_pagination( $this->item_provider_decorator->get_total_item_count(), $args );

        // Close page
        $this->page_decorator->render_page_end();
    }
예제 #9
0
/**
 * API function to create a new View
 *
 * @param $args array set of arguments for the new View
 *    'title' (string) (semi-mandatory) Title for the View
 *    'settings' (array) (optional) Array compatible with the View settings to override the defaults
 *    'layout_settings' (array) (optional) Array compatible with the View layout settings to override the defaults
 *
 * @return array response of the operation, one of the following
 *    $return['success] = View ID
 *    $return['error'] = 'Error message'
 *
 * @since 1.6.0
 *
 * @note overriding default Views settings and layout settings must provide complete data when the element is an array, because it overrides them all.
 *    For example, $args['settings']['pagination'] can not override just the "postsper page" options: it must provide a complete pagination implementation.
 *    This might change and be corrected in the future, keeping backwards compatibility.
 *
 * @todo once we create a default layout for a View, we need to make sure that:
 * - the _view_loop_template postmeta is created and updated - DONE
 * - the fields added to that loop Template are stored in the layout settings - PENDING
 * - check how Layouts can apply this all to their Views, to create a Bootstrap loop by default - PENDING
 *
 * @deprecated Since 1.10. Consider using WPV_View::create() or WPV_WordPress_Archive::create() instead.
 */
function wpv_create_view( $args ) {

    $title = wpv_getarr( $args, 'title' );
    $creation_args = $args;

    $view_settings = wpv_getarr( $args, 'settings', array() );
    $creation_args['view_settings'] = $view_settings;

    $query_mode = wpv_getarr( $view_settings, WPV_View_Base::VIEW_SETTINGS_QUERY_MODE, 'normal', array( 'normal', 'archive', 'layouts-loop' ) );

    try {

        if( 'normal' == $query_mode ) {
            $view = WPV_View::create( $title, $creation_args );
            $id = $view->id;
        } else {
            $wpa = WPV_WordPress_Archive::create( $title, $creation_args );
            $id = $wpa->id;
        }
        return array( 'success' => $id );

    } catch( WPV_RuntimeExceptionWithMessage $e ) {
        return array( 'error' => $e->getUserMessage() );
    } catch( Exception $e ) {
        return array( 'error' => __( 'The View could not be created.', 'wpv-views' ) );
    }
}
예제 #10
0
 /**
  * Get "query mode", a value determining what kind of object this is.
  *
  * Allowed values are 'normal', 'archive' and 'layouts-loop'. The value will be an empty string if the query mode
  * is not set for this object (which should never happen, though).
  *
  * @return string
  *
  * @since 1.8
  */
 protected function _get_query_mode()
 {
     $settings = $this->settings;
     // to avoid PHP notice
     return wpv_getarr($settings, 'view-query-mode', '', array('normal', 'archive', 'layouts-loop'));
 }
    /**
     * First time it is called, create the query, save it to $this->query and fill $this->items.
     *
     * @param array $args Query arguments. See class description.
     */
    private function ensure_query( $args ) {

        if( $this->query instanceof WP_Query ) {
            // We've already done this.
            return;
        }

        // Build arguments for WP_Query
        $posts_per_page = (int) wpv_getarr( $args, 'items_per_page', 0 );
        $posts_per_page = ( 0 == $posts_per_page ) ? WPV_ITEMS_PER_PAGE : $posts_per_page;

        $paged = (int) wpv_getarr( $args, 'paged', 0 );
        $paged = ( 0 == $paged ) ? 1 : $paged;

        $query_args = array(
            'post_type' => 'view-template',
            'posts_per_page' => $posts_per_page,
            'paged' => $paged,
            'order' => wpv_getarr( $args, 'order', 'ASC', array( 'ASC', 'DESC' ) ),
            'orderby' => wpv_getarr( $args, 'orderby', 'post_title' ),
            'post_status' => 'publish' );

        $search = wpv_getarr( $args, 'search', '' );
        if( !empty( $search ) ) {
            $query_args['s'] = $search;
        }

        $this->query = new WP_Query( $query_args );

        // Create WPV_Content_Template_Embedded objects from WP_Post objects.
        $this->items = array();
        $posts = $this->query->posts;
        foreach( $posts as $post ) {
            $this->items[] = new WPV_Content_Template_Embedded( $post );
        }

    }
예제 #12
0
	/**
	 * Get information about currently existing archive loops.
	 *
	 * @param string $loop_type Optional. Desired type of loops. 'native'|'post_type'|'taxonomy'|'all'. Default is 'all'.
	 * @param bool $include_wpa Optional. Determines whether the information about WPA assigned to this loop should be
	 *     retrieved (the $wpa element). Default is false.
     * @param bool $include_ct Optional. Determines whether the information about CT assigned to given post type archive
     *     or taxonomy archive should be retrieved (the $ct element). Default is false.
     * @param bool $noexclude Optional. If true, no loops of given type will be excluded. Default is false.
	 *
	 * @return array An array of information about native archive loops and loops for custom post types and taxonomies.
	 *     Each element is an array representing one loop:
	 *     array(
	 *         @type string $slug Unique slug (within loop type) as used in other parts of Views.
	 *         @type string $display_name Display name for the loop.
	 *         @type string $post_type_name For 'post_type' loop type, this will contain "raw" post type slug.
	 *         @type string $loop_type 'native'|'post_type'|'taxonomy'
	 *         @type int $wpa If $include_wpa is true, this contains an ID of WPA assigned to this loop, or zero if
	 *             no WPA is assigned.
     *         @type int $ct If $include_ct is true, this contains an ID of CT assigned to this custom post type
     *             archive or taxonomy archive, or zero if no CT is assigned. This element isn't present for native loops.
     *         @type int $single_ct If $include_ct is true, this contains an ID of CT assigned to single posts of
     *             this custom post type, or zero if no CT is assigned. This element is present only for post types.
	 *     )
	 *
	 * @since 1.7
	 *
     * @todo consider implementing caching mechanism
	 */  
	function get_archive_loops( $loop_type = 'all', $include_wpa = false, $include_ct = false, $noexclude = false ) {

		global $WPV_settings;
		
		switch( $loop_type ) {
		
			case 'native':
				$loops = array(
						array(
								'slug' => 'home-blog-page',
								'option' => 'view_home-blog-page',
								'loop_type' => 'native',
								'display_name' => __( 'Home/Blog', 'wpv-views' ) ),
						array(
								'slug' => 'search-page',
								'option' => 'view_search-page',
								'loop_type' => 'native',
								'display_name' => __( 'Search results', 'wpv-views' ) ),
						array(
								'slug' => 'author-page',
								'option' => 'view_author-page',
								'loop_type' => 'native',
								'display_name' => __( 'Author archives', 'wpv-views' ) ),
						array(
								'slug' => 'year-page',
								'option' => 'view_year-page',
								'loop_type' => 'native',
								'display_name' => __( 'Year archives', 'wpv-views' ) ),
						array(
								'slug' => 'month-page',
								'option' => 'view_month-page',
								'loop_type' => 'native',
								'display_name'  => __( 'Month archives', 'wpv-views' ) ),
						array(
								'slug' => 'day-page',
								'option' => 'view_day-page',
								'loop_type' => 'native',
								'display_name' => __( 'Day archives', 'wpv-views' ) ) );

				if( $include_wpa ) {
					$loop_count = count( $loops );
					for( $i = 0; $i < $loop_count; ++$i ) {
						$option = $loops[ $i ]['option'];
						$loops[ $i ]['wpa'] = isset( $WPV_settings[ $option ] ) ? $WPV_settings[ $option ] : 0;
					}
				}
				return $loops;

			case 'post_type':
			
				$pt_loops = array();
				// Only offer loops for post types that already have an archive, unless $noexclude is given
                $pt_query_args = array( 'public' => true );
                if( !$noexclude ) {
                    $pt_query_args['has_archive'] = true;
                }
				$post_types = get_post_types( $pt_query_args, 'objects' );

				foreach ( $post_types as $post_type ) {
					if ( $noexclude || !in_array( $post_type->name, array( 'post', 'page', 'attachment' ) ) ) {
					
						$loop = array(
								'slug' => 'cpt_' . $post_type->name,
								'post_type_name' => $post_type->name,
								'option' => 'view_cpt_' . $post_type->name,
								'display_name' => $post_type->labels->name,
                                'singular_name' => $post_type->labels->singular_name,
								'loop_type' => 'post_type' );

						if( $include_wpa ) {
							$loop['wpa'] = isset( $WPV_settings[ $loop['option'] ] ) ? $WPV_settings[ $loop['option'] ] : 0;
						}

                        if( $include_ct ) {
                            $loop['ct'] = wpv_getarr( $WPV_settings, "views_template_archive_for_{$post_type->name}", 0 );
                            $loop['single_ct'] = wpv_getarr( $WPV_settings, "views_template_for_{$post_type->name}", 0 );
                        }

						$pt_loops[] = $loop;
					}
				}

				return $pt_loops;

			case 'taxonomy':

				$tx_loops = array();
				$taxonomies = get_taxonomies( '', 'objects' );
				$exclude_tax_slugs = array();
                if( !$noexclude ) {
                    $exclude_tax_slugs = apply_filters('wpv_admin_exclude_tax_slugs', $exclude_tax_slugs);
                }
				foreach ( $taxonomies as $taxonomy_slug => $taxonomy ) {
					if ( in_array( $taxonomy_slug, $exclude_tax_slugs ) ) {
						continue;
					}
					// Only show taxonomies with show_ui set to TRUE
					if ( !$taxonomy->show_ui ) {
						continue;
					}
					
					$loop = array(
							'slug' => $taxonomy->name,
							'option' => 'view_taxonomy_loop_' . $taxonomy->name,
							'display_name' => $taxonomy->labels->singular_name,
							'loop_type' => 'taxonomy' );
							
					if( $include_wpa ) {
						$loop['wpa'] = isset( $WPV_settings[ $loop['option'] ] ) ? $WPV_settings[ $loop['option'] ] : 0;
					}

                    if( $include_ct ) {
                        $loop['ct'] = wpv_getarr( $WPV_settings, "views_template_loop_{$taxonomy->name}", 0 );
                    }
					
					$tx_loops[] = $loop;
				}
					
				return $tx_loops;

			case 'all':
			default:
				return array_merge(
						$this->get_archive_loops( 'native', $include_wpa ),
						$this->get_archive_loops( 'post_type', $include_wpa ),
						$this->get_archive_loops( 'taxonomy', $include_wpa ) );
		}
	}
예제 #13
0
/**
 * Update one or more properties of a Content Template.
 *
 * Note: I've put this into ct-editor.php instead of wpv-admin-ajax.php, because it will most probably
 * be used *only* by Content Template edit page. No need to further bloat that file with single-purpose
 * call handlers. If the usage should change in the future, just move the code to a more appropriate place.
 *     --Jan
 *
 * Following POST parameters are expected:
 * - id: Content Template ID
 * - wpnonce: A valid wpv_ct_{$id}_update_properties_by_{$user_id} nonce.
 * - properties: An array of objects (that will be decoded from JSON to associative arrays),
 *     each of them representing a property with "name" and "value" keys.
 *
 * A WPV_Content_Template object will be instantiated and this function will try to update values of
 * it's properties as defined in the "properties" POST parameter. The "update transaction" mechansim
 * is used for this purpose (see WPV_Post_Object_Wrapper::update_transaction() for details
 * about update logic).
 *
 * It always returns JSON object with a 'success' key. If an "generic" error (like invalid
 * nonce or some invalid arguments) happens, success will be false. Otherwise, if success is true,
 * there will be a 'data' key containing:
 * - 'all_succeeded' - boolean
 * - 'results', an object with property names as keys and booleans indicating that particular
 *   property has been saved successfully (which depends on the logic in WPV_Content_Template),
 *   optionally also containing a "message" property that should be displayed to the user.
 *
 * @since 1.9
 */
function wpv_ct_update_properties_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}_update_properties_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' );
    }

    $properties = wpv_getpost( 'properties' );
    if( !is_array( $properties ) ) {
        wp_send_json_error( 'Invalid arguments (' . print_r( $properties, true ) . ')' );
    }

    // Try to save data as a transaction (all at once or nothing).
    // Refer to WPV_Post_Object_Wrapper::update_transaction() for details.
    $transaction_data = array();
    foreach( $properties as $property ) {
        // Missing property value defaults to empty array because of jQuery.ajax issues with empty arrays.
        // If it's invalid value for the property, it should be rejected during validation - no harm done here.
        $property_value = wpv_getarr( $property, 'value', array() );

        $transaction_data[ $property['name'] ] = $property_value;
    }

    // Run the update transaction.
    // Second parameter is false mostly because vm.processTitleSectionUpdateResults in JS.
    $transaction_result = $ct->update_transaction( $transaction_data, false );

    // Parse the translation result into per-property results that will be returned.
    $results = array();
    foreach( $properties as $property ) {

        $propery_name = $property['name'];
        $result = array( 'name' => $propery_name );

        if( true == $transaction_result['success'] ) {
            // Transaction success == all was updated without errors.
            $result['success'] = true;
        } else if( true == $transaction_result['partial']
            && in_array( $propery_name, $transaction_result['updated_properties'] ) ) {
            // The least desired situation (but rare) where some properties have been updated
            // and some haven't.
            $result['success'] = true;
        } else {
            // Failure, for one or the other reason. Look for an optional error message.
            $result['success'] = false;
            if( array_key_exists( $propery_name, $transaction_result['error_messages'] ) ) {
                $error = $transaction_result['error_messages'][ $propery_name ];
                $result['message'] = $error['message'];
                $result['code'] = $error['code'];
            }
        }

        $results[] = $result;
    }


    // Report success (because the AJAX call succeeded in general) and attach information
    // about each property update.
    wp_send_json_success( array( 'results' => $results ) );
}
예제 #14
0
/**
 * Perform basic authentication check.
 *
 * Check user capability and nonce. Dies with an error message (wp_json_error() by default) if the authentization
 * is not successful.
 *
 * @param string $nonce_name Name of the nonce that should be verified.
 * @param array $args Arguments (
 *     @type string $nonce_parameter Name of the parameter containing nonce value.
 *         Optional, defaults to "wpnonce".
 *     @type string $parameter_source Determines where the function should look for the nonce parameter.
 *         Allowed values are 'get' and 'post'. Optional, defaults to 'post'.
 *     @type string $capability_needed Capability that user has to have in order to pass the check.
 *         Optional, default is "manage_options".
 *     @type string $type_of_death How to indicate failure:
 *         - 'die': The error message will be echoed as a simple string. Default behaviour.
 *         - 'false': Do not die, just return false.
 *         - 'message': Call wp_json_error() and pass message as data.
 *         - 'data': Call wp_json_error with array( 'type' => 'capability'|'nonce', 'message' => $error_message )
 *         Optional, default is 'die'.
 *     )
 *
 * @return bool|void
 *
 * @since 1.9
 */
function wpv_ajax_authenticate( $nonce_name, $args = array() )
{
    // Read arguments
    $type_of_death = wpv_getarr( $args, 'type_of_death', 'die', array( 'die', 'false', 'message', 'data' ) );
    $nonce_parameter = wpv_getarr( $args, 'nonce_parameter', 'wpnonce' );
    $capability_needed = wpv_getarr( $args, 'capability_needed', 'manage_options' );
    $parameter_source_name = wpv_getarr( $args, 'parameter_source', 'post', array( 'get', 'post' ) );
    $parameter_source = ( $parameter_source_name == 'get' ) ? $_GET : $_POST;

    $is_error = false;
    $error_message = null;
    $error_type = null;

    // Check permissions
    if ( ! current_user_can( $capability_needed ) ) {
        $error_message = __( 'You do not have permissions for that.', 'wpv-views' );
        $error_type = 'capability';
        $is_error = true;
    }

    // Check nonce
    if ( !$is_error && !wp_verify_nonce( wpv_getarr( $parameter_source, $nonce_parameter, '' ), $nonce_name ) ) {
        $error_message = __( 'Your security credentials have expired. Please reload the page to get new ones.', 'wpv-views' );
        $error_type = 'nonce';
        $is_error = true;
    }

    if( $is_error ) {
        switch( $type_of_death ) {

            case 'message':
                wp_send_json_error( $error_message );
                break;

            case 'data':
                wp_send_json_error( array( 'type' => $error_type, 'message' => $error_message ) );
                break;

            case 'false':
                return false;

            case 'die':
            default:
                die( $error_message );
                break;
        }
    }

    return true;
}
예제 #15
0
    /**
     * Render the search form.
     *
     * @param array $args
     */
    public function render_search_form( $args )
    {
        $search_term = wpv_getarr( $args, 'search', '' );

        $hidden_fields = array(
            'page' => wpv_getarr( $args, 'page', '' ),
            'items_per_page' => (int) wpv_getarr( $args, 'items_per_page', '' ),
            'paged' => 1 );

        $hidden_fields_flat = array();
        foreach( $hidden_fields as $field_name => $field_value ) {
            $hidden_fields_flat[] = sprintf( '<input type="hidden" name="%s" value="%s" />', $field_name, $field_value );
        }
        $hidden_fields = implode( $hidden_fields_flat );

        ?>
        <div class="alignright">
            <form id="posts-filter" method="get">
                <?php echo $hidden_fields; ?>
                <p class="search-box">
                    <label class="screen-reader-text" for="post-search-input"><?php echo $this->label; ?></label>
                    <input type="search" id="post-search-input" name="search" value="<?php echo $search_term; ?>" />
                    <input type="submit" name="" id="search-submit" class="button" value="<?php echo htmlentities( $this->label, ENT_QUOTES ); ?>" />
                </p>
            </form>
        </div>
        <?php
    }
예제 #16
0
    /**
     * 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;
    }
예제 #17
0
    /**
     * Render pagination controls.
     *
     * @param int $total_item_count Total count of items disregarding pagination.
     * @param array $args Arguments for displaying the page. Currently only 'order' and 'orderby' are supported.
     */
    function render_pagination( $total_item_count, $args )
    {
        $pages_count = ( $this->items_per_page > 0 ) ? ceil( (int) $total_item_count / $this->items_per_page ) : -1;

        if ( $pages_count > 1 ) {

            // Calculate offsets of first and last items displayed
            $items_start = ( ( ( $this->paged - 1 ) * $this->items_per_page ) + 1 );
            $items_end = ( ( ( $this->paged - 1 ) * $this->items_per_page ) + $this->items_per_page );

            if ( $this->paged == $pages_count ) {
                $items_end = $total_item_count;
            }

            // Array of URL parameters to preserve
            $mod_url = array(
                'page' => $this->page_name,
                'orderby' => wpv_getarr( $args, 'orderby', '' ),
                'order' => wpv_getarr( $args, 'order', '' ),
                'search' => wpv_getarr( $args, 'search', '' ),
                'items_per_page' => $this->items_per_page );

            ?>
            <div class="wpv-listing-pagination tablenav">

                <div class="tablenav-pages">

                    <span class="displaying-num">
                        <?php echo __( 'Displaying ', 'wpv-views' ) . "$items_start - $items_end" . __( ' of ', 'wpv-views' ) . $total_item_count; ?>
                    </span>

                    <?php

                    // "Previous page" link
                    if ( $this->paged > 1 ) {

                        $previous_page_args = array_merge( $mod_url, array( 'paged' => $this->paged - 1 ) );

                        printf(
                            '<a href="%s" class="wpv-filter-navigation-link">&laquo; %s</a>',
                            wpv_maybe_add_query_arg( $previous_page_args, admin_url( 'admin.php' ) ),
                            __( 'Previous page', 'wpv-views' ) );
                    }

                    // Page number links
                    for ( $i = 1; $i <= $pages_count; $i++ ) {
                        $classes = ( $this->paged == $i ) ? 'active current' : '';

                        // If this is a last page, we'll add an argument indicating that.
                        $is_last_page = ( $i == $pages_count );

                        $page_number_args = array_merge( $mod_url, array(
                            'paged' => $i,
                            'last_page' => $is_last_page ? '1' : '' ) );

                        printf(
                            '<a href="%s" class="%s">%s</a>',
                            wpv_maybe_add_query_arg( $page_number_args, admin_url( 'admin.php' ) ),
                            $classes,
                            $i );
                    }

                    // "Next page" link
                    if ( $this->paged < $pages_count ) {

                        $is_last_page = ( ( $this->paged + 1 )  == $pages_count );

                        $next_page_args = array_merge( $mod_url, array(
                            'paged' => $this->paged + 1,
                            'last_page' => $is_last_page ? '1' : '' ) );

                        printf(
                            '<a href="%s" class="wpv-filter-navigation-link">%s &raquo;</a>',
                            wpv_maybe_add_query_arg( $next_page_args, admin_url( 'admin.php' ) ),
                            __( 'Next page','wpv-views' ) );
                    }

                    // Items per page switcher
                    _e( 'Items per page', 'wpv-views' );

                    ?>
                    <select class="js-items-per-page">
                        <option value="10" <?php selected( $this->items_per_page == '10' ); ?> >10</option>
                        <option value="20" <?php selected( $this->items_per_page == '20' ); ?> >20</option>
                        <option value="50" <?php selected( $this->items_per_page == '50' ); ?> >50</option>
                    </select>
                    <a href="#" class="js-wpv-display-all-items"><?php _e( 'Display all items', 'wpv-views' ); ?></a>

                </div>
            </div>

        <?php

            } else if ( ( WPV_ITEMS_PER_PAGE != $this->items_per_page ) && ( $total_item_count > WPV_ITEMS_PER_PAGE ) ) {
                // We have only one page, non-default items_per_page setting and more items than we can show in a default setting.
                // Only show a link to reset to defaults.
                ?>
                <div class="wpv-listing-pagination tablenav">
                    <div class="tablenav-pages">
                        <a href="#" class="js-wpv-display-default-items"><?php _e( 'Display 20 items per page', 'wpv-views' ); ?></a>
                    </div>
                </div>
                <?php
            }

        ?>
        <?php
    }