Completed
Push — master-stable ( ae7755...f03c30 )
by
unknown
87:13 queued 78:25
created

Jetpack_Portfolio::add_to_sitemap()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 5
rs 9.4286
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
class Jetpack_Portfolio {
4
	const CUSTOM_POST_TYPE       = 'jetpack-portfolio';
5
	const CUSTOM_TAXONOMY_TYPE   = 'jetpack-portfolio-type';
6
	const CUSTOM_TAXONOMY_TAG    = 'jetpack-portfolio-tag';
7
	const OPTION_NAME            = 'jetpack_portfolio';
8
	const OPTION_READING_SETTING = 'jetpack_portfolio_posts_per_page';
9
10
	public $version = '0.1';
11
12
	static function init() {
13
		static $instance = false;
14
15
		if ( ! $instance ) {
16
			$instance = new Jetpack_Portfolio;
17
		}
18
19
		return $instance;
20
	}
21
22
	/**
23
	 * Conditionally hook into WordPress.
24
	 *
25
	 * Setup user option for enabling CPT
26
	 * If user has CPT enabled, show in admin
27
	 */
28
	function __construct() {
29
		// Add an option to enable the CPT
30
		add_action( 'admin_init',                                                      array( $this, 'settings_api_init' ) );
31
32
		// Check on theme switch if theme supports CPT and setting is disabled
33
		add_action( 'after_switch_theme',                                              array( $this, 'activation_post_type_support' ) );
34
35
		// Make sure the post types are loaded for imports
36
		add_action( 'import_start',                                                    array( $this, 'register_post_types' ) );
37
38
		$setting = get_option( self::OPTION_NAME, '0' );
39
40
		// Bail early if Portfolio option is not set and the theme doesn't declare support
41
		if ( empty( $setting ) && ! $this->site_supports_custom_post_type() ) {
42
			return;
43
		}
44
45
		// Enable Omnisearch for Portfolio Items.
46
		if ( class_exists( 'Jetpack_Omnisearch_Posts' ) )
47
			new Jetpack_Omnisearch_Posts( self::CUSTOM_POST_TYPE );
48
49
		// CPT magic
50
		$this->register_post_types();
51
		add_action( sprintf( 'add_option_%s', self::OPTION_NAME ),                     array( $this, 'flush_rules_on_enable' ), 10 );
52
		add_action( sprintf( 'update_option_%s', self::OPTION_NAME ),                  array( $this, 'flush_rules_on_enable' ), 10 );
53
		add_action( sprintf( 'publish_%s', self::CUSTOM_POST_TYPE),                    array( $this, 'flush_rules_on_first_project' ) );
54
		add_action( 'after_switch_theme',                                              array( $this, 'flush_rules_on_switch' ) );
55
56
		// Admin Customization
57
		add_filter( 'post_updated_messages',                                           array( $this, 'updated_messages'   ) );
58
		add_filter( sprintf( 'manage_%s_posts_columns', self::CUSTOM_POST_TYPE),       array( $this, 'edit_admin_columns' ) );
59
		add_filter( sprintf( 'manage_%s_posts_custom_column', self::CUSTOM_POST_TYPE), array( $this, 'image_column'       ), 10, 2 );
60
61
		add_image_size( 'jetpack-portfolio-admin-thumb', 50, 50, true );
62
		add_action( 'admin_enqueue_scripts',                                           array( $this, 'enqueue_admin_styles'  ) );
63
64
		// register jetpack_portfolio shortcode and portfolio shortcode (legacy)
65
		add_shortcode( 'portfolio',                                                    array( $this, 'portfolio_shortcode' ) );
66
		add_shortcode( 'jetpack_portfolio',                                            array( $this, 'portfolio_shortcode' ) );
67
68
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
69
			// Add to Dotcom XML sitemaps
70
			add_filter( 'wpcom_sitemap_post_types',                                    array( $this, 'add_to_sitemap' ) );
71
		} else {
72
			// Add to Jetpack XML sitemap
73
			add_filter( 'jetpack_sitemap_post_types',                                  array( $this, 'add_to_sitemap' ) );
74
		}
75
76
		// Adjust CPT archive and custom taxonomies to obey CPT reading setting
77
		add_filter( 'pre_get_posts',                                                   array( $this, 'query_reading_setting' ) );
78
79
		// If CPT was enabled programatically and no CPT items exist when user switches away, disable
80
		if ( $setting && $this->site_supports_custom_post_type() ) {
81
			add_action( 'switch_theme',                                                array( $this, 'deactivation_post_type_support' ) );
82
		}
83
	}
84
85
	/**
86
	 * Add a checkbox field in 'Settings' > 'Writing'
87
	 * for enabling CPT functionality.
88
	 *
89
	 * @return null
90
	 */
91
	function settings_api_init() {
92
		add_settings_field(
93
			self::OPTION_NAME,
94
			'<span class="cpt-options">' . __( 'Portfolio Projects', 'jetpack' ) . '</span>',
95
			array( $this, 'setting_html' ),
96
			'writing',
97
			'jetpack_cpt_section'
98
		);
99
		register_setting(
100
			'writing',
101
			self::OPTION_NAME,
102
			'intval'
103
		);
104
105
		// Check if CPT is enabled first so that intval doesn't get set to NULL on re-registering
106
		if ( get_option( self::OPTION_NAME, '0' ) || current_theme_supports( self::CUSTOM_POST_TYPE ) ) {
107
			register_setting(
108
				'writing',
109
				self::OPTION_READING_SETTING,
110
				'intval'
111
			);
112
		}
113
	}
114
115
	/**
116
	 * HTML code to display a checkbox true/false option
117
	 * for the Portfolio CPT setting.
118
	 *
119
	 * @return html
120
	 */
121
	function setting_html() {
122 View Code Duplication
		if ( current_theme_supports( self::CUSTOM_POST_TYPE ) ) : ?>
123
			<p><?php printf( __( 'Your theme supports <strong>%s</strong>', 'jetpack' ), self::CUSTOM_POST_TYPE ); ?></p>
124
		<?php else : ?>
125
			<label for="<?php echo esc_attr( self::OPTION_NAME ); ?>">
126
				<input name="<?php echo esc_attr( self::OPTION_NAME ); ?>" id="<?php echo esc_attr( self::OPTION_NAME ); ?>" <?php echo checked( get_option( self::OPTION_NAME, '0' ), true, false ); ?> type="checkbox" value="1" />
127
				<?php esc_html_e( 'Enable Portfolio Projects for this site.', 'jetpack' ); ?>
128
				<a target="_blank" href="http://en.support.wordpress.com/portfolios/"><?php esc_html_e( 'Learn More', 'jetpack' ); ?></a>
129
			</label>
130
		<?php endif;
131
		if ( get_option( self::OPTION_NAME, '0' ) || current_theme_supports( self::CUSTOM_POST_TYPE ) ) :
132
			printf( '<p><label for="%1$s">%2$s</label></p>',
133
				esc_attr( self::OPTION_READING_SETTING ),
134
				sprintf( __( 'Portfolio pages display at most %1$s projects', 'jetpack' ),
135
					sprintf( '<input name="%1$s" id="%1$s" type="number" step="1" min="1" value="%2$s" class="small-text" />',
136
						esc_attr( self::OPTION_READING_SETTING ),
137
						esc_attr( get_option( self::OPTION_READING_SETTING, '10' ) )
138
					)
139
				)
140
			);
141
		endif;
142
	}
143
144
	/**
145
	* Should this Custom Post Type be made available?
146
	*/
147 View Code Duplication
	function site_supports_custom_post_type() {
148
		// If the current theme requests it.
149
		if ( current_theme_supports( self::CUSTOM_POST_TYPE ) || get_option( self::OPTION_NAME, '0' ) ) {
150
			return true;
151
		}
152
153
		// Otherwise, say no unless something wants to filter us to say yes.
154
		/** This action is documented in modules/custom-post-types/nova.php */
155
		return (bool) apply_filters( 'jetpack_enable_cpt', false, self::CUSTOM_POST_TYPE );
156
	}
157
158
	/*
159
	 * Flush permalinks when CPT option is turned on/off
160
	 */
161
	function flush_rules_on_enable() {
162
		flush_rewrite_rules();
163
	}
164
165
	/*
166
	 * Count published projects and flush permalinks when first projects is published
167
	 */
168 View Code Duplication
	function flush_rules_on_first_project() {
169
		$projects = get_transient( 'jetpack-portfolio-count-cache' );
170
171
		if ( false === $projects ) {
172
			flush_rewrite_rules();
173
			$projects = (int) wp_count_posts( self::CUSTOM_POST_TYPE )->publish;
174
175
			if ( ! empty( $projects ) ) {
176
				set_transient( 'jetpack-portfolio-count-cache', $projects, HOUR_IN_SECONDS * 12 );
177
			}
178
		}
179
	}
180
181
	/*
182
	 * Flush permalinks when CPT supported theme is activated
183
	 */
184
	function flush_rules_on_switch() {
185
		if ( current_theme_supports( self::CUSTOM_POST_TYPE ) ) {
186
			flush_rewrite_rules();
187
		}
188
	}
189
190
	/**
191
	 * On plugin/theme activation, check if current theme supports CPT
192
	 */
193
	static function activation_post_type_support() {
194
		if ( current_theme_supports( self::CUSTOM_POST_TYPE ) ) {
195
			update_option( self::OPTION_NAME, '1' );
196
		}
197
	}
198
199
	/**
200
	 * On theme switch, check if CPT item exists and disable if not
201
	 */
202 View Code Duplication
	function deactivation_post_type_support() {
203
		$portfolios = get_posts( array(
204
			'fields'           => 'ids',
205
			'posts_per_page'   => 1,
206
			'post_type'        => self::CUSTOM_POST_TYPE,
207
			'suppress_filters' => false
208
		) );
209
210
		if ( empty( $portfolios ) ) {
211
			update_option( self::OPTION_NAME, '0' );
212
		}
213
	}
214
215
	/**
216
	 * Register Post Type
217
	 */
218
	function register_post_types() {
219
		if ( post_type_exists( self::CUSTOM_POST_TYPE ) ) {
220
			return;
221
		}
222
223
		register_post_type( self::CUSTOM_POST_TYPE, array(
224
			'description' => __( 'Portfolio Items', 'jetpack' ),
225
			'labels' => array(
226
				'name'                  => esc_html__( 'Projects',                   'jetpack' ),
227
				'singular_name'         => esc_html__( 'Project',                    'jetpack' ),
228
				'menu_name'             => esc_html__( 'Portfolio',                  'jetpack' ),
229
				'all_items'             => esc_html__( 'All Projects',               'jetpack' ),
230
				'add_new'               => esc_html__( 'Add New',                    'jetpack' ),
231
				'add_new_item'          => esc_html__( 'Add New Project',            'jetpack' ),
232
				'edit_item'             => esc_html__( 'Edit Project',               'jetpack' ),
233
				'new_item'              => esc_html__( 'New Project',                'jetpack' ),
234
				'view_item'             => esc_html__( 'View Project',               'jetpack' ),
235
				'search_items'          => esc_html__( 'Search Projects',            'jetpack' ),
236
				'not_found'             => esc_html__( 'No Projects found',          'jetpack' ),
237
				'not_found_in_trash'    => esc_html__( 'No Projects found in Trash', 'jetpack' ),
238
				'filter_items_list'     => esc_html__( 'Filter projects list',       'jetpack' ),
239
				'items_list_navigation' => esc_html__( 'Project list navigation',    'jetpack' ),
240
				'items_list'            => esc_html__( 'Projects list',              'jetpack' ),
241
			),
242
			'supports' => array(
243
				'title',
244
				'editor',
245
				'thumbnail',
246
				'author',
247
				'comments',
248
				'publicize',
249
				'wpcom-markdown',
250
			),
251
			'rewrite' => array(
252
				'slug'       => 'portfolio',
253
				'with_front' => false,
254
				'feeds'      => true,
255
				'pages'      => true,
256
			),
257
			'public'          => true,
258
			'show_ui'         => true,
259
			'menu_position'   => 20,                    // below Pages
260
			'menu_icon'       => 'dashicons-portfolio', // 3.8+ dashicon option
261
			'capability_type' => 'page',
262
			'map_meta_cap'    => true,
263
			'taxonomies'      => array( self::CUSTOM_TAXONOMY_TYPE, self::CUSTOM_TAXONOMY_TAG ),
264
			'has_archive'     => true,
265
			'query_var'       => 'portfolio',
266
		) );
267
268
		register_taxonomy( self::CUSTOM_TAXONOMY_TYPE, self::CUSTOM_POST_TYPE, array(
269
			'hierarchical'      => true,
270
			'labels'            => array(
271
				'name'                  => esc_html__( 'Project Types',                 'jetpack' ),
272
				'singular_name'         => esc_html__( 'Project Type',                  'jetpack' ),
273
				'menu_name'             => esc_html__( 'Project Types',                 'jetpack' ),
274
				'all_items'             => esc_html__( 'All Project Types',             'jetpack' ),
275
				'edit_item'             => esc_html__( 'Edit Project Type',             'jetpack' ),
276
				'view_item'             => esc_html__( 'View Project Type',             'jetpack' ),
277
				'update_item'           => esc_html__( 'Update Project Type',           'jetpack' ),
278
				'add_new_item'          => esc_html__( 'Add New Project Type',          'jetpack' ),
279
				'new_item_name'         => esc_html__( 'New Project Type Name',         'jetpack' ),
280
				'parent_item'           => esc_html__( 'Parent Project Type',           'jetpack' ),
281
				'parent_item_colon'     => esc_html__( 'Parent Project Type:',          'jetpack' ),
282
				'search_items'          => esc_html__( 'Search Project Types',          'jetpack' ),
283
				'items_list_navigation' => esc_html__( 'Project type list navigation',  'jetpack' ),
284
				'items_list'            => esc_html__( 'Project type list',             'jetpack' ),
285
			),
286
			'public'            => true,
287
			'show_ui'           => true,
288
			'show_in_nav_menus' => true,
289
			'show_admin_column' => true,
290
			'query_var'         => true,
291
			'rewrite'           => array( 'slug' => 'project-type' ),
292
		) );
293
294
		register_taxonomy( self::CUSTOM_TAXONOMY_TAG, self::CUSTOM_POST_TYPE, array(
295
			'hierarchical'      => false,
296
			'labels'            => array(
297
				'name'                       => esc_html__( 'Project Tags',                   'jetpack' ),
298
				'singular_name'              => esc_html__( 'Project Tag',                    'jetpack' ),
299
				'menu_name'                  => esc_html__( 'Project Tags',                   'jetpack' ),
300
				'all_items'                  => esc_html__( 'All Project Tags',               'jetpack' ),
301
				'edit_item'                  => esc_html__( 'Edit Project Tag',               'jetpack' ),
302
				'view_item'                  => esc_html__( 'View Project Tag',               'jetpack' ),
303
				'update_item'                => esc_html__( 'Update Project Tag',             'jetpack' ),
304
				'add_new_item'               => esc_html__( 'Add New Project Tag',            'jetpack' ),
305
				'new_item_name'              => esc_html__( 'New Project Tag Name',           'jetpack' ),
306
				'search_items'               => esc_html__( 'Search Project Tags',            'jetpack' ),
307
				'popular_items'              => esc_html__( 'Popular Project Tags',           'jetpack' ),
308
				'separate_items_with_commas' => esc_html__( 'Separate tags with commas',      'jetpack' ),
309
				'add_or_remove_items'        => esc_html__( 'Add or remove tags',             'jetpack' ),
310
				'choose_from_most_used'      => esc_html__( 'Choose from the most used tags', 'jetpack' ),
311
				'not_found'                  => esc_html__( 'No tags found.',                 'jetpack' ),
312
				'items_list_navigation'      => esc_html__( 'Project tag list navigation',    'jetpack' ),
313
				'items_list'                 => esc_html__( 'Project tag list',               'jetpack' ),
314
			),
315
			'public'            => true,
316
			'show_ui'           => true,
317
			'show_in_nav_menus' => true,
318
			'show_admin_column' => true,
319
			'query_var'         => true,
320
			'rewrite'           => array( 'slug' => 'project-tag' ),
321
		) );
322
	}
323
324
	/**
325
	 * Update messages for the Portfolio admin.
326
	 */
327 View Code Duplication
	function updated_messages( $messages ) {
328
		global $post;
329
330
		$messages[self::CUSTOM_POST_TYPE] = array(
331
			0  => '', // Unused. Messages start at index 1.
332
			1  => sprintf( __( 'Project updated. <a href="%s">View item</a>', 'jetpack'), esc_url( get_permalink( $post->ID ) ) ),
333
			2  => esc_html__( 'Custom field updated.', 'jetpack' ),
334
			3  => esc_html__( 'Custom field deleted.', 'jetpack' ),
335
			4  => esc_html__( 'Project updated.', 'jetpack' ),
336
			/* translators: %s: date and time of the revision */
337
			5  => isset( $_GET['revision'] ) ? sprintf( esc_html__( 'Project restored to revision from %s', 'jetpack'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
338
			6  => sprintf( __( 'Project published. <a href="%s">View project</a>', 'jetpack' ), esc_url( get_permalink( $post->ID ) ) ),
339
			7  => esc_html__( 'Project saved.', 'jetpack' ),
340
			8  => sprintf( __( 'Project submitted. <a target="_blank" href="%s">Preview project</a>', 'jetpack'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
341
			9  => sprintf( __( 'Project scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview project</a>', 'jetpack' ),
342
			// translators: Publish box date format, see http://php.net/date
343
			date_i18n( __( 'M j, Y @ G:i', 'jetpack' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post->ID ) ) ),
344
			10 => sprintf( __( 'Project item draft updated. <a target="_blank" href="%s">Preview project</a>', 'jetpack' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
345
		);
346
347
		return $messages;
348
	}
349
350
	/**
351
	 * Change ‘Title’ column label
352
	 * Add Featured Image column
353
	 */
354
	function edit_admin_columns( $columns ) {
355
		// change 'Title' to 'Project'
356
		$columns['title'] = __( 'Project', 'jetpack' );
357
		if ( current_theme_supports( 'post-thumbnails' ) ) {
358
			// add featured image before 'Project'
359
			$columns = array_slice( $columns, 0, 1, true ) + array( 'thumbnail' => '' ) + array_slice( $columns, 1, NULL, true );
360
		}
361
362
		return $columns;
363
	}
364
365
	/**
366
	 * Add featured image to column
367
	 */
368
	function image_column( $column, $post_id ) {
369
		global $post;
370
		switch ( $column ) {
371
			case 'thumbnail':
372
				echo get_the_post_thumbnail( $post_id, 'jetpack-portfolio-admin-thumb' );
373
				break;
374
		}
375
	}
376
377
	/**
378
	 * Adjust image column width
379
	 */
380
	function enqueue_admin_styles( $hook ) {
381
		$screen = get_current_screen();
382
383
		if ( 'edit.php' == $hook && self::CUSTOM_POST_TYPE == $screen->post_type && current_theme_supports( 'post-thumbnails' ) ) {
384
			wp_add_inline_style( 'wp-admin', '.manage-column.column-thumbnail { width: 50px; } @media screen and (max-width: 360px) { .column-thumbnail{ display:none; } }' );
385
		}
386
	}
387
388
	/**
389
	 * Follow CPT reading setting on CPT archive and taxonomy pages
390
	 */
391
	function query_reading_setting( $query ) {
392
		if ( ! is_admin() &&
393
			$query->is_main_query() &&
394
			( $query->is_post_type_archive( self::CUSTOM_POST_TYPE ) || $query->is_tax( self::CUSTOM_TAXONOMY_TYPE ) || $query->is_tax( self::CUSTOM_TAXONOMY_TAG ) )
395
		) {
396
			$query->set( 'posts_per_page', get_option( self::OPTION_READING_SETTING, '10' ) );
397
		}
398
	}
399
400
	/**
401
	 * Add CPT to Dotcom sitemap
402
	 */
403
	function add_to_sitemap( $post_types ) {
404
		$post_types[] = self::CUSTOM_POST_TYPE;
405
406
		return $post_types;
407
	}
408
409
	/**
410
	 * Our [portfolio] shortcode.
411
	 * Prints Portfolio data styled to look good on *any* theme.
412
	 *
413
	 * @return portfolio_shortcode_html
414
	 */
415
	static function portfolio_shortcode( $atts ) {
416
		// Default attributes
417
		$atts = shortcode_atts( array(
418
			'display_types'   => true,
419
			'display_tags'    => true,
420
			'display_content' => true,
421
			'display_author'  => false,
422
			'show_filter'     => false,
423
			'include_type'    => false,
424
			'include_tag'     => false,
425
			'columns'         => 2,
426
			'showposts'       => -1,
427
			'order'           => 'asc',
428
			'orderby'         => 'date',
429
		), $atts, 'portfolio' );
430
431
		// A little sanitization
432
		if ( $atts['display_types'] && 'true' != $atts['display_types'] ) {
433
			$atts['display_types'] = false;
434
		}
435
436
		if ( $atts['display_tags'] && 'true' != $atts['display_tags'] ) {
437
			$atts['display_tags'] = false;
438
		}
439
440
		if ( $atts['display_author'] && 'true' != $atts['display_author'] ) {
441
			$atts['display_author'] = false;
442
		}
443
444 View Code Duplication
		if ( $atts['display_content'] && 'true' != $atts['display_content'] && 'full' != $atts['display_content'] ) {
445
			$atts['display_content'] = false;
446
		}
447
448
		if ( $atts['include_type'] ) {
449
			$atts['include_type'] = explode( ',', str_replace( ' ', '', $atts['include_type'] ) );
450
		}
451
452
		if ( $atts['include_tag'] ) {
453
			$atts['include_tag'] = explode( ',', str_replace( ' ', '', $atts['include_tag'] ) );
454
		}
455
456
		$atts['columns'] = absint( $atts['columns'] );
457
458
		$atts['showposts'] = intval( $atts['showposts'] );
459
460
461 View Code Duplication
		if ( $atts['order'] ) {
462
			$atts['order'] = urldecode( $atts['order'] );
463
			$atts['order'] = strtoupper( $atts['order'] );
464
			if ( 'DESC' != $atts['order'] ) {
465
				$atts['order'] = 'ASC';
466
			}
467
		}
468
469 View Code Duplication
		if ( $atts['orderby'] ) {
470
			$atts['orderby'] = urldecode( $atts['orderby'] );
471
			$atts['orderby'] = strtolower( $atts['orderby'] );
472
			$allowed_keys = array( 'author', 'date', 'title', 'rand' );
473
474
			$parsed = array();
475
			foreach ( explode( ',', $atts['orderby'] ) as $portfolio_index_number => $orderby ) {
476
				if ( ! in_array( $orderby, $allowed_keys ) ) {
477
					continue;
478
				}
479
				$parsed[] = $orderby;
480
			}
481
482
			if ( empty( $parsed ) ) {
483
				unset( $atts['orderby'] );
484
			} else {
485
				$atts['orderby'] = implode( ' ', $parsed );
486
			}
487
		}
488
489
		// enqueue shortcode styles when shortcode is used
490
		wp_enqueue_style( 'jetpack-portfolio-style', plugins_url( 'css/portfolio-shortcode.css', __FILE__ ), array(), '20140326' );
491
492
		return self::portfolio_shortcode_html( $atts );
493
	}
494
495
	/**
496
	 * Query to retrieve entries from the Portfolio post_type.
497
	 *
498
	 * @return object
499
	 */
500
	static function portfolio_query( $atts ) {
501
		// Default query arguments
502
		$default = array(
503
			'order'          => $atts['order'],
504
			'orderby'        => $atts['orderby'],
505
			'posts_per_page' => $atts['showposts'],
506
		);
507
508
		$args = wp_parse_args( $atts, $default );
509
		$args['post_type'] = self::CUSTOM_POST_TYPE; // Force this post type
510
511 View Code Duplication
		if ( false != $atts['include_type'] || false != $atts['include_tag'] ) {
512
			$args['tax_query'] = array();
513
		}
514
515
		// If 'include_type' has been set use it on the main query
516 View Code Duplication
		if ( false != $atts['include_type'] ) {
517
			array_push( $args['tax_query'], array(
518
				'taxonomy' => self::CUSTOM_TAXONOMY_TYPE,
519
				'field'    => 'slug',
520
				'terms'    => $atts['include_type'],
521
			) );
522
		}
523
524
		// If 'include_tag' has been set use it on the main query
525 View Code Duplication
		if ( false != $atts['include_tag'] ) {
526
			array_push( $args['tax_query'], array(
527
				'taxonomy' => self::CUSTOM_TAXONOMY_TAG,
528
				'field'    => 'slug',
529
				'terms'    => $atts['include_tag'],
530
			) );
531
		}
532
533 View Code Duplication
		if ( false != $atts['include_type'] && false != $atts['include_tag'] ) {
534
			$args['tax_query']['relation'] = 'AND';
535
		}
536
537
		// Run the query and return
538
		$query = new WP_Query( $args );
539
		return $query;
540
	}
541
542
	/**
543
	 * The Portfolio shortcode loop.
544
	 *
545
	 * @todo add theme color styles
0 ignored issues
show
Coding Style introduced by
Comment refers to a TODO task

This check looks TODO comments that have been left in the code.

``TODO``s show that something is left unfinished and should be attended to.

Loading history...
546
	 * @return html
547
	 */
548
	static function portfolio_shortcode_html( $atts ) {
549
550
		$query = self::portfolio_query( $atts );
551
		$portfolio_index_number = 0;
552
553
		ob_start();
554
555
		// If we have posts, create the html
556
		// with hportfolio markup
557
		if ( $query->have_posts() ) {
558
559
			// Render styles
560
			//self::themecolor_styles();
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
561
562
		?>
563
			<div class="jetpack-portfolio-shortcode column-<?php echo esc_attr( $atts['columns'] ); ?>">
564
			<?php  // open .jetpack-portfolio
565
566
			// Construct the loop...
567
			while ( $query->have_posts() ) {
568
				$query->the_post();
569
				$post_id = get_the_ID();
570
				?>
571
				<div class="portfolio-entry <?php echo esc_attr( self::get_project_class( $portfolio_index_number, $atts['columns'] ) ); ?>">
572
					<header class="portfolio-entry-header">
573
					<?php
574
					// Featured image
575
					echo self::get_portfolio_thumbnail_link( $post_id );
576
					?>
577
578
					<h2 class="portfolio-entry-title"><a href="<?php echo esc_url( get_permalink() ); ?>" title="<?php echo esc_attr( the_title_attribute( ) ); ?>"><?php the_title(); ?></a></h2>
579
580
						<div class="portfolio-entry-meta">
581
						<?php
582
						if ( false != $atts['display_types'] ) {
583
							echo self::get_project_type( $post_id );
584
						}
585
586
						if ( false != $atts['display_tags'] ) {
587
							echo self::get_project_tags( $post_id );
588
						}
589
590
						if ( false != $atts['display_author'] ) {
591
							echo self::get_project_author( $post_id );
0 ignored issues
show
Unused Code introduced by
The call to Jetpack_Portfolio::get_project_author() has too many arguments starting with $post_id.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
592
						}
593
						?>
594
						</div>
595
596
					</header>
597
598
				<?php
599
				// The content
600 View Code Duplication
				if ( false !== $atts['display_content'] ) {
601
					if ( 'full' === $atts['display_content'] ) {
602
					?>
603
						<div class="portfolio-entry-content"><?php the_content(); ?></div>
604
					<?php
605
					} else {
606
					?>
607
						<div class="portfolio-entry-content"><?php the_excerpt(); ?></div>
608
					<?php
609
					}
610
				}
611
				?>
612
				</div><!-- close .portfolio-entry -->
613
				<?php $portfolio_index_number++;
614
			} // end of while loop
615
616
			wp_reset_postdata();
617
			?>
618
			</div><!-- close .jetpack-portfolio -->
619
		<?php
620
		} else { ?>
621
			<p><em><?php _e( 'Your Portfolio Archive currently has no entries. You can start creating them on your dashboard.', 'jetpack' ); ?></p></em>
622
		<?php
623
		}
624
		$html = ob_get_clean();
625
626
		// If there is a [portfolio] within a [portfolio], remove the shortcode
627
		if ( has_shortcode( $html, 'portfolio' ) ){
628
			remove_shortcode( 'portfolio' );
629
		}
630
631
		// Return the HTML block
632
		return $html;
633
	}
634
635
	/**
636
	 * Individual project class
637
	 *
638
	 * @return string
639
	 */
640
	static function get_project_class( $portfolio_index_number, $columns ) {
641
		$project_types = wp_get_object_terms( get_the_ID(), self::CUSTOM_TAXONOMY_TYPE, array( 'fields' => 'slugs' ) );
642
		$class = array();
643
644
		$class[] = 'portfolio-entry-column-'.$columns;
645
		// add a type- class for each project type
646
		foreach ( $project_types as $project_type ) {
647
			$class[] = 'type-' . esc_html( $project_type );
648
		}
649
		if( $columns > 1) {
650
			if ( ( $portfolio_index_number % 2 ) == 0 ) {
651
				$class[] = 'portfolio-entry-mobile-first-item-row';
652
			} else {
653
				$class[] = 'portfolio-entry-mobile-last-item-row';
654
			}
655
		}
656
657
		// add first and last classes to first and last items in a row
658
		if ( ( $portfolio_index_number % $columns ) == 0 ) {
659
			$class[] = 'portfolio-entry-first-item-row';
660
		} elseif ( ( $portfolio_index_number % $columns ) == ( $columns - 1 ) ) {
661
			$class[] = 'portfolio-entry-last-item-row';
662
		}
663
664
665
		/**
666
		 * Filter the class applied to project div in the portfolio
667
		 *
668
		 * @module custom-content-types
669
		 *
670
		 * @since 3.1.0
671
		 *
672
		 * @param string $class class name of the div.
673
		 * @param int $portfolio_index_number iterator count the number of columns up starting from 0.
674
		 * @param int $columns number of columns to display the content in.
675
		 *
676
		 */
677
		return apply_filters( 'portfolio-project-post-class', implode( " ", $class ) , $portfolio_index_number, $columns );
678
	}
679
680
	/**
681
	 * Displays the project type that a project belongs to.
682
	 *
683
	 * @return html
684
	 */
685 View Code Duplication
	static function get_project_type( $post_id ) {
686
		$project_types = get_the_terms( $post_id, self::CUSTOM_TAXONOMY_TYPE );
687
688
		// If no types, return empty string
689
		if ( empty( $project_types ) || is_wp_error( $project_types ) ) {
690
			return;
691
		}
692
693
		$html = '<div class="project-types"><span>' . __( 'Types', 'jetpack' ) . ':</span>';
694
		$types = array();
695
		// Loop thorugh all the types
696
		foreach ( $project_types as $project_type ) {
697
			$project_type_link = get_term_link( $project_type, self::CUSTOM_TAXONOMY_TYPE );
698
699
			if ( is_wp_error( $project_type_link ) ) {
700
				return $project_type_link;
701
			}
702
703
			$types[] = '<a href="' . esc_url( $project_type_link ) . '" rel="tag">' . esc_html( $project_type->name ) . '</a>';
704
		}
705
		$html .= ' '.implode( ', ', $types );
706
		$html .= '</div>';
707
708
		return $html;
709
	}
710
711
	/**
712
	 * Displays the project tags that a project belongs to.
713
	 *
714
	 * @return html
715
	 */
716 View Code Duplication
	static function get_project_tags( $post_id ) {
717
		$project_tags = get_the_terms( $post_id, self::CUSTOM_TAXONOMY_TAG );
718
719
		// If no tags, return empty string
720
		if ( empty( $project_tags ) || is_wp_error( $project_tags ) ) {
721
			return false;
722
		}
723
724
		$html = '<div class="project-tags"><span>' . __( 'Tags', 'jetpack' ) . ':</span>';
725
		$tags = array();
726
		// Loop thorugh all the tags
727
		foreach ( $project_tags as $project_tag ) {
728
			$project_tag_link = get_term_link( $project_tag, self::CUSTOM_TAXONOMY_TYPE );
729
730
			if ( is_wp_error( $project_tag_link ) ) {
731
				return $project_tag_link;
732
			}
733
734
			$tags[] = '<a href="' . esc_url( $project_tag_link ) . '" rel="tag">' . esc_html( $project_tag->name ) . '</a>';
735
		}
736
		$html .= ' '. implode( ', ', $tags );
737
		$html .= '</div>';
738
739
		return $html;
740
	}
741
742
	/**
743
	 * Displays the author of the current portfolio project.
744
	 *
745
	 * @return html
746
	 */
747
	static function get_project_author() {
748
		$html = '<div class="project-author">';
749
		/* translators: %1$s is link to author posts, %2$s is author display name */
750
		$html .= sprintf( __( '<span>Author:</span> <a href="%1$s">%2$s</a>', 'jetpack' ),
751
			esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
752
			esc_html( get_the_author() )
753
		);
754
		$html .= '</div>';
755
756
		return $html;
757
	}
758
759
	/**
760
	 * Display the featured image if it's available
761
	 *
762
	 * @return html
763
	 */
764 View Code Duplication
	static function get_portfolio_thumbnail_link( $post_id ) {
765
		if ( has_post_thumbnail( $post_id ) ) {
766
			/**
767
			 * Change the Portfolio thumbnail size.
768
			 *
769
			 * @module custom-content-types
770
			 *
771
			 * @since 3.4.0
772
			 *
773
			 * @param string|array $var Either a registered size keyword or size array.
774
			 */
775
			return '<a class="portfolio-featured-image" href="' . esc_url( get_permalink( $post_id ) ) . '">' . get_the_post_thumbnail( $post_id, apply_filters( 'jetpack_portfolio_thumbnail_size', 'large' ) ) . '</a>';
776
		}
777
	}
778
}
779
780
add_action( 'init', array( 'Jetpack_Portfolio', 'init' ) );
781
782
// Check on plugin activation if theme supports CPT
783
register_activation_hook( __FILE__,                         array( 'Jetpack_Portfolio', 'activation_post_type_support' ) );
784
add_action( 'jetpack_activate_module_custom-content-types', array( 'Jetpack_Portfolio', 'activation_post_type_support' ) );
785