Dev
New Links Section + Tutorial

I’ve always liked sharing links of interest but I’m taking that content and putting it on my own site instead of puffing up social media. I’ll still share stuff there too from time to time but this will be the main place I share links from now on. They are mostly for me to find again later but I also share in case someone else finds them interesting.

I’m using a custom Genesis child theme for my site and I wrote some code to make it easier to create the links section the way I wanted. I didn’t like the built-in links manager so I built something myself.

Tools used:

  • Custom theme code
  • Custom functions
  • Custom css
  • Custom Post Type UI
  • Advanced Custom Fields Pro (Pro is not required for this – standard will work)

For this step we just need to run this code one time. Add it to your functions.php and load your site once and then remove this code. It will turn off the built-in links manager but we don’t want that running on every page load for performance reasons so remove it after you run it once.

1update_option( 'link_manager_enabled', 0 );

Step 2: Create Custom Post Type

First thing I did was create a custom post type called Links. This is where we’ll post our links. I disabled everything but the Title on this one. The title is what will be used at the link text for our posts.

Below is the export for this and you can use the Custom Post Type UI plugin to import it.

1{"links":{"name":"links","label":"Links","singular_label":"Link","description":"","public":"true","publicly_queryable":"true","show_ui":"true","show_in_nav_menus":"true","delete_with_user":"false","show_in_rest":"true","rest_base":"","rest_controller_class":"","has_archive":"true","has_archive_string":"","exclude_from_search":"false","capability_type":"post","hierarchical":"false","rewrite":"true","rewrite_slug":"","rewrite_withfront":"true","query_var":"true","query_var_slug":"","menu_position":"","show_in_menu":"true","show_in_menu_string":"","menu_icon":"","supports":["title"],"taxonomies":[],"labels":{"menu_name":"","all_items":"","add_new":"","add_new_item":"","edit_item":"","new_item":"","view_item":"","view_items":"","search_items":"","not_found":"","not_found_in_trash":"","parent_item_colon":"","featured_image":"","set_featured_image":"","remove_featured_image":"","use_featured_image":"","archives":"","insert_into_item":"","uploaded_to_this_item":"","filter_items_list":"","items_list_navigation":"","items_list":"","attributes":"","name_admin_bar":"","item_published":"","item_published_privately":"","item_reverted_to_draft":"","item_scheduled":"","item_updated":""},"custom_supports":""}}

Step 3: Create Custom Taxonomy

Next up is creating a custom taxonomy so we can put our links into categories. I called it link_categories. Below is the Custom Post Type UI export for the this.

1{"link_categories":{"name":"link_categories","label":"Categories","singular_label":"Category","description":"","public":"true","publicly_queryable":"true","hierarchical":"true","show_ui":"true","show_in_menu":"true","show_in_nav_menus":"true","query_var":"true","query_var_slug":"","rewrite":"true","rewrite_slug":"","rewrite_withfront":"1","rewrite_hierarchical":"0","show_admin_column":"false","show_in_rest":"true","show_in_quick_edit":"","rest_base":"","rest_controller_class":"","labels":{"menu_name":"","all_items":"","edit_item":"","view_item":"","update_item":"","add_new_item":"","new_item_name":"","parent_item":"","parent_item_colon":"","search_items":"","popular_items":"","separate_items_with_commas":"","add_or_remove_items":"","choose_from_most_used":"","not_found":"","no_terms":"","items_list_navigation":"","items_list":""},"meta_box_cb":"","object_types":["links"]}}

Step 4: Create Custom Fields

The first thing I did was create my fields in ACF. Below is the json if you want to use this.

1[
2 {
3 "key": "group_5eff6a5f42209",
4 "title": "Links",
5 "fields": [
6 {
7 "key": "field_5eff6a726937a",
8 "label": "URL",
9 "name": "url",
10 "type": "url",
11 "instructions": "Enter the full URL for this link",
12 "required": 1,
13 "conditional_logic": 0,
14 "wrapper": {
15 "width": "",
16 "class": "",
17 "id": ""
18 },
19 "acfe_permissions": "",
20 "default_value": "",
21 "placeholder": "https:\/\/google.com"
22 },
23 {
24 "key": "field_5eff6aac6937b",
25 "label": "Link Quote",
26 "name": "link_quote",
27 "type": "textarea",
28 "instructions": "Quote from linked resource.",
29 "required": 0,
30 "conditional_logic": 0,
31 "wrapper": {
32 "width": "",
33 "class": "",
34 "id": ""
35 },
36 "acfe_permissions": "",
37 "default_value": "",
38 "placeholder": "",
39 "maxlength": "",
40 "rows": "",
41 "new_lines": "wpautop",
42 "acfe_textarea_code": 0
43 },
44 {
45 "key": "field_5eff6ad06937c",
46 "label": "Link Note",
47 "name": "link_note",
48 "type": "textarea",
49 "instructions": "Have anything to say about this link? Why is it a good or interesting link?",
50 "required": 0,
51 "conditional_logic": 0,
52 "wrapper": {
53 "width": "",
54 "class": "",
55 "id": ""
56 },
57 "acfe_permissions": "",
58 "default_value": "",
59 "placeholder": "",
60 "maxlength": "",
61 "rows": "",
62 "new_lines": "",
63 "acfe_textarea_code": 0
64 },
65 {
66 "key": "field_5effa1eea1b8d",
67 "label": "Source Link",
68 "name": "source_link",
69 "type": "url",
70 "instructions": "",
71 "required": 0,
72 "conditional_logic": 0,
73 "wrapper": {
74 "width": "",
75 "class": "",
76 "id": ""
77 },
78 "acfe_permissions": "",
79 "default_value": "",
80 "placeholder": ""
81 },
82 {
83 "key": "field_5effa1fda1b8e",
84 "label": "Source Text",
85 "name": "source_text",
86 "type": "text",
87 "instructions": "",
88 "required": 0,
89 "conditional_logic": 0,
90 "wrapper": {
91 "width": "",
92 "class": "",
93 "id": ""
94 },
95 "acfe_permissions": "",
96 "default_value": "",
97 "placeholder": "",
98 "prepend": "",
99 "append": "",
100 "maxlength": ""
101 }
102 ],
103 "location": [
104 [
105 {
106 "param": "post_type",
107 "operator": "==",
108 "value": "links"
109 }
110 ]
111 ],
112 "menu_order": 0,
113 "position": "normal",
114 "style": "default",
115 "label_placement": "left",
116 "instruction_placement": "label",
117 "hide_on_screen": "",
118 "active": true,
119 "description": "",
120 "acfe_display_title": "",
121 "acfe_autosync": "",
122 "acfe_permissions": "",
123 "acfe_form": 0,
124 "acfe_meta": "",
125 "acfe_note": ""
126 }
127]

Step 5: Add ACF Template Includes

For the first part of this task you need to create a directory where you want to put your “template parts”. These are reusable bits of code that can be included as needed in your theme. If you aren’t already familiar I suggest you read up on how <a href="https://developer.wordpress.org/reference/functions/get_template_part/">get_template_part()</a>works, it’s super handy.

The first function below displays the custom ACF content if we have a template named after our custom post type. In this case that would be acf-links.php (which I’ll show you in another step). I put this file my theme folder in a sub folder called tempalte-parts. If your theme already has a template part folder with a different name you can change that value. Just remember you’ll need to do that in this function and the next.

I wrote this function so it’ll look for a file for any post type in this folder so if you created a new custom post type and wanted to customize the output you would simply need to create a file called acf-recipes (or whatever you name you recipe post type) and put that into your template-parts directory. This code goes in themes functions.php file.

1function chb_add_acf_blocks( $content ) {
2 
3 //
4 if ( is_singular() && in_the_loop() && is_main_query() ) {
5 
6 $excluded_post_types = array('post', 'page', 'attachment', 'revision', 'nav_menu_item');
7 $style_sheet_dir = get_stylesheet_directory();
8 $post_type = get_post_type();
9 $file = $style_sheet_dir . '/template-parts/acf-' . $post_type . '.php';
10 if ( ! in_array( $post_type, $excluded_post_types ) && file_exists( $file ) ) {
11 
12 ob_start();
13 get_template_part('template-parts/acf', $post_type );
14 $acf_content = ob_get_contents();
15 ob_end_clean();
16 
17 echo $acf_content;
18 }
19 }
20 
21 echo $content;
22 
23}
24add_action( 'genesis_entry_content', 'chb_add_acf_blocks' );

This next block does the same as above but adds it to the archive. Remember if you changed your template-parts directory in the last function you’ll need do do that here too. This code goes in themes functions.php file.

1function chb_add_acf_blocks_to_archive( $excerpt ) {
2 
3 global $post;
4 $excluded_post_types = array('post', 'page', 'attachment', 'revision', 'nav_menu_item');
5 $style_sheet_dir = get_stylesheet_directory();
6 $post_type = get_post_type( $post->ID );
7 $file = $style_sheet_dir . '/template-parts/acf-' . $post_type . '.php';
8 if ( ! in_array( $post_type, $excluded_post_types ) && file_exists( $file ) ) {
9 
10 ob_start();
11 get_template_part('template-parts/acf', $post_type );
12 $acf_content = ob_get_contents();
13 ob_end_clean();
14 return $acf_content;
15 }
16 
17 else {
18 return $excerpt;
19 }
20 
21 
22}
23add_filter( 'get_the_excerpt', 'chb_add_acf_blocks_to_archive' );

Step: 6 – Create the acf-links.php template file

Next, you need to create a file called acf-links.php and put it in the directory you created in the previous step for your template parts.

1<?php
2/**
3 * Links Module
4 *
5 * @package groovy-1976
6 */
7 
8$title = get_the_title();
9$url = get_field( 'url' );
10$link_quote = get_field( 'link_quote' );
11$link_note = get_field( 'link_note' );
12$source_link = get_field( 'source_link' );
13$source_text = get_field( 'source_text' );
14$source_html = '';
15 
16if ( $source_link ) {
17 $via = "<a href=\"$source_link\"?>via";
18 if ( $source_text ) { $via = "via: <a href="\"$source_link\"">$source_text</a>"; }
19 $source_html = "<div class="\"link_source\"">[ $via ]</div>";
20}
21 
22?>
23 
24<section class="text-block row-<?php echo get_the_ID(); ?>">
25 <span class="dashicons-before dashicons-admin-links"> </span><a class="link" href="<?php esc_attr_e($url); ?>" target="_blank" title="<?php esc_attr_e($title); ?>"><?php echo esc_html( $title ); ??></a>
26 <?php if ( ! empty( $link_quote ) ) : ??>
27 <blockquote class="link-quote">
28 <?php echo wpautop($link_quote); ??>
29 <?php echo $source_html ??>
30 </blockquote>
31 <?php endif; ??>
32 
33 <?php if ( ! empty( $link_note ) ) : ??>
34 <blockquote class="link-note">
35 <?php echo wpautop($link_note); ??>
36 </blockquote>
37 <?php endif; ??>
38 
39</section>
40 
41<p class="entry-meta">
42 <span class="entry-categories">Filed Under:
43 
44 <?php $terms = get_the_terms( $post-?>ID, 'link_categories' );
45 
46 foreach ( $terms as $term ) {
47 ?>
48 <a href="<?php echo get_term_link($term->slug, 'link_categories'); ?>" rel="category tag"><?php echo $term-?>name; ?></a>  
49 <?php }
50 ??>
51 
52 </span>
53</p>

Step 7: – Remove The Title from Archive & Single pages

I didn’t need the “post titles” showing for the archives or single because the links already have the title. I want this to look like a list of links and not posts. See the links tab in my nav for a demo. This code goes in themes functions.php file.

1function remove_single_custom_post_titles( $title ) {
2 if ( is_archive() || is_single() ) {
3 global $post;
4 $post_type = get_post_type ($post->ID);
5 if ( 'links' === $post_type ) {
6 remove_action( 'genesis_entry_header', 'genesis_post_info', 12 );
7 return '';
8 }
9 }
10 
11 return $title;
12}
13add_filter( 'genesis_post_title_output', 'remove_single_custom_post_titles' );

Step 8: Change the posts per page for the links custom post type

I didn’t want to use the default setting from WordPress for this because the links are short and won’t take up that much room. I set this to 50 per page on mine but you can set it to anything you like. This code goes in themes functions.php file.

1function chb_change_links_posts_per_page( $query ) {
2 
3 if ( $query->is_post_type_archive( 'links' ) && ! is_admin() && $query->is_main_query() ) {
4 $query->set( 'posts_per_page', '100' );
5 }
6 
7 return $query;
8 
9}
10add_filter( 'pre_get_posts', 'chb_change_links_posts_per_page' );

Step 9: Add Dashicons support on the front end

This code enables the WordPress Dashicons to the front end of the site. I used it to use the link icon in front of the links to make it look nice. This code goes in your themes functions.php file.

1function chb_load_dashicons_front_end() {
2 wp_enqueue_style( 'dashicons' );
3}
4add_action( 'wp_enqueue_scripts', 'chb_load_dashicons_front_end' );

Step 10: Add our styles

Last but not least we need to add a little bit of CSS to make things look nice. You may need to adjust this to suit your site. This is what worked for how I wanted it to look within my site.

1.post-type-archive-links .entry-categories a:after {
2 content: ",";
3 color: #ccc;
4}
5 
6.post-type-archive-links .entry-categories a:last-child:after {
7 content: "";
8 color: #ccc;
9}
10 
11blockquote.link-quote {
12 margin-top: 2px;
13 border-left: 2px solid #ccc;
14 padding-left: 8px;
15}
16 
17blockquote.link-note {
18 margin-top: 2px;
19 border-left: 2px solid #ccc;
20 padding-left: 8px;
21}

That should have you all set! If you run into any problems or have any questions just post them below and I’ll get back to you as soon as I can.

I plan on turning this into a plugin. It was specifically written to work with Genesis based themes but with a few tweaks I can make it do that selectively by detecting if Genesis is the parent theme or not. It would also take some very minor tweaks to make this work with any WordPress theme, there’s very little that’s Genesis specific.

Feedback / comments welcome. I’ll refactor it when I turn it into a plugin.

Update: Thanks to Christina Workman for catching some typos! Christina is a a co-worker at Maintiann as well as the host of wp-contribute, which you should totally check out!

No comments yet…

avatar
You can use Markdown
No results