Completed
Push — add/changelog-62 ( 9977bb...d371c2 )
by
unknown
10:21
created

Jetpack_Portfolio::__construct()   B

Complexity

Conditions 8
Paths 9

Size

Total Lines 60
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 30
nc 9
nop 0
dl 0
loc 60
rs 7.0677
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
		// Add to REST API post type whitelist
39
		add_filter( 'rest_api_allowed_post_types',                                     array( $this, 'allow_portfolio_rest_api_type' ) );
40
41
		$setting = Jetpack_Options::get_option_and_ensure_autoload( self::OPTION_NAME, '0' );
42
43
		// Bail early if Portfolio option is not set and the theme doesn't declare support
44
		if ( empty( $setting ) && ! $this->site_supports_custom_post_type() ) {
45
			return;
46
		}
47
48
		// Enable Omnisearch for Portfolio Items.
49
		if ( class_exists( 'Jetpack_Omnisearch_Posts' ) )
50
			new Jetpack_Omnisearch_Posts( self::CUSTOM_POST_TYPE );
51
52
		// CPT magic
53
		$this->register_post_types();
54
		add_action( sprintf( 'add_option_%s', self::OPTION_NAME ),                     array( $this, 'flush_rules_on_enable' ), 10 );
55
		add_action( sprintf( 'update_option_%s', self::OPTION_NAME ),                  array( $this, 'flush_rules_on_enable' ), 10 );
56
		add_action( sprintf( 'publish_%s', self::CUSTOM_POST_TYPE),                    array( $this, 'flush_rules_on_first_project' ) );
57
		add_action( 'after_switch_theme',                                              array( $this, 'flush_rules_on_switch' ) );
58
59
		// Admin Customization
60
		add_filter( 'post_updated_messages',                                           array( $this, 'updated_messages'   ) );
61
		add_filter( sprintf( 'manage_%s_posts_columns', self::CUSTOM_POST_TYPE),       array( $this, 'edit_admin_columns' ) );
62
		add_filter( sprintf( 'manage_%s_posts_custom_column', self::CUSTOM_POST_TYPE), array( $this, 'image_column'       ), 10, 2 );
63
		add_action( 'customize_register',                                              array( $this, 'customize_register' ) );
64
65
		add_image_size( 'jetpack-portfolio-admin-thumb', 50, 50, true );
66
		add_action( 'admin_enqueue_scripts',                                           array( $this, 'enqueue_admin_styles'  ) );
67
68
		// register jetpack_portfolio shortcode and portfolio shortcode (legacy)
69
		add_shortcode( 'portfolio',                                                    array( $this, 'portfolio_shortcode' ) );
70
		add_shortcode( 'jetpack_portfolio',                                            array( $this, 'portfolio_shortcode' ) );
71
72
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
73
			// Add to Dotcom XML sitemaps
74
			add_filter( 'wpcom_sitemap_post_types',                                    array( $this, 'add_to_sitemap' ) );
75
		} else {
76
			// Add to Jetpack XML sitemap
77
			add_filter( 'jetpack_sitemap_post_types',                                  array( $this, 'add_to_sitemap' ) );
78
		}
79
80
		// Adjust CPT archive and custom taxonomies to obey CPT reading setting
81
		add_filter( 'pre_get_posts',                                                   array( $this, 'query_reading_setting' ) );
82
83
		// If CPT was enabled programatically and no CPT items exist when user switches away, disable
84
		if ( $setting && $this->site_supports_custom_post_type() ) {
85
			add_action( 'switch_theme',                                                array( $this, 'deactivation_post_type_support' ) );
86
		}
87
	}
88
89
	/**
90
	 * Add a checkbox field in 'Settings' > 'Writing'
91
	 * for enabling CPT functionality.
92
	 *
93
	 * @return null
94
	 */
95
	function settings_api_init() {
96
		add_settings_field(
97
			self::OPTION_NAME,
98
			'<span class="cpt-options">' . __( 'Portfolio Projects', 'jetpack' ) . '</span>',
99
			array( $this, 'setting_html' ),
100
			'writing',
101
			'jetpack_cpt_section'
102
		);
103
		register_setting(
104
			'writing',
105
			self::OPTION_NAME,
106
			'intval'
107
		);
108
109
		// Check if CPT is enabled first so that intval doesn't get set to NULL on re-registering
110
		if ( get_option( self::OPTION_NAME, '0' ) || current_theme_supports( self::CUSTOM_POST_TYPE ) ) {
111
			register_setting(
112
				'writing',
113
				self::OPTION_READING_SETTING,
114
				'intval'
115
			);
116
		}
117
	}
118
119
	/**
120
	 * HTML code to display a checkbox true/false option
121
	 * for the Portfolio CPT setting.
122
	 *
123
	 * @return html
124
	 */
125
	function setting_html() {
126 View Code Duplication
		if ( current_theme_supports( self::CUSTOM_POST_TYPE ) ) : ?>
127
			<p><?php printf( /* translators: %s is the name of a custom post type such as "jetpack-portfolio" */ __( 'Your theme supports <strong>%s</strong>', 'jetpack' ), self::CUSTOM_POST_TYPE ); ?></p>
128
		<?php else : ?>
129
			<label for="<?php echo esc_attr( self::OPTION_NAME ); ?>">
130
				<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" />
131
				<?php esc_html_e( 'Enable Portfolio Projects for this site.', 'jetpack' ); ?>
132
				<a target="_blank" href="http://en.support.wordpress.com/portfolios/"><?php esc_html_e( 'Learn More', 'jetpack' ); ?></a>
133
			</label>
134
		<?php endif;
135
		if ( get_option( self::OPTION_NAME, '0' ) || current_theme_supports( self::CUSTOM_POST_TYPE ) ) :
136
			printf( '<p><label for="%1$s">%2$s</label></p>',
137
				esc_attr( self::OPTION_READING_SETTING ),
138
				/* translators: %1$s is replaced with an input field for numbers */
139
				sprintf( __( 'Portfolio pages display at most %1$s projects', 'jetpack' ),
140
					sprintf( '<input name="%1$s" id="%1$s" type="number" step="1" min="1" value="%2$s" class="small-text" />',
141
						esc_attr( self::OPTION_READING_SETTING ),
142
						esc_attr( get_option( self::OPTION_READING_SETTING, '10' ) )
143
					)
144
				)
145
			);
146
		endif;
147
	}
148
149
	/**
150
	* Should this Custom Post Type be made available?
151
	*/
152 View Code Duplication
	function site_supports_custom_post_type() {
153
		// If the current theme requests it.
154
		if ( current_theme_supports( self::CUSTOM_POST_TYPE ) || get_option( self::OPTION_NAME, '0' ) ) {
155
			return true;
156
		}
157
158
		// Otherwise, say no unless something wants to filter us to say yes.
159
		/** This action is documented in modules/custom-post-types/nova.php */
160
		return (bool) apply_filters( 'jetpack_enable_cpt', false, self::CUSTOM_POST_TYPE );
161
	}
162
163
	/*
164
	 * Flush permalinks when CPT option is turned on/off
165
	 */
166
	function flush_rules_on_enable() {
167
		flush_rewrite_rules();
168
	}
169
170
	/*
171
	 * Count published projects and flush permalinks when first projects is published
172
	 */
173 View Code Duplication
	function flush_rules_on_first_project() {
174
		$projects = get_transient( 'jetpack-portfolio-count-cache' );
175
176
		if ( false === $projects ) {
177
			flush_rewrite_rules();
178
			$projects = (int) wp_count_posts( self::CUSTOM_POST_TYPE )->publish;
179
180
			if ( ! empty( $projects ) ) {
181
				set_transient( 'jetpack-portfolio-count-cache', $projects, HOUR_IN_SECONDS * 12 );
182
			}
183
		}
184
	}
185
186
	/*
187
	 * Flush permalinks when CPT supported theme is activated
188
	 */
189
	function flush_rules_on_switch() {
190
		if ( current_theme_supports( self::CUSTOM_POST_TYPE ) ) {
191
			flush_rewrite_rules();
192
		}
193
	}
194
195
	/**
196
	 * On plugin/theme activation, check if current theme supports CPT
197
	 */
198
	static function activation_post_type_support() {
199
		if ( current_theme_supports( self::CUSTOM_POST_TYPE ) ) {
200
			update_option( self::OPTION_NAME, '1' );
201
		}
202
	}
203
204
	/**
205
	 * On theme switch, check if CPT item exists and disable if not
206
	 */
207 View Code Duplication
	function deactivation_post_type_support() {
208
		$portfolios = get_posts( array(
209
			'fields'           => 'ids',
210
			'posts_per_page'   => 1,
211
			'post_type'        => self::CUSTOM_POST_TYPE,
212
			'suppress_filters' => false
213
		) );
214
215
		if ( empty( $portfolios ) ) {
216
			update_option( self::OPTION_NAME, '0' );
217
		}
218
	}
219
220
	/**
221
	 * Register Post Type
222
	 */
223
	function register_post_types() {
224
		if ( post_type_exists( self::CUSTOM_POST_TYPE ) ) {
225
			return;
226
		}
227
228
		register_post_type( self::CUSTOM_POST_TYPE, array(
229
			'description' => __( 'Portfolio Items', 'jetpack' ),
230
			'labels' => array(
231
				'name'                  => esc_html__( 'Projects',                   'jetpack' ),
232
				'singular_name'         => esc_html__( 'Project',                    'jetpack' ),
233
				'menu_name'             => esc_html__( 'Portfolio',                  'jetpack' ),
234
				'all_items'             => esc_html__( 'All Projects',               'jetpack' ),
235
				'add_new'               => esc_html__( 'Add New',                    'jetpack' ),
236
				'add_new_item'          => esc_html__( 'Add New Project',            'jetpack' ),
237
				'edit_item'             => esc_html__( 'Edit Project',               'jetpack' ),
238
				'new_item'              => esc_html__( 'New Project',                'jetpack' ),
239
				'view_item'             => esc_html__( 'View Project',               'jetpack' ),
240
				'search_items'          => esc_html__( 'Search Projects',            'jetpack' ),
241
				'not_found'             => esc_html__( 'No Projects found',          'jetpack' ),
242
				'not_found_in_trash'    => esc_html__( 'No Projects found in Trash', 'jetpack' ),
243
				'filter_items_list'     => esc_html__( 'Filter projects list',       'jetpack' ),
244
				'items_list_navigation' => esc_html__( 'Project list navigation',    'jetpack' ),
245
				'items_list'            => esc_html__( 'Projects list',              'jetpack' ),
246
			),
247
			'supports' => array(
248
				'title',
249
				'editor',
250
				'thumbnail',
251
				'author',
252
				'comments',
253
				'publicize',
254
				'wpcom-markdown',
255
				'revisions',
256
				'excerpt',
257
			),
258
			'rewrite' => array(
259
				'slug'       => 'portfolio',
260
				'with_front' => false,
261
				'feeds'      => true,
262
				'pages'      => true,
263
			),
264
			'public'          => true,
265
			'show_ui'         => true,
266
			'menu_position'   => 20,                    // below Pages
267
			'menu_icon'       => 'dashicons-portfolio', // 3.8+ dashicon option
268
			'capability_type' => 'page',
269
			'map_meta_cap'    => true,
270
			'taxonomies'      => array( self::CUSTOM_TAXONOMY_TYPE, self::CUSTOM_TAXONOMY_TAG ),
271
			'has_archive'     => true,
272
			'query_var'       => 'portfolio',
273
			'show_in_rest'    => true,
274
		) );
275
276
		register_taxonomy( self::CUSTOM_TAXONOMY_TYPE, self::CUSTOM_POST_TYPE, array(
277
			'hierarchical'      => true,
278
			'labels'            => array(
279
				'name'                  => esc_html__( 'Project Types',                 'jetpack' ),
280
				'singular_name'         => esc_html__( 'Project Type',                  'jetpack' ),
281
				'menu_name'             => esc_html__( 'Project Types',                 'jetpack' ),
282
				'all_items'             => esc_html__( 'All Project Types',             'jetpack' ),
283
				'edit_item'             => esc_html__( 'Edit Project Type',             'jetpack' ),
284
				'view_item'             => esc_html__( 'View Project Type',             'jetpack' ),
285
				'update_item'           => esc_html__( 'Update Project Type',           'jetpack' ),
286
				'add_new_item'          => esc_html__( 'Add New Project Type',          'jetpack' ),
287
				'new_item_name'         => esc_html__( 'New Project Type Name',         'jetpack' ),
288
				'parent_item'           => esc_html__( 'Parent Project Type',           'jetpack' ),
289
				'parent_item_colon'     => esc_html__( 'Parent Project Type:',          'jetpack' ),
290
				'search_items'          => esc_html__( 'Search Project Types',          'jetpack' ),
291
				'items_list_navigation' => esc_html__( 'Project type list navigation',  'jetpack' ),
292
				'items_list'            => esc_html__( 'Project type list',             'jetpack' ),
293
			),
294
			'public'            => true,
295
			'show_ui'           => true,
296
			'show_in_nav_menus' => true,
297
			'show_in_rest'      => true,
298
			'show_admin_column' => true,
299
			'query_var'         => true,
300
			'rewrite'           => array( 'slug' => 'project-type' ),
301
		) );
302
303
		register_taxonomy( self::CUSTOM_TAXONOMY_TAG, self::CUSTOM_POST_TYPE, array(
304
			'hierarchical'      => false,
305
			'labels'            => array(
306
				'name'                       => esc_html__( 'Project Tags',                   'jetpack' ),
307
				'singular_name'              => esc_html__( 'Project Tag',                    'jetpack' ),
308
				'menu_name'                  => esc_html__( 'Project Tags',                   'jetpack' ),
309
				'all_items'                  => esc_html__( 'All Project Tags',               'jetpack' ),
310
				'edit_item'                  => esc_html__( 'Edit Project Tag',               'jetpack' ),
311
				'view_item'                  => esc_html__( 'View Project Tag',               'jetpack' ),
312
				'update_item'                => esc_html__( 'Update Project Tag',             'jetpack' ),
313
				'add_new_item'               => esc_html__( 'Add New Project Tag',            'jetpack' ),
314
				'new_item_name'              => esc_html__( 'New Project Tag Name',           'jetpack' ),
315
				'search_items'               => esc_html__( 'Search Project Tags',            'jetpack' ),
316
				'popular_items'              => esc_html__( 'Popular Project Tags',           'jetpack' ),
317
				'separate_items_with_commas' => esc_html__( 'Separate tags with commas',      'jetpack' ),
318
				'add_or_remove_items'        => esc_html__( 'Add or remove tags',             'jetpack' ),
319
				'choose_from_most_used'      => esc_html__( 'Choose from the most used tags', 'jetpack' ),
320
				'not_found'                  => esc_html__( 'No tags found.',                 'jetpack' ),
321
				'items_list_navigation'      => esc_html__( 'Project tag list navigation',    'jetpack' ),
322
				'items_list'                 => esc_html__( 'Project tag list',               'jetpack' ),
323
			),
324
			'public'            => true,
325
			'show_ui'           => true,
326
			'show_in_nav_menus' => true,
327
			'show_in_rest'      => true,
328
			'show_admin_column' => true,
329
			'query_var'         => true,
330
			'rewrite'           => array( 'slug' => 'project-tag' ),
331
		) );
332
	}
333
334
	/**
335
	 * Update messages for the Portfolio admin.
336
	 */
337 View Code Duplication
	function updated_messages( $messages ) {
338
		global $post;
339
340
		$messages[self::CUSTOM_POST_TYPE] = array(
341
			0  => '', // Unused. Messages start at index 1.
342
			1  => sprintf( __( 'Project updated. <a href="%s">View item</a>', 'jetpack'), esc_url( get_permalink( $post->ID ) ) ),
343
			2  => esc_html__( 'Custom field updated.', 'jetpack' ),
344
			3  => esc_html__( 'Custom field deleted.', 'jetpack' ),
345
			4  => esc_html__( 'Project updated.', 'jetpack' ),
346
			/* translators: %s: date and time of the revision */
347
			5  => isset( $_GET['revision'] ) ? sprintf( esc_html__( 'Project restored to revision from %s', 'jetpack'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
348
			6  => sprintf( __( 'Project published. <a href="%s">View project</a>', 'jetpack' ), esc_url( get_permalink( $post->ID ) ) ),
349
			7  => esc_html__( 'Project saved.', 'jetpack' ),
350
			8  => sprintf( __( 'Project submitted. <a target="_blank" href="%s">Preview project</a>', 'jetpack'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
351
			9  => sprintf( __( 'Project scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview project</a>', 'jetpack' ),
352
			// translators: Publish box date format, see http://php.net/date
353
			date_i18n( __( 'M j, Y @ G:i', 'jetpack' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post->ID ) ) ),
354
			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 ) ) ) ),
355
		);
356
357
		return $messages;
358
	}
359
360
	/**
361
	 * Change ‘Title’ column label
362
	 * Add Featured Image column
363
	 */
364
	function edit_admin_columns( $columns ) {
365
		// change 'Title' to 'Project'
366
		$columns['title'] = __( 'Project', 'jetpack' );
367
		if ( current_theme_supports( 'post-thumbnails' ) ) {
368
			// add featured image before 'Project'
369
			$columns = array_slice( $columns, 0, 1, true ) + array( 'thumbnail' => '' ) + array_slice( $columns, 1, NULL, true );
370
		}
371
372
		return $columns;
373
	}
374
375
	/**
376
	 * Add featured image to column
377
	 */
378
	function image_column( $column, $post_id ) {
379
		global $post;
380
		switch ( $column ) {
381
			case 'thumbnail':
382
				echo get_the_post_thumbnail( $post_id, 'jetpack-portfolio-admin-thumb' );
383
				break;
384
		}
385
	}
386
387
	/**
388
	 * Adjust image column width
389
	 */
390
	function enqueue_admin_styles( $hook ) {
391
		$screen = get_current_screen();
392
393
		if ( 'edit.php' == $hook && self::CUSTOM_POST_TYPE == $screen->post_type && current_theme_supports( 'post-thumbnails' ) ) {
394
			wp_add_inline_style( 'wp-admin', '.manage-column.column-thumbnail { width: 50px; } @media screen and (max-width: 360px) { .column-thumbnail{ display:none; } }' );
395
		}
396
	}
397
398
	/**
399
	 * Adds portfolio section to the Customizer.
400
	 */
401
	function customize_register( $wp_customize ) {
402
		$options = get_theme_support( self::CUSTOM_POST_TYPE );
403
404
		if ( ( ! isset( $options[0]['title'] ) || true !== $options[0]['title'] ) && ( ! isset( $options[0]['content'] ) || true !== $options[0]['content'] ) && ( ! isset( $options[0]['featured-image'] ) || true !== $options[0]['featured-image'] ) ) {
405
			return;
406
		}
407
408
		$wp_customize->add_section( 'jetpack_portfolio', array(
409
			'title'                    => esc_html__( 'Portfolio', 'jetpack' ),
410
			'theme_supports'           => self::CUSTOM_POST_TYPE,
411
			'priority'                 => 130,
412
		) );
413
414 View Code Duplication
		if ( isset( $options[0]['title'] ) && true === $options[0]['title'] ) {
415
			$wp_customize->add_setting( 'jetpack_portfolio_title', array(
416
				'default'              => esc_html__( 'Projects', 'jetpack' ),
417
				'type'                 => 'option',
418
				'sanitize_callback'    => 'sanitize_text_field',
419
				'sanitize_js_callback' => 'sanitize_text_field',
420
			) );
421
422
			$wp_customize->add_control( 'jetpack_portfolio_title', array(
423
				'section'              => 'jetpack_portfolio',
424
				'label'                => esc_html__( 'Portfolio Archive Title', 'jetpack' ),
425
				'type'                 => 'text',
426
			) );
427
		}
428
429 View Code Duplication
		if ( isset( $options[0]['content'] ) && true === $options[0]['content'] ) {
430
			$wp_customize->add_setting( 'jetpack_portfolio_content', array(
431
				'default'              => '',
432
				'type'                 => 'option',
433
				'sanitize_callback'    => 'wp_kses_post',
434
				'sanitize_js_callback' => 'wp_kses_post',
435
			) );
436
437
			$wp_customize->add_control( 'jetpack_portfolio_content', array(
438
				'section'              => 'jetpack_portfolio',
439
				'label'                => esc_html__( 'Portfolio Archive Content', 'jetpack' ),
440
				'type'                 => 'textarea',
441
			) );
442
		}
443
444 View Code Duplication
		if ( isset( $options[0]['featured-image'] ) && true === $options[0]['featured-image'] ) {
445
			$wp_customize->add_setting( 'jetpack_portfolio_featured_image', array(
446
				'default'              => '',
447
				'type'                 => 'option',
448
				'sanitize_callback'    => 'attachment_url_to_postid',
449
				'sanitize_js_callback' => 'attachment_url_to_postid',
450
				'theme_supports'       => 'post-thumbnails',
451
			) );
452
453
			$wp_customize->add_control( new WP_Customize_Image_Control( $wp_customize, 'jetpack_portfolio_featured_image', array(
454
				'section'              => 'jetpack_portfolio',
455
				'label'                => esc_html__( 'Portfolio Archive Featured Image', 'jetpack' ),
456
			) ) );
457
		}
458
	}
459
460
	/**
461
	 * Follow CPT reading setting on CPT archive and taxonomy pages
462
	 */
463
	function query_reading_setting( $query ) {
464
		if ( ! is_admin() &&
465
			$query->is_main_query() &&
466
			( $query->is_post_type_archive( self::CUSTOM_POST_TYPE ) || $query->is_tax( self::CUSTOM_TAXONOMY_TYPE ) || $query->is_tax( self::CUSTOM_TAXONOMY_TAG ) )
467
		) {
468
			$query->set( 'posts_per_page', get_option( self::OPTION_READING_SETTING, '10' ) );
469
		}
470
	}
471
472
	/**
473
	 * Add CPT to Dotcom sitemap
474
	 */
475
	function add_to_sitemap( $post_types ) {
476
		$post_types[] = self::CUSTOM_POST_TYPE;
477
478
		return $post_types;
479
	}
480
481
	/**
482
	 * Add to REST API post type whitelist
483
	 */
484
	function allow_portfolio_rest_api_type( $post_types ) {
485
		$post_types[] = self::CUSTOM_POST_TYPE;
486
487
		return $post_types;
488
	}
489
490
	/**
491
	 * Our [portfolio] shortcode.
492
	 * Prints Portfolio data styled to look good on *any* theme.
493
	 *
494
	 * @return portfolio_shortcode_html
495
	 */
496
	static function portfolio_shortcode( $atts ) {
497
		// Default attributes
498
		$atts = shortcode_atts( array(
499
			'display_types'   => true,
500
			'display_tags'    => true,
501
			'display_content' => true,
502
			'display_author'  => false,
503
			'show_filter'     => false,
504
			'include_type'    => false,
505
			'include_tag'     => false,
506
			'columns'         => 2,
507
			'showposts'       => -1,
508
			'order'           => 'asc',
509
			'orderby'         => 'date',
510
		), $atts, 'portfolio' );
511
512
		// A little sanitization
513
		if ( $atts['display_types'] && 'true' != $atts['display_types'] ) {
514
			$atts['display_types'] = false;
515
		}
516
517
		if ( $atts['display_tags'] && 'true' != $atts['display_tags'] ) {
518
			$atts['display_tags'] = false;
519
		}
520
521
		if ( $atts['display_author'] && 'true' != $atts['display_author'] ) {
522
			$atts['display_author'] = false;
523
		}
524
525 View Code Duplication
		if ( $atts['display_content'] && 'true' != $atts['display_content'] && 'full' != $atts['display_content'] ) {
526
			$atts['display_content'] = false;
527
		}
528
529
		if ( $atts['include_type'] ) {
530
			$atts['include_type'] = explode( ',', str_replace( ' ', '', $atts['include_type'] ) );
531
		}
532
533
		if ( $atts['include_tag'] ) {
534
			$atts['include_tag'] = explode( ',', str_replace( ' ', '', $atts['include_tag'] ) );
535
		}
536
537
		$atts['columns'] = absint( $atts['columns'] );
538
539
		$atts['showposts'] = intval( $atts['showposts'] );
540
541
542 View Code Duplication
		if ( $atts['order'] ) {
543
			$atts['order'] = urldecode( $atts['order'] );
544
			$atts['order'] = strtoupper( $atts['order'] );
545
			if ( 'DESC' != $atts['order'] ) {
546
				$atts['order'] = 'ASC';
547
			}
548
		}
549
550 View Code Duplication
		if ( $atts['orderby'] ) {
551
			$atts['orderby'] = urldecode( $atts['orderby'] );
552
			$atts['orderby'] = strtolower( $atts['orderby'] );
553
			$allowed_keys = array( 'author', 'date', 'title', 'rand' );
554
555
			$parsed = array();
556
			foreach ( explode( ',', $atts['orderby'] ) as $portfolio_index_number => $orderby ) {
557
				if ( ! in_array( $orderby, $allowed_keys ) ) {
558
					continue;
559
				}
560
				$parsed[] = $orderby;
561
			}
562
563
			if ( empty( $parsed ) ) {
564
				unset( $atts['orderby'] );
565
			} else {
566
				$atts['orderby'] = implode( ' ', $parsed );
567
			}
568
		}
569
570
		// enqueue shortcode styles when shortcode is used
571
		wp_enqueue_style( 'jetpack-portfolio-style', plugins_url( 'css/portfolio-shortcode.css', __FILE__ ), array(), '20140326' );
572
573
		return self::portfolio_shortcode_html( $atts );
574
	}
575
576
	/**
577
	 * Query to retrieve entries from the Portfolio post_type.
578
	 *
579
	 * @return object
580
	 */
581
	static function portfolio_query( $atts ) {
582
		// Default query arguments
583
		$default = array(
584
			'order'          => $atts['order'],
585
			'orderby'        => $atts['orderby'],
586
			'posts_per_page' => $atts['showposts'],
587
		);
588
589
		$args = wp_parse_args( $atts, $default );
590
		$args['post_type'] = self::CUSTOM_POST_TYPE; // Force this post type
591
592 View Code Duplication
		if ( false != $atts['include_type'] || false != $atts['include_tag'] ) {
593
			$args['tax_query'] = array();
594
		}
595
596
		// If 'include_type' has been set use it on the main query
597 View Code Duplication
		if ( false != $atts['include_type'] ) {
598
			array_push( $args['tax_query'], array(
599
				'taxonomy' => self::CUSTOM_TAXONOMY_TYPE,
600
				'field'    => 'slug',
601
				'terms'    => $atts['include_type'],
602
			) );
603
		}
604
605
		// If 'include_tag' has been set use it on the main query
606 View Code Duplication
		if ( false != $atts['include_tag'] ) {
607
			array_push( $args['tax_query'], array(
608
				'taxonomy' => self::CUSTOM_TAXONOMY_TAG,
609
				'field'    => 'slug',
610
				'terms'    => $atts['include_tag'],
611
			) );
612
		}
613
614 View Code Duplication
		if ( false != $atts['include_type'] && false != $atts['include_tag'] ) {
615
			$args['tax_query']['relation'] = 'AND';
616
		}
617
618
		// Run the query and return
619
		$query = new WP_Query( $args );
620
		return $query;
621
	}
622
623
	/**
624
	 * The Portfolio shortcode loop.
625
	 *
626
	 * @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...
627
	 * @return html
628
	 */
629
	static function portfolio_shortcode_html( $atts ) {
630
631
		$query = self::portfolio_query( $atts );
632
		$portfolio_index_number = 0;
633
634
		ob_start();
635
636
		// If we have posts, create the html
637
		// with hportfolio markup
638
		if ( $query->have_posts() ) {
639
640
			// Render styles
641
			//self::themecolor_styles();
642
643
		?>
644
			<div class="jetpack-portfolio-shortcode column-<?php echo esc_attr( $atts['columns'] ); ?>">
645
			<?php  // open .jetpack-portfolio
646
647
			// Construct the loop...
648
			while ( $query->have_posts() ) {
649
				$query->the_post();
650
				$post_id = get_the_ID();
651
				?>
652
				<div class="portfolio-entry <?php echo esc_attr( self::get_project_class( $portfolio_index_number, $atts['columns'] ) ); ?>">
653
					<header class="portfolio-entry-header">
654
					<?php
655
					// Featured image
656
					echo self::get_portfolio_thumbnail_link( $post_id );
657
					?>
658
659
					<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>
660
661
						<div class="portfolio-entry-meta">
662
						<?php
663
						if ( false != $atts['display_types'] ) {
664
							echo self::get_project_type( $post_id );
665
						}
666
667
						if ( false != $atts['display_tags'] ) {
668
							echo self::get_project_tags( $post_id );
669
						}
670
671
						if ( false != $atts['display_author'] ) {
672
							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...
673
						}
674
						?>
675
						</div>
676
677
					</header>
678
679
				<?php
680
				// The content
681
				if ( false !== $atts['display_content'] ) {
682
					add_filter( 'wordads_inpost_disable', '__return_true', 20 );
683
					if ( 'full' === $atts['display_content'] ) {
684
					?>
685
						<div class="portfolio-entry-content"><?php the_content(); ?></div>
686
					<?php
687
					} else {
688
					?>
689
						<div class="portfolio-entry-content"><?php the_excerpt(); ?></div>
690
					<?php
691
					}
692
					remove_filter( 'wordads_inpost_disable', '__return_true', 20 );
693
				}
694
				?>
695
				</div><!-- close .portfolio-entry -->
696
				<?php $portfolio_index_number++;
697
			} // end of while loop
698
699
			wp_reset_postdata();
700
			?>
701
			</div><!-- close .jetpack-portfolio -->
702
		<?php
703
		} else { ?>
704
			<p><em><?php _e( 'Your Portfolio Archive currently has no entries. You can start creating them on your dashboard.', 'jetpack' ); ?></p></em>
705
		<?php
706
		}
707
		$html = ob_get_clean();
708
709
		// If there is a [portfolio] within a [portfolio], remove the shortcode
710
		if ( has_shortcode( $html, 'portfolio' ) ){
711
			remove_shortcode( 'portfolio' );
712
		}
713
714
		// Return the HTML block
715
		return $html;
716
	}
717
718
	/**
719
	 * Individual project class
720
	 *
721
	 * @return string
722
	 */
723
	static function get_project_class( $portfolio_index_number, $columns ) {
724
		$project_types = wp_get_object_terms( get_the_ID(), self::CUSTOM_TAXONOMY_TYPE, array( 'fields' => 'slugs' ) );
725
		$class = array();
726
727
		$class[] = 'portfolio-entry-column-'.$columns;
728
		// add a type- class for each project type
729
		foreach ( $project_types as $project_type ) {
730
			$class[] = 'type-' . esc_html( $project_type );
731
		}
732
		if( $columns > 1) {
733
			if ( ( $portfolio_index_number % 2 ) == 0 ) {
734
				$class[] = 'portfolio-entry-mobile-first-item-row';
735
			} else {
736
				$class[] = 'portfolio-entry-mobile-last-item-row';
737
			}
738
		}
739
740
		// add first and last classes to first and last items in a row
741
		if ( ( $portfolio_index_number % $columns ) == 0 ) {
742
			$class[] = 'portfolio-entry-first-item-row';
743
		} elseif ( ( $portfolio_index_number % $columns ) == ( $columns - 1 ) ) {
744
			$class[] = 'portfolio-entry-last-item-row';
745
		}
746
747
748
		/**
749
		 * Filter the class applied to project div in the portfolio
750
		 *
751
		 * @module custom-content-types
752
		 *
753
		 * @since 3.1.0
754
		 *
755
		 * @param string $class class name of the div.
756
		 * @param int $portfolio_index_number iterator count the number of columns up starting from 0.
757
		 * @param int $columns number of columns to display the content in.
758
		 *
759
		 */
760
		return apply_filters( 'portfolio-project-post-class', implode( " ", $class ) , $portfolio_index_number, $columns );
761
	}
762
763
	/**
764
	 * Displays the project type that a project belongs to.
765
	 *
766
	 * @return html
767
	 */
768 View Code Duplication
	static function get_project_type( $post_id ) {
769
		$project_types = get_the_terms( $post_id, self::CUSTOM_TAXONOMY_TYPE );
770
771
		// If no types, return empty string
772
		if ( empty( $project_types ) || is_wp_error( $project_types ) ) {
773
			return;
774
		}
775
776
		$html = '<div class="project-types"><span>' . __( 'Types', 'jetpack' ) . ':</span>';
777
		$types = array();
778
		// Loop thorugh all the types
779
		foreach ( $project_types as $project_type ) {
780
			$project_type_link = get_term_link( $project_type, self::CUSTOM_TAXONOMY_TYPE );
781
782
			if ( is_wp_error( $project_type_link ) ) {
783
				return $project_type_link;
784
			}
785
786
			$types[] = '<a href="' . esc_url( $project_type_link ) . '" rel="tag">' . esc_html( $project_type->name ) . '</a>';
787
		}
788
		$html .= ' '.implode( ', ', $types );
789
		$html .= '</div>';
790
791
		return $html;
792
	}
793
794
	/**
795
	 * Displays the project tags that a project belongs to.
796
	 *
797
	 * @return html
798
	 */
799 View Code Duplication
	static function get_project_tags( $post_id ) {
800
		$project_tags = get_the_terms( $post_id, self::CUSTOM_TAXONOMY_TAG );
801
802
		// If no tags, return empty string
803
		if ( empty( $project_tags ) || is_wp_error( $project_tags ) ) {
804
			return false;
805
		}
806
807
		$html = '<div class="project-tags"><span>' . __( 'Tags', 'jetpack' ) . ':</span>';
808
		$tags = array();
809
		// Loop thorugh all the tags
810
		foreach ( $project_tags as $project_tag ) {
811
			$project_tag_link = get_term_link( $project_tag, self::CUSTOM_TAXONOMY_TYPE );
812
813
			if ( is_wp_error( $project_tag_link ) ) {
814
				return $project_tag_link;
815
			}
816
817
			$tags[] = '<a href="' . esc_url( $project_tag_link ) . '" rel="tag">' . esc_html( $project_tag->name ) . '</a>';
818
		}
819
		$html .= ' '. implode( ', ', $tags );
820
		$html .= '</div>';
821
822
		return $html;
823
	}
824
825
	/**
826
	 * Displays the author of the current portfolio project.
827
	 *
828
	 * @return html
829
	 */
830
	static function get_project_author() {
831
		$html = '<div class="project-author">';
832
		/* translators: %1$s is link to author posts, %2$s is author display name */
833
		$html .= sprintf( __( '<span>Author:</span> <a href="%1$s">%2$s</a>', 'jetpack' ),
834
			esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
835
			esc_html( get_the_author() )
836
		);
837
		$html .= '</div>';
838
839
		return $html;
840
	}
841
842
	/**
843
	 * Display the featured image if it's available
844
	 *
845
	 * @return html
846
	 */
847 View Code Duplication
	static function get_portfolio_thumbnail_link( $post_id ) {
848
		if ( has_post_thumbnail( $post_id ) ) {
849
			/**
850
			 * Change the Portfolio thumbnail size.
851
			 *
852
			 * @module custom-content-types
853
			 *
854
			 * @since 3.4.0
855
			 *
856
			 * @param string|array $var Either a registered size keyword or size array.
857
			 */
858
			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>';
859
		}
860
	}
861
}
862
863
add_action( 'init', array( 'Jetpack_Portfolio', 'init' ) );
864
865
// Check on plugin activation if theme supports CPT
866
register_activation_hook( __FILE__,                         array( 'Jetpack_Portfolio', 'activation_post_type_support' ) );
867
add_action( 'jetpack_activate_module_custom-content-types', array( 'Jetpack_Portfolio', 'activation_post_type_support' ) );
868