├── .gitignore ├── assets ├── css │ ├── _mixins.scss │ ├── admin.css │ ├── admin.scss │ ├── woo-projects-handheld.css │ ├── woo-projects-handheld.scss │ ├── woo-projects.css │ └── woo-projects.scss ├── images │ └── placeholder.png └── js │ ├── admin.js │ ├── script.js │ └── script.min.js ├── classes ├── class-projects-admin.php ├── class-projects-frontend.php ├── class-projects-integrations.php ├── class-projects-query.php ├── class-projects-settings.php ├── class-projects-shortcodes.php ├── class-projects-taxonomy.php ├── class-projects-template-loader.php ├── class-widget-project-categories.php └── class-widget-projects.php ├── config.codekit ├── dummy_data.xml ├── lang └── projects-by-woothemes.pot ├── projects-core-functions.php ├── projects-hooks.php ├── projects-template.php ├── projects.php ├── readme.txt └── templates ├── archive-project.php ├── content-project-category.php ├── content-project-widget.php ├── content-project.php ├── content-single-project.php ├── layout ├── sidebar.php ├── wrapper-end.php └── wrapper-start.php ├── loop ├── loop-end.php ├── loop-start.php ├── no-projects-found.php ├── pagination.php └── short-description.php ├── single-project.php ├── single-project ├── description.php ├── meta.php ├── pagination.php ├── project-feature.php ├── project-gallery.php ├── short-description.php └── title.php └── taxonomy-project-category.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .sass-cache -------------------------------------------------------------------------------- /assets/css/_mixins.scss: -------------------------------------------------------------------------------- 1 | @import "bourbon"; 2 | 3 | // Vars 4 | $error: #f63121; 5 | 6 | // Mixins 7 | @mixin iconbefore( $glyph: "\f179" ) 8 | { 9 | font-family: 'dashicons'; 10 | vertical-align: top; 11 | margin-right: .618em; 12 | content: $glyph; 13 | } 14 | 15 | @mixin iconafter( $glyph: "\f179" ) 16 | { 17 | font-family: 'dashicons'; 18 | vertical-align: top; 19 | margin-left: .618em; 20 | content: $glyph; 21 | } 22 | 23 | @mixin icon( $glyph: "\f179" ) 24 | { 25 | font-family: 'dashicons'; 26 | speak: none; 27 | font-weight: normal; 28 | font-variant: normal; 29 | text-transform: none; 30 | line-height: 1; 31 | -webkit-font-smoothing: antialiased; 32 | margin:0; 33 | text-indent: 0; 34 | position: absolute; 35 | top:0; 36 | left:0; 37 | width:100%; 38 | height: 100%; 39 | text-align: center; 40 | content: $glyph; 41 | } 42 | 43 | // Mixins 44 | @mixin border_radius_reset() 45 | { 46 | -webkit-border-radius: none; 47 | -moz-border-radius: none; 48 | border-radius: none; 49 | } 50 | 51 | @mixin opacity($opacity:0.75) 52 | { 53 | opacity: $opacity; 54 | filter: alpha(opacity=$opacity * 100); 55 | } -------------------------------------------------------------------------------- /assets/css/admin.css: -------------------------------------------------------------------------------- 1 | .post-type-project.edit-php table.wp-list-table .column-image { 2 | width: 120px; 3 | text-align: center; } 4 | .post-type-project.edit-php table.wp-list-table .column-image img { 5 | width: 60px; 6 | height: auto; } 7 | 8 | #project-images .inside { 9 | margin: 0; 10 | padding: 0; } 11 | #project-images .inside .add_project_images { 12 | padding: 0 12px 12px; } 13 | #project-images .inside #project_images_container { 14 | padding: 0 0 0 9px; } 15 | #project-images .inside #project_images_container ul { 16 | margin: 0; 17 | padding: 0; } 18 | #project-images .inside #project_images_container ul:after { 19 | content: ""; 20 | display: table; 21 | clear: both; } 22 | #project-images .inside #project_images_container ul li.image, 23 | #project-images .inside #project_images_container ul li.add, 24 | #project-images .inside #project_images_container ul li.projects-metabox-sortable-placeholder { 25 | width: 80px; 26 | float: left; 27 | cursor: move; 28 | margin: 9px 9px 0 0; 29 | background: #f7f7f7; 30 | position: relative; 31 | background: #000; 32 | -webkit-box-sizing: border-box; 33 | /* Safari/Chrome, other WebKit */ 34 | -moz-box-sizing: border-box; 35 | /* Firefox, other Gecko */ 36 | box-sizing: border-box; 37 | /* Opera/IE 8+ */ } 38 | #project-images .inside #project_images_container ul li.image img, 39 | #project-images .inside #project_images_container ul li.add img, 40 | #project-images .inside #project_images_container ul li.projects-metabox-sortable-placeholder img { 41 | width: 100%; 42 | height: auto; 43 | display: block; 44 | -webkit-animation: all ease 0.2s; 45 | -moz-animation: all ease 0.2s; 46 | animation: all ease 0.2s; } 47 | #project-images .inside #project_images_container ul li.image:hover img, 48 | #project-images .inside #project_images_container ul li.add:hover img, 49 | #project-images .inside #project_images_container ul li.projects-metabox-sortable-placeholder:hover img { 50 | opacity: 0.75; 51 | filter: alpha(opacity=75); } 52 | #project-images .inside #project_images_container ul li.projects-metabox-sortable-placeholder { 53 | background: #f1f1f1; } 54 | #project-images .inside #project_images_container ul ul.actions { 55 | position: absolute; 56 | top: 0; 57 | right: 0; 58 | -webkit-animation: all ease 0.2s; 59 | -moz-animation: all ease 0.2s; 60 | animation: all ease 0.2s; 61 | opacity: 0; 62 | filter: alpha(opacity=0); } 63 | #project-images .inside #project_images_container ul ul.actions li { 64 | float: right; } 65 | #project-images .inside #project_images_container ul ul.actions li a { 66 | width: 20px; 67 | margin: 0; 68 | height: 20px; 69 | font-size: 16px; 70 | display: block; 71 | overflow: hidden; 72 | color: #fff; 73 | background: #000; 74 | font-weight: 300; 75 | line-height: 20px; 76 | text-align: center; 77 | text-decoration: none; 78 | -webkit-animation: all ease 0.2s; 79 | -moz-animation: all ease 0.2s; 80 | animation: all ease 0.2s; } 81 | #project-images .inside #project_images_container ul ul.actions li a.edit, #project-images .inside #project_images_container ul ul.actions li a.delete { 82 | text-indent: -999px; 83 | position: relative; 84 | background: #000; } 85 | #project-images .inside #project_images_container ul ul.actions li a.edit:before, #project-images .inside #project_images_container ul ul.actions li a.delete:before { 86 | content: "\f464"; 87 | display: block; 88 | position: absolute; 89 | top: 0; 90 | right: 0; 91 | bottom: 0; 92 | left: 0; 93 | font-family: 'Dashicons'; 94 | color: #fff; 95 | text-indent: 0; 96 | font-weight: normal; } 97 | #project-images .inside #project_images_container ul ul.actions li a.edit:hover, #project-images .inside #project_images_container ul ul.actions li a.delete:hover { 98 | background: #444; } 99 | #project-images .inside #project_images_container ul ul.actions li a.delete { 100 | background-color: #f63121; } 101 | #project-images .inside #project_images_container ul ul.actions li a.delete:before { 102 | content: "\f335"; } 103 | #project-images .inside #project_images_container ul ul.actions li a.delete:hover { 104 | background: #d40f00; } 105 | #project-images .inside #project_images_container ul li:hover ul.actions { 106 | opacity: 1; 107 | filter: alpha(opacity=100); } 108 | 109 | .post-type-project .ui-autocomplete { 110 | font-family: inherit; 111 | font-size: 1em; 112 | background: #fafafa; 113 | -webkit-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1); 114 | box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1); 115 | -webkit-border-radius: 0 0 4px 4px; 116 | border-radius: 0 0 4px 4px; 117 | -webkit-transform: translateY(-1px); 118 | transform: translateY(-1px); } 119 | .post-type-project .ui-autocomplete li a { 120 | -webkit-border-radius: 0; 121 | border-radius: 0; 122 | border: 0; 123 | background: none; } 124 | .post-type-project .ui-autocomplete li a:hover { 125 | border: 0; 126 | background: #f6f6f6; } 127 | .post-type-project .ui-autocomplete li:last-child a { 128 | -webkit-border-radius: 0 0 4px 4px; 129 | border-radius: 0 0 4px 4px; } 130 | .post-type-project .projects-radio label { 131 | display: block; 132 | line-height: 1.5; } 133 | -------------------------------------------------------------------------------- /assets/css/admin.scss: -------------------------------------------------------------------------------- 1 | // Imports 2 | @import 'mixins'; 3 | 4 | // Projects screen 5 | .post-type-project.edit-php { 6 | table.wp-list-table { 7 | .column-image { 8 | width: 120px; 9 | text-align: center;; 10 | 11 | img { 12 | width: 60px; 13 | height: auto; 14 | } 15 | } 16 | } 17 | } 18 | 19 | // Project Gallery 20 | #project-images { 21 | .inside { 22 | margin: 0; 23 | padding: 0; 24 | .add_project_images { 25 | padding: 0 12px 12px; 26 | } 27 | #project_images_container { 28 | padding: 0 0 0 9px; 29 | ul { 30 | margin: 0; 31 | padding: 0; 32 | @include clearfix; 33 | 34 | li.image, 35 | li.add, 36 | li.projects-metabox-sortable-placeholder { 37 | width: 80px; 38 | float: left; 39 | cursor: move; 40 | margin: 9px 9px 0 0; 41 | background: #f7f7f7; 42 | position: relative; 43 | background: #000; 44 | -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */ 45 | -moz-box-sizing: border-box; /* Firefox, other Gecko */ 46 | box-sizing: border-box; /* Opera/IE 8+ */ 47 | img { 48 | width: 100%; 49 | height: auto; 50 | display: block; 51 | @include animation(all ease .2s); 52 | } 53 | &:hover { 54 | img { 55 | @include opacity(0.75); 56 | } 57 | } 58 | } 59 | li.projects-metabox-sortable-placeholder { 60 | background: #f1f1f1; 61 | } 62 | ul.actions { 63 | position: absolute; 64 | top:0; 65 | right: 0; 66 | @include animation(all ease .2s); 67 | @include opacity(0); 68 | li { 69 | float: right; 70 | //margin: 0 0 0 1px; 71 | a { 72 | width: 20px; 73 | margin: 0; 74 | height: 20px; 75 | font-size: 16px; 76 | display: block; 77 | overflow: hidden; 78 | color: #fff; 79 | background:#000; 80 | font-weight: 300; 81 | line-height: 20px; 82 | text-align: center; 83 | text-decoration: none; 84 | @include animation(all ease .2s); 85 | &.edit, 86 | &.delete { 87 | text-indent: -999px; 88 | position: relative; 89 | background: #000; 90 | 91 | &:before { 92 | content: "\f464"; 93 | display: block; 94 | position: absolute; 95 | top: 0; 96 | right: 0; 97 | bottom: 0; 98 | left: 0; 99 | font-family: 'Dashicons'; 100 | color: #fff; 101 | text-indent: 0; 102 | font-weight: normal; 103 | } 104 | 105 | &:hover { 106 | background: #444; 107 | } 108 | } 109 | 110 | &.delete { 111 | background-color: $error; 112 | &:before { 113 | content: "\f335"; 114 | } 115 | &:hover { 116 | background: $error - #222; 117 | } 118 | } 119 | } 120 | } 121 | } 122 | li:hover ul.actions { 123 | @include opacity(1); 124 | } 125 | } 126 | } 127 | } 128 | } 129 | 130 | // Autocomplete 131 | .post-type-project { 132 | .ui-autocomplete { 133 | font-family: inherit; 134 | font-size: 1em; 135 | background: #fafafa; 136 | -webkit-box-shadow: 0 1px 2px 0 rgba(0,0,0,0.1); 137 | box-shadow: 0 1px 2px 0 rgba(0,0,0,0.1); 138 | -webkit-border-radius: 0 0 4px 4px; 139 | border-radius: 0 0 4px 4px; 140 | -webkit-transform: translateY(-1px); 141 | transform: translateY(-1px); 142 | li { 143 | a { 144 | -webkit-border-radius: 0; 145 | border-radius: 0; 146 | border: 0; 147 | background: none; 148 | &:hover { 149 | border: 0; 150 | background: #f6f6f6; 151 | } 152 | } 153 | &:last-child { 154 | a { 155 | -webkit-border-radius: 0 0 4px 4px; 156 | border-radius: 0 0 4px 4px; 157 | } 158 | } 159 | } 160 | } 161 | 162 | .projects-radio { 163 | label { 164 | display: block; 165 | line-height: 1.5; 166 | } 167 | } 168 | } -------------------------------------------------------------------------------- /assets/css/woo-projects-handheld.css: -------------------------------------------------------------------------------- 1 | @media only screen and (max-width: 768px) { 2 | .projects ul.projects li.project, .projects-page ul.projects li.project { 3 | width: 48%; 4 | float: left; 5 | clear: both; } 6 | .projects ul.projects li.project:nth-child(2n), .projects-page ul.projects li.project:nth-child(2n) { 7 | margin-right: 0; 8 | float: right; 9 | clear: none !important; } 10 | 11 | .single-project.has-gallery .gallery, 12 | .single-project.has-gallery .summary { 13 | width: 100%; 14 | float: none; 15 | padding: 0; } 16 | .single-project.has-gallery .summary > div { 17 | font-size: 1em; } 18 | .single-project.no-gallery .project_title, 19 | .single-project.no-gallery .single-project-description, 20 | .single-project.no-gallery .project-meta { 21 | width: 100% !important; 22 | float: none; } } 23 | -------------------------------------------------------------------------------- /assets/css/woo-projects-handheld.scss: -------------------------------------------------------------------------------- 1 | // Imports 2 | @import 'mixins'; 3 | 4 | // Styles for handheld devices 5 | 6 | @media only screen and ( max-width: 768px ) { 7 | 8 | 9 | 10 | .projects, .projects-page { 11 | ul.projects { 12 | li.project { 13 | width:48%; 14 | float: left; 15 | clear:both; 16 | &:nth-child(2n) { 17 | margin-right:0; 18 | float: right; 19 | clear: none !important; 20 | } 21 | } 22 | } 23 | } 24 | 25 | .single-project { 26 | &.has-gallery { 27 | .gallery, 28 | .summary { 29 | width: 100%; 30 | float: none; 31 | padding: 0; 32 | } 33 | 34 | .summary { 35 | > div { 36 | font-size: 1em; 37 | } 38 | } 39 | } 40 | 41 | &.no-gallery { 42 | .project_title, 43 | .single-project-description, 44 | .project-meta { 45 | width: 100% !important; 46 | float: none; 47 | } 48 | } 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /assets/css/woo-projects.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Layout Styles 3 | */ 4 | .projects ul.projects, 5 | .projects-page ul.projects { 6 | list-style: none; 7 | margin: 0; 8 | margin-left: 0 !important; 9 | padding: 0 !important; 10 | *zoom: 1; } 11 | .projects ul.projects:before, .projects ul.projects:after, 12 | .projects-page ul.projects:before, 13 | .projects-page ul.projects:after { 14 | content: " "; 15 | display: table; } 16 | .projects ul.projects:after, 17 | .projects-page ul.projects:after { 18 | clear: both; } 19 | .projects ul.projects li.project, 20 | .projects-page ul.projects li.project { 21 | margin: 0 0 2.618em; 22 | padding: 0; 23 | width: 48%; 24 | float: left; 25 | margin-right: 3.8%; } 26 | .projects ul.projects li.project .project-thumbnail, 27 | .projects-page ul.projects li.project .project-thumbnail { 28 | margin: 0 0 1em; } 29 | .projects ul.projects li.project a, 30 | .projects-page ul.projects li.project a { 31 | text-decoration: none; } 32 | .projects ul.projects li.project h3, 33 | .projects-page ul.projects li.project h3 { 34 | margin-bottom: .618em; } 35 | .projects ul.projects li.project img, 36 | .projects-page ul.projects li.project img { 37 | max-width: 100%; 38 | height: auto; 39 | -webkit-box-shadow: none; 40 | -moz-box-shadow: none; 41 | box-shadow: none; 42 | border-top-left-radius: 0; 43 | border-top-right-radius: 0; 44 | border-bottom-left-radius: 0; 45 | border-bottom-right-radius: 0; 46 | padding: 0; 47 | border: 0; 48 | margin: 0 auto; 49 | display: block; } 50 | .projects ul.projects li.project.first, 51 | .projects-page ul.projects li.project.first { 52 | clear: both; } 53 | .projects ul.projects li.project.last, 54 | .projects-page ul.projects li.project.last { 55 | margin-right: 0; } 56 | .projects ul.project-categories, 57 | .projects-page ul.project-categories { 58 | margin-left: 0 !important; 59 | padding: 0 !important; 60 | list-style: none; } 61 | .projects ul.project-categories:after, 62 | .projects-page ul.project-categories:after { 63 | content: ""; 64 | display: table; 65 | clear: both; } 66 | .projects ul.project-categories li, 67 | .projects-page ul.project-categories li { 68 | display: inline-block; 69 | margin-right: .5em; 70 | list-style: none; 71 | margin-left: 0 !important; } 72 | .projects ul.project-categories li:after, 73 | .projects-page ul.project-categories li:after { 74 | content: "|"; 75 | display: inline-block; 76 | padding-left: .5em; } 77 | .projects ul.project-categories li:last-child:after, 78 | .projects-page ul.project-categories li:last-child:after { 79 | display: none; } 80 | .projects .projects-pagination, 81 | .projects-page .projects-pagination { 82 | text-align: center; } 83 | .projects .projects-pagination li, 84 | .projects-page .projects-pagination li { 85 | display: inline-block; 86 | margin: 0 .236em; } 87 | 88 | .projects.columns-2:after, .projects.columns-3:after, .projects.columns-4:after, .projects.columns-5:after, .projects.columns-6:after { 89 | content: ""; 90 | display: table; 91 | clear: both; } 92 | .projects.columns-2 ul.projects li.project, .projects.columns-3 ul.projects li.project, .projects.columns-4 ul.projects li.project, .projects.columns-5 ul.projects li.project, .projects.columns-6 ul.projects li.project { 93 | float: left; 94 | margin-right: 3.8%; 95 | clear: none; } 96 | .projects.columns-2 ul.projects li.project.first, .projects.columns-3 ul.projects li.project.first, .projects.columns-4 ul.projects li.project.first, .projects.columns-5 ul.projects li.project.first, .projects.columns-6 ul.projects li.project.first { 97 | clear: both; } 98 | .projects.columns-2 ul.projects li.project.last, .projects.columns-3 ul.projects li.project.last, .projects.columns-4 ul.projects li.project.last, .projects.columns-5 ul.projects li.project.last, .projects.columns-6 ul.projects li.project.last { 99 | margin-right: 0; } 100 | .projects.columns-2 ul.projects li.project:nth-child(2), .projects.columns-3 ul.projects li.project:nth-child(2), .projects.columns-4 ul.projects li.project:nth-child(2), .projects.columns-5 ul.projects li.project:nth-child(2), .projects.columns-6 ul.projects li.project:nth-child(2) { 101 | float: left; 102 | clear: none; } 103 | .projects.columns-1 ul.projects li.project { 104 | width: 100%; } 105 | .projects.columns-2 ul.projects li.project { 106 | width: 48%; } 107 | .projects.columns-3 ul.projects li.project { 108 | width: 30.75%; } 109 | .projects.columns-4 ul.projects li.project { 110 | width: 22.05%; } 111 | .projects.columns-5 ul.projects li.project { 112 | width: 16.9%; } 113 | .projects.columns-6 ul.projects li.project { 114 | width: 13.5%; } 115 | 116 | .single-project .project { 117 | margin-bottom: 1.618em; } 118 | .single-project .project:after { 119 | content: ""; 120 | display: table; 121 | clear: both; } 122 | .single-project .project .single-project-short-description { 123 | margin-bottom: 1.618em; } 124 | .single-project .project .summary .single-project-categories li:before { 125 | font-family: 'dashicons'; 126 | vertical-align: top; 127 | margin-right: .618em; 128 | content: "\f318"; } 129 | .single-project .project .summary .client-name:before { 130 | font-family: 'dashicons'; 131 | vertical-align: top; 132 | margin-right: .618em; 133 | content: "\f338"; } 134 | .single-project .project .summary .project-url:before { 135 | font-family: 'dashicons'; 136 | vertical-align: top; 137 | margin-right: .618em; 138 | content: "\f319"; } 139 | .single-project .project .summary .single-project-categories, 140 | .single-project .project .summary .url, 141 | .single-project .project .summary .client { 142 | margin-bottom: 1.618em; } 143 | .single-project .project .summary .project-meta ul, 144 | .single-project .project .summary .project-meta li { 145 | list-style: none; } 146 | .single-project .project .summary .purchase .amount { 147 | display: block; } 148 | .single-project .single-featured { 149 | margin-bottom: 1.618em; } 150 | .single-project.has-gallery .gallery { 151 | width: 62%; 152 | float: left; } 153 | .single-project.has-gallery .gallery a { 154 | display: block; } 155 | .single-project.has-gallery .gallery img { 156 | border-top-left-radius: 0; 157 | border-top-right-radius: 0; 158 | border-bottom-left-radius: 0; 159 | border-bottom-right-radius: 0; 160 | max-width: 100%; 161 | height: auto; 162 | -webkit-box-shadow: none; 163 | -moz-box-shadow: none; 164 | box-shadow: none; 165 | display: block; } 166 | .single-project.has-gallery .summary { 167 | width: 38%; 168 | float: right; 169 | padding: 0 0 0 2.618em; 170 | -webkit-box-sizing: border-box; 171 | -moz-box-sizing: border-box; 172 | box-sizing: border-box; } 173 | .single-project.has-gallery .summary > div { 174 | font-size: .857em; } 175 | .single-project.no-gallery .summary:after { 176 | content: ""; 177 | display: table; 178 | clear: both; } 179 | .single-project.no-gallery .summary .project_title, 180 | .single-project.no-gallery .summary .single-project-description { 181 | width: 62%; 182 | float: left; } 183 | .single-project.no-gallery .summary .project-meta { 184 | width: 34%; 185 | float: right; } 186 | .single-project .projects-single-pagination:after { 187 | content: ""; 188 | display: table; 189 | clear: both; } 190 | .single-project .projects-single-pagination .previous a, 191 | .single-project .projects-single-pagination .next a { 192 | text-decoration: none; } 193 | .single-project .projects-single-pagination .previous { 194 | float: right; } 195 | .single-project .projects-single-pagination .previous a:after { 196 | font-family: 'dashicons'; 197 | vertical-align: top; 198 | margin-left: .618em; 199 | content: "\f344"; } 200 | .single-project .projects-single-pagination .next { 201 | float: left; } 202 | .single-project .projects-single-pagination .next a:before { 203 | font-family: 'dashicons'; 204 | vertical-align: top; 205 | margin-right: .618em; 206 | content: "\f340"; } 207 | .single-project .project-testimonial blockquote { 208 | padding: 1.618em; 209 | border: 1px solid rgba(0, 0, 0, 0.1); 210 | position: relative; 211 | margin: 0; 212 | margin-bottom: 1.387em; } 213 | .single-project .project-testimonial blockquote:after { 214 | content: ""; 215 | display: block; 216 | border: 10px solid rgba(0, 0, 0, 0.1); 217 | border-color: rgba(0, 0, 0, 0.1) transparent transparent transparent; 218 | position: absolute; 219 | bottom: -21px; 220 | left: 1em; } 221 | .single-project .project-testimonial .quote:after { 222 | content: ""; 223 | display: table; 224 | clear: both; } 225 | .single-project .project-testimonial .quote .avatar-link { 226 | float: left; 227 | display: block; 228 | margin: 0 1em 1em 0; } 229 | .single-project .project-testimonial .quote cite span { 230 | display: block; } 231 | 232 | /** 233 | * Widgets 234 | */ 235 | .projects_list_widget li { 236 | margin-bottom: 1.618em; } 237 | .projects_list_widget li a { 238 | display: block; } 239 | .projects_list_widget li a:after { 240 | content: ""; 241 | display: table; 242 | clear: both; } 243 | .projects_list_widget li img { 244 | float: right; 245 | max-width: 60px; 246 | height: auto; } 247 | .projects_list_widget li .project-title { 248 | float: left; } 249 | 250 | .widget_projects_categories ul.children { 251 | margin-left: 2.618em; } 252 | 253 | /** 254 | * Twenty Thirteen Specific 255 | */ 256 | .single-project .twentythirteen .entry-summary { 257 | padding: 0; } 258 | .single-project .twentythirteen ul.single-project-categories { 259 | padding-left: 0; } 260 | .single-project.has-gallery .twentythirteen .summary { 261 | width: 36%; } 262 | .single-project.has-gallery .twentythirteen .gallery { 263 | width: 61%; } 264 | 265 | /** 266 | * Twenty Fourteen Specific 267 | */ 268 | .single-project.has-gallery .tfp .gallery { 269 | width: 50%; } 270 | .single-project.has-gallery .tfp .entry-summary { 271 | width: 50%; 272 | padding-left: 2.618em !important; } 273 | 274 | .twentyfourteen .tfp { 275 | padding: 12px 10px 0; 276 | max-width: 474px; 277 | margin: 0 auto; } 278 | .twentyfourteen .tfp .project .entry-summary { 279 | padding: 0; 280 | margin: 0 0 1.618em !important; } 281 | .twentyfourteen .tfp div.project.hentry.has-post-thumbnail { 282 | margin-top: 0; } 283 | .twentyfourteen .tfp .project .images img { 284 | margin-bottom: 1em; } 285 | 286 | @media screen and (min-width: 673px) { 287 | .twentyfourteen .tfp { 288 | padding-right: 30px; 289 | padding-left: 30px; } } 290 | @media screen and (min-width: 1040px) { 291 | .twentyfourteen .tfp { 292 | padding-right: 15px; 293 | padding-left: 15px; } } 294 | @media screen and (min-width: 1110px) { 295 | .twentyfourteen .tfp { 296 | padding-right: 30px; 297 | padding-left: 30px; } } 298 | @media screen and (min-width: 1218px) { 299 | .twentyfourteen .tfp { 300 | margin-right: 54px; } 301 | 302 | .full-width .twentyfourteen .tfp { 303 | margin-right: auto; } } 304 | -------------------------------------------------------------------------------- /assets/css/woo-projects.scss: -------------------------------------------------------------------------------- 1 | // Imports 2 | @import 'mixins'; 3 | 4 | /** 5 | * Layout Styles 6 | */ 7 | .projects, 8 | .projects-page { 9 | ul.projects { 10 | list-style: none; 11 | margin: 0; 12 | margin-left: 0 !important; 13 | padding: 0 !important; 14 | *zoom: 1; 15 | 16 | &:before, &:after { 17 | content: " "; 18 | display: table; 19 | } 20 | 21 | &:after { 22 | clear: both; 23 | } 24 | 25 | li.project { 26 | margin: 0 0 2.618em; 27 | padding: 0; 28 | width: 48%; 29 | float: left; 30 | margin-right: 3.8%; 31 | 32 | .project-thumbnail { 33 | margin: 0 0 1em; 34 | } 35 | 36 | a { 37 | text-decoration: none; 38 | } 39 | 40 | h3 { 41 | margin-bottom: .618em; 42 | } 43 | 44 | img { 45 | max-width: 100%; 46 | height: auto; 47 | -webkit-box-shadow: none; 48 | -moz-box-shadow: none; 49 | box-shadow: none; 50 | @include border-top-radius(0); 51 | @include border-bottom-radius(0); 52 | padding: 0; 53 | border: 0; 54 | margin: 0 auto; 55 | display: block; 56 | } 57 | 58 | &.first { 59 | clear: both; 60 | } 61 | 62 | &.last { 63 | margin-right: 0; 64 | } 65 | } 66 | } 67 | 68 | ul.project-categories { 69 | margin-left: 0 !important; 70 | padding: 0 !important; 71 | @include clearfix; 72 | list-style: none; 73 | 74 | li { 75 | display: inline-block; 76 | margin-right: .5em; 77 | list-style: none; 78 | margin-left: 0 !important; 79 | 80 | &:after { 81 | content: "|"; 82 | display: inline-block; 83 | padding-left: .5em; 84 | } 85 | 86 | &:last-child { 87 | &:after { 88 | display: none; 89 | } 90 | } 91 | } 92 | } 93 | 94 | .projects-pagination { 95 | text-align: center; 96 | 97 | li { 98 | display: inline-block; 99 | margin:0 .236em; 100 | } 101 | } 102 | } 103 | 104 | .projects { 105 | &.columns-2, 106 | &.columns-3, 107 | &.columns-4, 108 | &.columns-5, 109 | &.columns-6 { 110 | @include clearfix; 111 | 112 | ul.projects li.project { 113 | float: left; 114 | margin-right: 3.8%; 115 | clear: none; 116 | 117 | &.first { 118 | clear: both; 119 | } 120 | 121 | &.last { 122 | margin-right: 0; 123 | } 124 | 125 | &:nth-child(2) { 126 | float: left; 127 | clear: none; 128 | } 129 | } 130 | } 131 | 132 | &.columns-1 { 133 | ul.projects li.project { 134 | width: 100%; 135 | } 136 | } 137 | 138 | &.columns-2 { 139 | ul.projects li.project { 140 | width: 48%; 141 | } 142 | } 143 | 144 | &.columns-3 { 145 | ul.projects li.project { 146 | width: 30.75%; 147 | } 148 | } 149 | 150 | &.columns-4 { 151 | ul.projects li.project { 152 | width: 22.05%; 153 | } 154 | } 155 | 156 | &.columns-5 { 157 | ul.projects li.project { 158 | width: 16.9%; 159 | } 160 | } 161 | 162 | &.columns-6 { 163 | ul.projects li.project { 164 | width: 13.5%; 165 | } 166 | } 167 | } 168 | 169 | .single-project { 170 | .project { 171 | @include clearfix; 172 | margin-bottom: 1.618em; 173 | 174 | .single-project-short-description { 175 | margin-bottom: 1.618em; 176 | } 177 | 178 | .summary { 179 | .single-project-categories { 180 | li:before { 181 | @include iconbefore( "\f318" ); 182 | } 183 | } 184 | 185 | .client-name { 186 | &:before { 187 | @include iconbefore( "\f338" ); 188 | } 189 | } 190 | 191 | .project-url { 192 | &:before { 193 | @include iconbefore( "\f319" ); 194 | } 195 | } 196 | 197 | .single-project-categories, 198 | .url, 199 | .client { 200 | margin-bottom: 1.618em; 201 | } 202 | 203 | .project-meta { 204 | ul, 205 | li { 206 | list-style: none; 207 | } 208 | } 209 | 210 | .purchase { 211 | .amount { 212 | display: block; 213 | } 214 | } 215 | } 216 | } 217 | 218 | .single-featured { 219 | margin-bottom: 1.618em; 220 | } 221 | 222 | &.has-gallery { 223 | .gallery { 224 | width: 62%; 225 | float: left; 226 | a { 227 | display: block; 228 | } 229 | 230 | img { 231 | @include border-top-radius(0); 232 | @include border-bottom-radius(0); 233 | max-width: 100%; 234 | height: auto; 235 | -webkit-box-shadow: none; 236 | -moz-box-shadow: none; 237 | box-shadow: none; 238 | display: block; 239 | } 240 | } 241 | .summary { 242 | width: 38%; 243 | float: right; 244 | padding: 0 0 0 2.618em; 245 | @include box-sizing(border-box); 246 | > div { 247 | font-size: .857em; 248 | } 249 | } 250 | } 251 | 252 | &.no-gallery { 253 | .summary { 254 | @include clearfix; 255 | 256 | .project_title, 257 | .single-project-description { 258 | width: 62%; 259 | float: left; 260 | } 261 | 262 | .project-meta { 263 | width: 34%; 264 | float: right; 265 | } 266 | } 267 | } 268 | 269 | .projects-single-pagination { 270 | @include clearfix; 271 | 272 | .previous, 273 | .next { 274 | a { 275 | text-decoration: none; 276 | } 277 | } 278 | 279 | .previous { 280 | float: right; 281 | 282 | a:after { 283 | @include iconafter( "\f344" ); 284 | } 285 | } 286 | 287 | .next { 288 | float: left; 289 | 290 | a:before { 291 | @include iconbefore( "\f340" ); 292 | } 293 | } 294 | } 295 | 296 | .project-testimonial { 297 | blockquote { 298 | padding: 1.618em; 299 | border: 1px solid rgba(0,0,0,0.1); 300 | position: relative; 301 | margin: 0; 302 | margin-bottom: 1.387em; 303 | 304 | &:after { 305 | content: ""; 306 | display: block; 307 | border: 10px solid rgba(0,0,0,0.1); 308 | border-color: rgba(0,0,0,0.1) transparent transparent transparent; 309 | position: absolute; 310 | bottom: -21px; 311 | left: 1em; 312 | } 313 | } 314 | 315 | .quote { 316 | @include clearfix(); 317 | 318 | .avatar-link { 319 | float: left; 320 | display: block; 321 | margin: 0 1em 1em 0; 322 | } 323 | 324 | cite { 325 | span { 326 | display: block; 327 | } 328 | } 329 | } 330 | } 331 | } 332 | 333 | /** 334 | * Widgets 335 | */ 336 | .projects_list_widget { 337 | li { 338 | margin-bottom: 1.618em; 339 | 340 | a { 341 | display: block; 342 | @include clearfix; 343 | } 344 | 345 | img { 346 | float: right; 347 | max-width: 60px; 348 | height: auto; 349 | } 350 | 351 | .project-title { 352 | float: left; 353 | } 354 | } 355 | } 356 | 357 | .widget_projects_categories { 358 | ul.children { 359 | margin-left: 2.618em; 360 | } 361 | } 362 | 363 | /** 364 | * Twenty Thirteen Specific 365 | */ 366 | .single-project { 367 | .twentythirteen { 368 | .entry-summary { 369 | padding: 0; 370 | } 371 | 372 | ul.single-project-categories { 373 | padding-left: 0; 374 | } 375 | } 376 | 377 | &.has-gallery { 378 | .twentythirteen { 379 | .summary { 380 | width: 36%; 381 | } 382 | 383 | .gallery { 384 | width: 61%; 385 | } 386 | } 387 | } 388 | } 389 | 390 | /** 391 | * Twenty Fourteen Specific 392 | */ 393 | .single-project.has-gallery { 394 | .tfp { 395 | .gallery { 396 | width: 50%; 397 | } 398 | 399 | .entry-summary { 400 | width: 50%; 401 | padding-left: 2.618em !important; 402 | } 403 | } 404 | } 405 | 406 | .twentyfourteen { 407 | .tfp { 408 | padding: 12px 10px 0; 409 | max-width: 474px; 410 | margin:0 auto; 411 | .project .entry-summary { 412 | padding: 0; 413 | margin: 0 0 1.618em !important; 414 | } 415 | div.project.hentry.has-post-thumbnail { 416 | margin-top:0; 417 | } 418 | .project { 419 | .images { 420 | img { 421 | margin-bottom:1em; 422 | } 423 | } 424 | } 425 | } 426 | } 427 | 428 | @media screen and (min-width: 673px) { 429 | .twentyfourteen { 430 | .tfp { 431 | padding-right: 30px; 432 | padding-left: 30px; 433 | } 434 | } 435 | } 436 | 437 | @media screen and (min-width: 1040px) { 438 | .twentyfourteen { 439 | .tfp { 440 | padding-right: 15px; 441 | padding-left: 15px; 442 | } 443 | } 444 | } 445 | 446 | @media screen and (min-width: 1110px) { 447 | .twentyfourteen { 448 | .tfp { 449 | padding-right: 30px; 450 | padding-left: 30px; 451 | } 452 | } 453 | } 454 | 455 | @media screen and (min-width: 1218px) { 456 | .twentyfourteen { 457 | .tfp { 458 | margin-right: 54px; 459 | } 460 | } 461 | .full-width { 462 | .twentyfourteen { 463 | .tfp { 464 | margin-right: auto; 465 | } 466 | } 467 | } 468 | } -------------------------------------------------------------------------------- /assets/images/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woocommerce/projects/919846f486d268171e16c6a05ed034b520c28755/assets/images/placeholder.png -------------------------------------------------------------------------------- /assets/js/admin.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function($){ 2 | 3 | // Uploading files 4 | var project_gallery_frame; 5 | var $image_gallery_ids = $( '#project_image_gallery' ); 6 | var $project_images = $( '#project_images_container ul.project_images' ); 7 | 8 | jQuery( '.add_project_images' ).on( 'click', 'a', function( event ) { 9 | 10 | var $el = $(this); 11 | var attachment_ids = $image_gallery_ids.val(); 12 | 13 | event.preventDefault(); 14 | 15 | // If the media frame already exists, reopen it. 16 | if ( project_gallery_frame ) { 17 | project_gallery_frame.open(); 18 | return; 19 | } 20 | 21 | // Create the media frame. 22 | project_gallery_frame = wp.media.frames.downloadable_file = wp.media({ 23 | // Set the title of the modal. 24 | title: woo_projects_admin.gallery_title, 25 | button: { 26 | text: woo_projects_admin.gallery_button, 27 | }, 28 | multiple: true 29 | }); 30 | 31 | // When an image is selected, run a callback. 32 | project_gallery_frame.on( 'select', function() { 33 | 34 | var selection = project_gallery_frame.state().get( 'selection' ); 35 | 36 | selection.map( function( attachment ) { 37 | 38 | attachment = attachment.toJSON(); 39 | 40 | if ( attachment.id ) { 41 | attachment_ids = attachment_ids ? attachment_ids + "," + attachment.id : attachment.id; 42 | 43 | $project_images.append('\ 44 |
  • \ 45 | \ 46 | \ 49 |
  • '); 50 | } 51 | 52 | } ); 53 | 54 | $image_gallery_ids.val( attachment_ids ); 55 | }); 56 | 57 | // Finally, open the modal. 58 | project_gallery_frame.open(); 59 | }); 60 | 61 | // Image ordering 62 | $project_images.sortable({ 63 | items: 'li.image', 64 | cursor: 'move', 65 | scrollSensitivity:40, 66 | forcePlaceholderSize: true, 67 | forceHelperSize: false, 68 | helper: 'clone', 69 | opacity: 0.65, 70 | placeholder: 'projects-metabox-sortable-placeholder', 71 | start:function(event,ui){ 72 | ui.item.css( 'background-color','#f6f6f6' ); 73 | }, 74 | stop:function(event,ui){ 75 | ui.item.removeAttr( 'style' ); 76 | }, 77 | update: function(event, ui) { 78 | var attachment_ids = ''; 79 | $( '#project_images_container ul li.image' ).css( 'cursor','default' ).each(function() { 80 | var attachment_id = jQuery(this).attr( 'data-attachment_id' ); 81 | attachment_ids = attachment_ids + attachment_id + ','; 82 | }); 83 | $image_gallery_ids.val( attachment_ids ); 84 | } 85 | }); 86 | // Remove images 87 | $( '#project_images_container' ).on( 'click', 'a.delete', function() { 88 | $(this).closest( 'li.image' ).remove(); 89 | 90 | var attachment_ids = ''; 91 | 92 | $( '#project_images_container ul li.image' ).css( 'cursor','default' ).each(function() { 93 | var attachment_id = jQuery(this).attr( 'data-attachment_id' ); 94 | attachment_ids = attachment_ids + attachment_id + ','; 95 | }); 96 | 97 | $image_gallery_ids.val( attachment_ids ); 98 | 99 | return false; 100 | } ); 101 | 102 | 103 | 104 | // Instantiates the variable that holds the media library frame. 105 | var projects_data_frame; 106 | 107 | // Runs when the image button is clicked. 108 | jQuery( '#project-data' ).on( 'click', '.projects-upload', function( event ) { 109 | 110 | // Prevents the default action from occuring. 111 | event.preventDefault(); 112 | 113 | // store button object 114 | $button = $(this); 115 | 116 | // If the frame already exists, re-open it. 117 | if ( projects_data_frame ) { 118 | projects_data_frame.open(); 119 | return; 120 | } 121 | 122 | title = $button.data( 'title' ) ? $button.data( 'title' ) : woo_projects_admin.default_title; 123 | button = $button.data( 'button' ) ? $button.data( 'button' ) : woo_projects_admin.default_button; 124 | library = $button.data( 'library' ) ? $button.data( 'library' ) : ''; 125 | 126 | // Sets up the media library frame 127 | projects_data_frame = wp.media.frames.projects_data_frame = wp.media({ 128 | title: title, 129 | button: { text: button }, 130 | library: { type: library } 131 | }); 132 | 133 | // Runs when an image is selected. 134 | projects_data_frame.on( 'select', function(){ 135 | 136 | // Grabs the attachment selection and creates a JSON representation of the model. 137 | var media_attachment = projects_data_frame.state().get( 'selection' ).first().toJSON(); 138 | 139 | // Sends the attachment URL to our custom image input field. 140 | $button.prev( 'input.projects-upload-field' ).val( media_attachment.url ); 141 | 142 | }); 143 | 144 | // Opens the media library frame. 145 | projects_data_frame.open(); 146 | }); 147 | 148 | }); -------------------------------------------------------------------------------- /assets/js/script.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function($){ 2 | jQuery('ul.sorting a').click(function(e) { 3 | e.preventDefault(); 4 | jQuery(this).css('outline','none'); 5 | jQuery('ul.sorting .current').removeClass('current'); 6 | jQuery(this).parent().addClass('current'); 7 | 8 | // filterVal = slug of active link 9 | var filterVal = jQuery(this).text().toLowerCase().replace(' ','-'); 10 | 11 | // filterVal default = 'all' 12 | if( filterVal == 'all' ) { 13 | jQuery('ul.projects li.hidden').show().removeClass('hidden').addClass('visible'); 14 | } else { 15 | 16 | // Show / hide based on active link 17 | jQuery('ul.projects li').each(function() { 18 | 19 | if( ! jQuery(this).hasClass( filterVal ) ) { 20 | // If the li doesn't have a class = filterVal, hide it 21 | jQuery(this).hide().addClass('hidden').removeClass('visible'); 22 | } else { 23 | // If it does, show it 24 | jQuery(this).show().removeClass('hidden').addClass('visible'); 25 | } 26 | }); 27 | } 28 | 29 | //jQuery('ul.projects').hide().fadeIn(300); 30 | 31 | return false; 32 | }); 33 | 34 | jQuery('ul.sorting a').click(function() { 35 | jQuery('ul.projects').find('li').removeClass('last').removeClass('first'); 36 | }); 37 | 38 | jQuery('ul.sorting a').click(function() { 39 | jQuery('ul.projects li.visible').each(function(i) { 40 | i=( i+1 ); 41 | x=( i+2 ); 42 | if ( i%3==0 ) { 43 | jQuery(this).removeClass('first').addClass('last'); 44 | } 45 | if ( x%3==0 ) { 46 | jQuery(this).removeClass('last').addClass('first'); 47 | } 48 | }); 49 | }); 50 | }); -------------------------------------------------------------------------------- /assets/js/script.min.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function(e){jQuery("ul.sorting a").click(function(e){e.preventDefault();jQuery(this).css("outline","none");jQuery("ul.sorting .current").removeClass("current");jQuery(this).parent().addClass("current");var t=jQuery(this).text().toLowerCase().replace(" ","-");t=="all"?jQuery("ul.projects li.hidden").show().removeClass("hidden").addClass("visible"):jQuery("ul.projects li").each(function(){jQuery(this).hasClass(t)?jQuery(this).show().removeClass("hidden").addClass("visible"):jQuery(this).hide().addClass("hidden").removeClass("visible")});return!1});jQuery("ul.sorting a").click(function(){jQuery("ul.projects").find("li").removeClass("last").removeClass("first")});jQuery("ul.sorting a").click(function(){jQuery("ul.projects li.visible").each(function(e){e+=1;x=e+2;e%3==0&&jQuery(this).removeClass("first").addClass("last");x%3==0&&jQuery(this).removeClass("last").addClass("first")})})}); -------------------------------------------------------------------------------- /classes/class-projects-admin.php: -------------------------------------------------------------------------------- 1 | dir = dirname( $file ); 35 | $this->file = $file; 36 | $this->assets_dir = trailingslashit( $this->dir ) . 'assets'; 37 | $this->assets_url = esc_url( trailingslashit( plugins_url( '/assets/', $file ) ) ); 38 | $this->token = 'projects'; 39 | $this->post_type = 'project'; 40 | 41 | global $pagenow; 42 | 43 | add_action( 'admin_menu', array( $this, 'meta_box_setup' ), 20 ); 44 | add_action( 'save_post', array( $this, 'meta_box_save' ) ); 45 | add_filter( 'enter_title_here', array( $this, 'enter_title_here' ) ); 46 | add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_styles' ) ); 47 | add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) ); 48 | add_action( 'admin_notices', array( $this, 'configuration_admin_notice' ) ); 49 | add_action( 'do_meta_boxes', array( $this, 'featured_image_label' ) ); 50 | add_filter( 'admin_post_thumbnail_html', array( $this, 'featured_image_set_link' ) ); 51 | add_filter( 'admin_post_thumbnail_html', array( $this, 'featured_image_remove_link' ) ); 52 | add_filter( 'media_view_strings', array( $this, 'featured_image_popup_set_link' ) ); 53 | add_filter( 'manage_edit-' . $this->post_type . '_columns', array( $this, 'register_custom_column_headings' ), 10, 1 ); 54 | add_action( 'manage_' . $this->post_type .'_posts_custom_column', array( $this, 'register_custom_columns' ), 10, 2 ); 55 | 56 | if ( $pagenow == 'edit.php' && isset( $_GET['post_type'] ) && esc_attr( $_GET['post_type'] ) == $this->post_type ) { 57 | add_action( 'restrict_manage_posts', array( $this, 'projects_restrict_manage_posts' ) ); 58 | add_filter( 'parse_query', array( $this, 'projects_post_type_request' ) ); 59 | } 60 | } // End __construct() 61 | 62 | /** 63 | * Filter the request to just give posts for the given taxonomy, if applicable. 64 | * 65 | * @access public 66 | * @param array $post_types - post types to add taxonomy filtering to 67 | * @uses wp_dropdown_categories() 68 | * @since 1.1.0 69 | * @return void 70 | */ 71 | function projects_restrict_manage_posts() { 72 | global $typenow; 73 | 74 | $post_types = array( 'project' ); 75 | 76 | if ( in_array( $typenow, $post_types ) ) { 77 | $filters = get_object_taxonomies( $typenow ); 78 | 79 | foreach ( $filters as $tax_slug ) { 80 | 81 | $tax_obj = get_taxonomy( $tax_slug ); 82 | 83 | if ( isset( $_GET[$tax_slug] ) ) { 84 | $selected = esc_attr( $_GET[$tax_slug] ); 85 | } else { 86 | $selected = null; 87 | } 88 | 89 | wp_dropdown_categories( array( 90 | 'show_option_all' => __( 'Show All ' . $tax_obj->label, 'projects-by-woothemes' ), 91 | 'taxonomy' => $tax_slug, 92 | 'name' => $tax_obj->name, 93 | 'orderby' => 'name', 94 | 'selected' => $selected, 95 | 'hierarchical' => $tax_obj->hierarchical, 96 | 'show_count' => true, 97 | 'hide_empty' => true, 98 | ) ); 99 | } 100 | } 101 | } // projects_restrict_manage_posts() 102 | 103 | /** 104 | * Adjust the query string to use taxonomy slug instead of ID. 105 | * 106 | * @access public 107 | * @param array $filters - all taxonomies for the current post type 108 | * @uses get_object_taxonomies() 109 | * @uses get_term_by() 110 | * @since 1.1.0 111 | * @return void 112 | */ 113 | function projects_post_type_request( $query ) { 114 | global $pagenow, $typenow; 115 | 116 | $filters = get_object_taxonomies( $typenow ); 117 | 118 | foreach ( $filters as $tax_slug ) { 119 | $var = &$query->query_vars[$tax_slug]; 120 | 121 | if ( isset( $var ) ) { 122 | $term = get_term_by( 'id', $var, $tax_slug ); 123 | 124 | if ( false != $term ) { 125 | $var = $term->slug; 126 | } 127 | } 128 | } 129 | 130 | return $query; 131 | } // End projects_post_type_request() 132 | 133 | /** 134 | * Add custom columns for the "manage" screen of this post type. 135 | * 136 | * @access public 137 | * @param string $column_name 138 | * @param int $id 139 | * @since 1.0.0 140 | * @return void 141 | */ 142 | public function register_custom_columns ( $column_name, $id ) { 143 | global $wpdb, $post; 144 | 145 | $meta = get_post_custom( $id ); 146 | 147 | switch ( $column_name ) { 148 | 149 | case 'image': 150 | $value = ''; 151 | 152 | $value = projects_get_image( $id, 120 ); 153 | 154 | echo $value; 155 | break; 156 | 157 | default: 158 | break; 159 | 160 | } 161 | } // End register_custom_columns() 162 | 163 | /** 164 | * Add custom column headings for the "manage" screen of this post type. 165 | * 166 | * @access public 167 | * @param array $defaults 168 | * @since 1.0.0 169 | * @return void 170 | */ 171 | public function register_custom_column_headings ( $defaults ) { 172 | 173 | $new_columns = array(); 174 | $new_columns['cb'] = $defaults['cb']; 175 | $new_columns['image'] = __( 'Cover Image', 'projects-by-woothemes' ); 176 | 177 | $last_item = ''; 178 | 179 | if ( isset( $defaults['date'] ) ) { unset( $defaults['date'] ); } 180 | 181 | if ( count( $defaults ) > 2 ) { 182 | $last_item = array_slice( $defaults, -1 ); 183 | 184 | array_pop( $defaults ); 185 | } 186 | $defaults = array_merge( $new_columns, $defaults ); 187 | 188 | if ( $last_item != '' ) { 189 | foreach ( $last_item as $k => $v ) { 190 | $defaults[$k] = $v; 191 | break; 192 | } 193 | } 194 | 195 | return $defaults; 196 | } // End register_custom_column_headings() 197 | 198 | /** 199 | * Update messages for the post type admin. 200 | * @since 1.0.0 201 | * @param array $messages Array of messages for all post types. 202 | * @return array Modified array. 203 | */ 204 | public function updated_messages ( $messages ) { 205 | global $post, $post_ID, $projects; 206 | 207 | $messages[$this->post_type] = array( 208 | 0 => '', // Unused. Messages start at index 1. 209 | 1 => sprintf( __( '%s updated. View %s%s%s', 'projects-by-woothemes' ), $projects->singular_name, '', strtolower( $projects->singular_name ), '' ), 210 | 2 => __( 'Custom field updated.', 'projects-by-woothemes' ), 211 | 3 => __( 'Custom field deleted.', 'projects-by-woothemes' ), 212 | 4 => sprintf( __( '%s updated.', 'projects-by-woothemes' ), $projects->singular_name ), 213 | /* translators: %s: date and time of the revision */ 214 | 5 => isset( $_GET['revision'] ) ? sprintf( __( '%s restored to revision from %s', 'projects-by-woothemes' ), $projects->singular_name, wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, 215 | 6 => sprintf( __( '%s published. View %s%s%s', 'projects-by-woothemes' ), $projects->singular_name, '', strtolower( $projects->singular_name ), '' ), 216 | 7 => sprintf( __( '%s saved.' ), $projects->singular_name ), 217 | 8 => sprintf( __( '%s submitted. Preview %s%s%s', 'projects-by-woothemes' ), $projects->singular_name, '', strtolower( $projects->singular_name ), '' ), 218 | 9 => sprintf( __( '%s scheduled for: %s. Preview %s', 'projects-by-woothemes' ), $projects->singular_name, 219 | // translators: Publish box date format, see http://php.net/date 220 | '' . date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ) . '', '', strtolower( $projects->singular_name ), '' ), 221 | 10 => sprintf( __( '%s draft updated. Preview %s%s%s', 'projects-by-woothemes' ), $projects->singular_name, '', strtolower( $projects->singular_name ), '' ), 222 | ); 223 | 224 | return $messages; 225 | } // End updated_messages() 226 | 227 | /** 228 | * Setup the meta box. 229 | * 230 | * @access public 231 | * @since 1.1.0 232 | * @return void 233 | */ 234 | public function meta_box_setup () { 235 | global $projects; 236 | 237 | // Add short description meta box (replaces default excerpt) 238 | add_meta_box( 'postexcerpt', sprintf( __( '%s Short Description', 'projects-by-woothemes' ), $projects->singular_name ), array( $this, 'meta_box_short_description' ), $this->post_type, 'normal' ); 239 | 240 | // Project Details Meta Box Load 241 | add_meta_box( 'project-data', sprintf( __( '%s Details', 'projects-by-woothemes' ), $projects->singular_name ), array( $this, 'meta_box_content' ), $this->post_type, 'normal', 'high' ); 242 | 243 | // Project Images Meta Bog Load 244 | add_meta_box( 'project-images', sprintf( __( '%s Gallery', 'projects-by-woothemes' ), $projects->singular_name ), array( $this, 'meta_box_content_project_images' ), $this->post_type, 'side' ); 245 | 246 | } // End meta_box_setup() 247 | 248 | 249 | /** 250 | * The project short description meta box. 251 | * 252 | * @access public 253 | * @since 1.1.0 254 | * @return void 255 | */ 256 | public function meta_box_short_description( $post ) { 257 | $settings = array( 258 | 'textarea_name' => 'excerpt', 259 | 'quicktags' => array( 'buttons' => 'em,strong,link' ), 260 | 'tinymce' => array( 261 | 'theme_advanced_buttons1' => 'bold,italic,strikethrough,separator,bullist,numlist,separator,blockquote,separator,justifyleft,justifycenter,justifyright,separator,link,unlink,separator,undo,redo,separator', 262 | 'theme_advanced_buttons2' => '', 263 | ), 264 | 'editor_css' => '' 265 | ); 266 | 267 | wp_editor( htmlspecialchars_decode( $post->post_excerpt ), 'excerpt', apply_filters( 'projects_product_short_description_editor_settings', $settings ) ); 268 | } // End meta_box_short_description() 269 | 270 | /** 271 | * The contents of our meta box. 272 | * 273 | * @access public 274 | * @since 1.0.0 275 | * @return void 276 | */ 277 | public function meta_box_content () { 278 | global $post_id; 279 | $fields = get_post_custom( $post_id ); 280 | $field_data = $this->get_custom_fields_settings(); 281 | 282 | $html = ''; 283 | 284 | $html .= ''; 285 | 286 | if ( 0 < count( $field_data ) ) { 287 | $html .= '' . "\n"; 288 | $html .= '' . "\n"; 289 | 290 | foreach ( $field_data as $k => $v ) { 291 | $data = isset( $v['default'] ) ? $v['default'] : ''; 292 | if ( isset( $fields['_' . $k] ) && isset( $fields['_' . $k][0] ) ) { 293 | $data = maybe_unserialize( $fields['_' . $k][0] ); 294 | } 295 | 296 | switch ( $v['type'] ) { 297 | case 'hidden': 298 | $field = ''; 299 | $html .= '' . $field . "\n"; 300 | $html .= '' . "\n"; 301 | break; 302 | case 'text': 303 | case 'url': 304 | $field = ''; 305 | $html .= '' . "\n"; 308 | break; 309 | case 'textarea': 310 | $field = ''; 311 | $html .= '' . "\n"; 314 | break; 315 | case 'editor': 316 | $editor_arguments = array( 'media_buttons' => false, 'textarea_rows' => 10 ); 317 | ob_start(); 318 | wp_editor( $data, $k, apply_filters( 'projects_editor_arguments' , $editor_arguments ) ); 319 | $field = ob_get_contents(); 320 | ob_end_clean(); 321 | $html .= '' . "\n"; 324 | break; 325 | case 'upload': 326 | $data_atts = ''; 327 | if ( isset( $v['media-frame']['title'] ) ){ 328 | $data_atts .= sprintf( 'data-title="%s" ', esc_attr( $v['media-frame']['title'] ) ); 329 | } 330 | if ( isset( $v['media-frame']['button'] ) ){ 331 | $data_atts .= sprintf( 'data-button="%s" ', esc_attr( $v['media-frame']['button'] ) ); 332 | } 333 | if ( isset( $v['media-frame']['library'] ) ){ 334 | $data_atts .= sprintf( 'data-library="%s" ', esc_attr( $v['media-frame']['library'] ) ); 335 | } 336 | 337 | $field = ''; 338 | $field .= ''; 339 | $html .= '' . "\n"; 342 | break; 343 | case 'radio': 344 | $field = ''; 345 | if ( isset( $v['options'] ) && is_array( $v['options'] ) ) { 346 | foreach ( $v['options'] as $val => $option ){ 347 | $field .= '

    ' . "\n"; 348 | } 349 | } 350 | $html .= '' . "\n"; 353 | break; 354 | case 'checkbox': 355 | $field = '

    ' . "\n"; 356 | if( isset( $v['description'] ) ) $field .= '

    ' . $v['description'] . '

    ' . "\n"; 357 | $html .= '' . "\n"; 359 | break; 360 | case 'multicheck': 361 | $field = ''; 362 | if( isset( $v['options'] ) && is_array( $v['options'] ) ){ 363 | foreach ( $v['options'] as $val => $option ){ 364 | $field .= '

    ' . "\n"; 365 | } 366 | } 367 | $html .= '' . "\n"; 370 | break; 371 | case 'select': 372 | $field = ''. "\n"; 379 | $html .= '' . "\n"; 382 | break; 383 | default: 384 | $field = apply_filters( 'projects_data_field_type_' . $v['type'], null, $k, $data, $v ); 385 | if ( $field ) { 386 | $html .= '' . "\n"; 389 | } 390 | break; 391 | } 392 | 393 | } 394 | 395 | $html .= '' . "\n"; 396 | $html .= '
    ' . $field . "\n"; 306 | if( isset( $v['description'] ) ) $html .= '

    ' . $v['description'] . '

    ' . "\n"; 307 | $html .= '
    ' . $field . "\n"; 312 | if( isset( $v['description'] ) ) $html .= '

    ' . $v['description'] . '

    ' . "\n"; 313 | $html .= '
    ' . $field . "\n"; 322 | if( isset( $v['description'] ) ) $html .= '

    ' . $v['description'] . '

    ' . "\n"; 323 | $html .= '
    ' . $field . "\n"; 340 | if( isset( $v['description'] ) ) $html .= '

    ' . $v['description'] . '

    ' . "\n"; 341 | $html .= '
    ' . $field . "\n"; 351 | if( isset( $v['description'] ) ) $html .= '

    ' . $v['description'] . '

    ' . "\n"; 352 | $html .= '
    ' . $field . "\n"; 358 | $html .= '
    ' . $field . "\n"; 368 | if( isset( $v['description'] ) ) $html .= '

    ' . $v['description'] . '

    ' . "\n"; 369 | $html .= '
    ' . $field . "\n"; 380 | if( isset( $v['description'] ) ) $html .= '

    ' . $v['description'] . '

    ' . "\n"; 381 | $html .= '
    ' . $field . "\n"; 387 | if( isset( $v['description'] ) ) $html .= '

    ' . $v['description'] . '

    ' . "\n"; 388 | $html .= '
    ' . "\n"; 397 | } 398 | 399 | echo $html; 400 | } // End meta_box_content() 401 | 402 | /** 403 | * Display the project images meta box. 404 | * 405 | * @access public 406 | * @return void 407 | */ 408 | public function meta_box_content_project_images () { 409 | global $post, $projects; 410 | ?> 411 |
    412 | 437 | 438 | 439 | 440 |
    441 |

    442 | singular_name ) ); ?> 443 |

    444 | post_type ) || ! isset( $_POST['woo_' . $this->token . '_nonce'] ) || ! wp_verify_nonce( $_POST['woo_' . $this->token . '_nonce'], plugin_basename( $this->dir ) ) ) { 460 | return $post_id; 461 | } 462 | 463 | if ( 'page' == $_POST['post_type'] ) { 464 | if ( ! current_user_can( 'edit_page', $post_id ) ) { 465 | return $post_id; 466 | } 467 | } else { 468 | if ( ! current_user_can( 'edit_post', $post_id ) ) { 469 | return $post_id; 470 | } 471 | } 472 | 473 | $field_data = $this->get_custom_fields_settings(); 474 | $fields = array_keys( $field_data ); 475 | 476 | foreach ( $fields as $f ) { 477 | 478 | switch ( $field_data[$f]['type'] ) { 479 | case 'url': 480 | ${$f} = isset( $_POST[$f] ) ? esc_url( $_POST[$f] ) : ''; 481 | break; 482 | case 'textarea': 483 | case 'editor': 484 | ${$f} = isset( $_POST[$f] ) ? wp_kses_post( trim( $_POST[$f] ) ) : ''; 485 | break; 486 | case 'checkbox': 487 | ${$f} = isset( $_POST[$f] ) ? 'yes' : 'no'; 488 | break; 489 | case 'multicheck': 490 | // ensure checkbox is array and whitelist accepted values against options 491 | ${$f} = isset( $_POST[$f] ) && is_array( $field_data[$f]['options'] ) ? (array) array_intersect( (array) $_POST[$f], array_flip( $field_data[$f]['options'] ) ) : ''; 492 | break; 493 | case 'radio': 494 | case 'select': 495 | // whitelist accepted value against options 496 | $values = array(); 497 | if ( is_array( $field_data[$f]['options'] ) ) 498 | $values = array_keys( $field_data[$f]['options'] ); 499 | ${$f} = isset( $_POST[$f] ) && in_array( $_POST[$f], $values ) ? $_POST[$f] : ''; 500 | break; 501 | default : 502 | ${$f} = isset( $_POST[$f] ) ? strip_tags( trim( $_POST[$f] ) ) : ''; 503 | break; 504 | } 505 | 506 | // save it 507 | update_post_meta( $post_id, '_' . $f, ${$f} ); 508 | 509 | } 510 | 511 | // Save the project gallery image IDs. 512 | $attachment_ids = array_filter( explode( ',', sanitize_text_field( $_POST['project_image_gallery'] ) ) ); 513 | update_post_meta( $post_id, '_project_image_gallery', implode( ',', $attachment_ids ) ); 514 | 515 | do_action( 'projects_process_meta', $post_id, $field_data, $fields ); 516 | 517 | } // End meta_box_save() 518 | 519 | /** 520 | * Get the settings for the custom fields. 521 | * @since 1.1.0 522 | * @return array 523 | */ 524 | public function get_custom_fields_settings () { 525 | $fields = array(); 526 | 527 | $fields['client'] = array( 528 | 'name' => __( 'Client', 'projects-by-woothemes' ), 529 | 'description' => __( 'Enter the client name. (Optional)', 'projects-by-woothemes' ), 530 | 'type' => 'text', 531 | 'default' => '', 532 | 'section' => 'info' 533 | ); 534 | 535 | $fields['url'] = array( 536 | 'name' => __( 'URL', 'projects-by-woothemes' ), 537 | 'description' => __( 'Enter the project URL. (Optional)', 'projects-by-woothemes' ), 538 | 'type' => 'url', 539 | 'default' => '', 540 | 'section' => 'info' 541 | ); 542 | 543 | return apply_filters( 'projects_custom_fields', $fields ); 544 | } // End get_custom_fields_settings() 545 | 546 | /** 547 | * Customise the "Enter title here" text. 548 | * 549 | * @access public 550 | * @since 1.0.0 551 | * @param string $title 552 | * @return void 553 | */ 554 | public function enter_title_here ( $title ) { 555 | global $projects; 556 | if ( get_post_type() == $this->post_type ) { 557 | $title = sprintf( __( 'Enter the %s title here', 'projects-by-woothemes' ), strtolower( $projects->singular_name ) ); 558 | } 559 | return $title; 560 | } // End enter_title_here() 561 | 562 | /** 563 | * Enqueue post type admin CSS. 564 | * 565 | * @access public 566 | * @since 1.0.0 567 | * @return void 568 | */ 569 | public function enqueue_admin_styles () { 570 | global $pagenow; 571 | 572 | wp_enqueue_style( 'projects-admin', $this->assets_url . '/css/admin.css', array(), '1.0.0' ); 573 | 574 | if ( ( $pagenow == 'post.php' || $pagenow == 'post-new.php' ) && get_post_type() == $this->post_type ) { 575 | wp_enqueue_script( 'projects-admin', $this->assets_url . '/js/admin.js', array( 'jquery' ), '1.0.0', true ); 576 | 577 | 578 | wp_localize_script( 'projects-admin', 'woo_projects_admin', 579 | array( 580 | 'gallery_title' => __( 'Add Images to Project Gallery', 'projects-by-woothemes' ), 581 | 'gallery_button' => __( 'Add to gallery', 'projects-by-woothemes' ), 582 | 'delete_image' => __( 'Delete image', 'projects-by-woothemes' ), 583 | 'default_title' => __( 'Upload', 'projects-by-woothemes' ), 584 | 'default_button' => __( 'Select this', 'projects-by-woothemes' ), 585 | ) 586 | ); 587 | 588 | } 589 | 590 | } // End enqueue_admin_styles() 591 | 592 | /** 593 | * Display an admin notice, if not on the settings screen and if projects page isn't set. 594 | * @access public 595 | * @since 1.0.0 596 | * @return void 597 | */ 598 | public function configuration_admin_notice () { 599 | if ( ( isset( $_GET['page'] ) && 'projects-settings-page' == $_GET['page'] ) ) return; 600 | 601 | $projects_page = projects_get_page_id( 'projects' ); 602 | 603 | if ( -1 == $projects_page ) { 604 | $url = add_query_arg( 'post_type', 'project', admin_url( 'edit.php' ) ); 605 | $url = add_query_arg( 'page', 'projects-settings-page', $url ); 606 | echo '

    ' . sprintf( __( '%sProjects by WooThemes is almost ready.%s To get started, %sconfigure your projects page%s.', 'projects-by-woothemes' ), '', '', '', '' ) . '

    ' . "\n"; 607 | } 608 | } // End configuration_admin_notice() 609 | 610 | /** 611 | * Replace the featured image meta box 612 | * Functionality is identical, this is purely to change the label. 613 | * @access public 614 | * @since 1.0.0 615 | * @return void 616 | */ 617 | public function featured_image_label() { 618 | global $projects; 619 | remove_meta_box( 'postimagediv', 'project', 'side' ); 620 | add_meta_box( 'postimagediv', sprintf( __( '%s Cover Image', 'projects-by-woothemes' ), $projects->singular_name ), 'post_thumbnail_meta_box', 'project', 'side' ); 621 | } // End featured_image_label() 622 | 623 | /** 624 | * Tweak the 'Set featured image' string to say 'Set cover image'. 625 | * @access public 626 | * @since 1.0.0 627 | * @return void 628 | */ 629 | public function featured_image_set_link( $content ) { 630 | $post_type = $this->get_current_post_type(); 631 | 632 | if ( 'project' == $post_type ) { 633 | $content = str_replace( __( 'Set featured image' ), __( 'Set cover image', 'projects-by-woothemes' ), $content ); 634 | } 635 | 636 | return $content; 637 | } // End featured_image_set_link() 638 | 639 | /** 640 | * Tweak the 'Remove featured image' string to say 'Remove cover image'. 641 | * @access public 642 | * @since 1.0.0 643 | * @return void 644 | */ 645 | public function featured_image_remove_link( $content ) { 646 | $post_type = $this->get_current_post_type(); 647 | 648 | if ( 'project' == $post_type ) { 649 | $content = str_replace( __( 'Remove featured image' ), __( 'Remove cover image', 'projects-by-woothemes' ), $content ); 650 | } 651 | 652 | return $content; 653 | } // End featured_image_remove_link() 654 | 655 | /** 656 | * Tweak the featured image strings in the media popup 657 | * @access public 658 | * @since 1.0.0 659 | * @return void 660 | */ 661 | public function featured_image_popup_set_link( $strings ) { 662 | $post_type = $this->get_current_post_type(); 663 | if ( 'project' == $post_type ) { 664 | $strings['setFeaturedImageTitle'] = __( 'Set Cover Image', 'projects-by-woothemes' ); 665 | $strings['setFeaturedImage'] = __( 'Set cover image', 'projects-by-woothemes' ); 666 | } 667 | return $strings; 668 | } // End featured_image_popup_set_link() 669 | 670 | /** 671 | * Determine what post type the current admin page is related to 672 | * @access public 673 | * @since 1.0.0 674 | * @return string 675 | */ 676 | public function get_current_post_type() { 677 | global $post, $typenow, $current_screen; 678 | 679 | if ( $post && $post->post_type ) 680 | return $post->post_type; 681 | 682 | elseif ( $typenow ) 683 | return $typenow; 684 | 685 | elseif ( $current_screen && $current_screen->post_type ) 686 | return $current_screen->post_type; 687 | 688 | elseif ( isset( $_REQUEST['post_type'] ) ) 689 | return sanitize_key( $_REQUEST['post_type'] ); 690 | 691 | return null; 692 | } // End get_current_post_type() 693 | 694 | } // End Class 695 | -------------------------------------------------------------------------------- /classes/class-projects-frontend.php: -------------------------------------------------------------------------------- 1 | template_loader = new Projects_Template_Loader(); 43 | add_filter( 'template_include', array( $this->template_loader, 'template_loader' ) ); 44 | require_once( 'class-projects-query.php' ); 45 | $this->projects_query = new Projects_Query(); 46 | } // End __construct() 47 | } // End Class 48 | ?> -------------------------------------------------------------------------------- /classes/class-projects-integrations.php: -------------------------------------------------------------------------------- 1 | token = 'projects'; 27 | $this->post_type = 'project'; 28 | 29 | // Testimonials Integration 30 | add_action( 'init', array( $this, 'projects_testimonials_init' ) ); 31 | 32 | // WooCommerce Integration 33 | add_action( 'init', array( $this, 'projects_woocommerce_init' ) ); 34 | 35 | } // End __construct() 36 | 37 | 38 | /** 39 | * Init function for the Testimonials plugin integration. 40 | * @since 1.1.0 41 | * @return void 42 | */ 43 | public function projects_testimonials_init() { 44 | 45 | if ( class_exists( 'Woothemes_Testimonials' ) ) { 46 | 47 | // Add custom fields 48 | add_filter( 'projects_custom_fields', array( $this, 'testimonials_custom_fields' ) ); 49 | 50 | // Enqueue admin JavaScript 51 | add_action( 'admin_enqueue_scripts', array( $this, 'testimonials_admin_scripts' ) ); 52 | add_action( 'wp_ajax_get_testimonials', array( $this, 'get_testimonials_callback' ) ); 53 | add_action( 'admin_footer', array( $this, 'testimonials_javascript' ) ); 54 | 55 | } 56 | 57 | } // End projects_testimonials_init() 58 | 59 | public function testimonials_admin_scripts () { 60 | wp_enqueue_script( 'jquery-ui-autocomplete', null, array( 'jquery' ), null, false); 61 | } // End projects_testimonials_admin_scripts() 62 | 63 | /** 64 | * Ajax callback to search for testimonials. 65 | * @param string $query Search Query. 66 | * @since 1.1.0 67 | * @return json Search Results. 68 | */ 69 | public function get_testimonials_callback() { 70 | 71 | check_ajax_referer( 'projects_ajax_get_testimonials', 'security' ); 72 | 73 | $term = urldecode( stripslashes( strip_tags( $_GET['term'] ) ) ); 74 | 75 | if ( !empty( $term ) ) { 76 | 77 | header( 'Content-Type: application/json; charset=utf-8' ); 78 | 79 | $query_args = array( 80 | 'post_type' => 'testimonial', 81 | 'orderby' => 'title', 82 | 's' => $term, 83 | 'suppress_filters' => false 84 | ); 85 | 86 | $testimonials = get_posts( $query_args ); 87 | 88 | $found_testimonials = array(); 89 | 90 | if ( $testimonials ) { 91 | foreach ( $testimonials as $testimonial ) { 92 | $found_testimonials[] = array( 93 | 'id' => $testimonial->ID, 94 | 'title' => $testimonial->post_title 95 | ); 96 | } 97 | } 98 | 99 | echo json_encode( $found_testimonials ); 100 | 101 | } 102 | 103 | die(); 104 | 105 | } // End get_testimonials_callback() 106 | 107 | /** 108 | * Output Testimonials admin javascript 109 | * @since 1.1.0 110 | * @return void 111 | */ 112 | public function testimonials_javascript() { 113 | 114 | global $pagenow, $post_type; 115 | 116 | if ( ( $pagenow == 'post.php' || $pagenow == 'post-new.php' ) && isset( $post_type ) && esc_attr( $post_type ) == $this->post_type ) { 117 | 118 | $ajax_nonce = wp_create_nonce( 'projects_ajax_get_testimonials' ); 119 | 120 | ?> 121 | 158 | __( 'Testimonial', 'projects-by-woothemes' ), 166 | 'description' => __( 'Search for Testimonial to link to this Project. (Optional)', 'projects-by-woothemes' ), 167 | 'type' => 'text', 168 | 'default' => '', 169 | 'section' => 'info', 170 | ); 171 | 172 | $fields['testimonials_id'] = array( 173 | 'name' => __( 'Testimonial ID', 'projects-by-woothemes' ), 174 | 'description' => __( 'Holds the id of the selected testimonial.', 'projects-by-woothemes' ), 175 | 'type' => 'hidden', 176 | 'default' => 0, 177 | 'section' => 'info', 178 | ); 179 | 180 | return $fields; 181 | 182 | } // End testimonials_custom_fields() 183 | 184 | /** 185 | * Init function for the WooCommerce plugin integration. 186 | * @since 1.2.0 187 | * @return void 188 | */ 189 | public function projects_woocommerce_init() { 190 | 191 | if ( class_exists( 'WooCommerce' ) ) { 192 | 193 | // Add custom fields 194 | add_filter( 'projects_custom_fields', array( $this, 'woocommerce_custom_fields' ) ); 195 | 196 | // Enqueue admin JavaScript 197 | add_action( 'admin_enqueue_scripts', array( $this, 'woocommerce_admin_scripts' ) ); 198 | add_action( 'wp_ajax_get_products', array( $this, 'get_products_callback' ) ); 199 | add_action( 'admin_footer', array( $this, 'woocommerce_javascript' ) ); 200 | 201 | } 202 | 203 | } // End projects_woocommerce_init() 204 | 205 | public function woocommerce_admin_scripts () { 206 | wp_enqueue_script( 'jquery-ui-autocomplete', null, array( 'jquery' ), null, false ); 207 | } // End projects_woocommerce_admin_scripts() 208 | 209 | /** 210 | * Ajax callback to search for products. 211 | * @param string $query Search Query. 212 | * @since 1.2.0 213 | * @return json Search Results. 214 | */ 215 | public function get_products_callback() { 216 | check_ajax_referer( 'projects_ajax_get_products', 'security' ); 217 | 218 | $term = urldecode( stripslashes( strip_tags( $_GET['term'] ) ) ); 219 | 220 | if ( ! empty( $term ) ) { 221 | 222 | header( 'Content-Type: application/json; charset=utf-8' ); 223 | 224 | $query_args = array( 225 | 'post_type' => 'product', 226 | 'orderby' => 'title', 227 | 's' => $term, 228 | 'suppress_filters' => false 229 | ); 230 | 231 | $products = get_posts( $query_args ); 232 | 233 | $found_products = array(); 234 | 235 | if ( $products ) { 236 | 237 | foreach ( $products as $product ) { 238 | 239 | $_product = new WC_Product( $product->ID ); 240 | 241 | if ( $_product->get_sku() ) { 242 | $identifier = $_product->get_sku(); 243 | } else { 244 | $identifier = '#' . $_product->id; 245 | } 246 | 247 | $found_products[] = array( 248 | 'id' => $product->ID, 249 | 'title' => $product->post_title, 250 | 'identifier' => $identifier, 251 | ); 252 | } 253 | } 254 | 255 | echo json_encode( $found_products ); 256 | } 257 | 258 | die(); 259 | 260 | } // End get_products_callback() 261 | 262 | /** 263 | * Output Products admin javascript 264 | * @since 1.2.0 265 | * @return void 266 | */ 267 | public function woocommerce_javascript() { 268 | 269 | global $pagenow, $post_type; 270 | 271 | if ( ( $pagenow == 'post.php' || $pagenow == 'post-new.php' ) && isset( $post_type ) && esc_attr( $post_type ) == $this->post_type ) { 272 | 273 | $ajax_nonce = wp_create_nonce( 'projects_ajax_get_products' ); 274 | 275 | ?> 276 | 313 | __( 'Product', 'projects-by-woothemes' ), 321 | 'description' => __( 'Search for Product to link to this Project. (Optional)', 'projects-by-woothemes' ), 322 | 'type' => 'text', 323 | 'default' => '', 324 | 'section' => 'info', 325 | ); 326 | 327 | $fields['products_id'] = array( 328 | 'name' => __( 'Product ID', 'projects-by-woothemes' ), 329 | 'description' => __( 'Holds the id of the selected product.', 'projects-by-woothemes' ), 330 | 'type' => 'hidden', 331 | 'default' => 0, 332 | 'section' => 'info', 333 | ); 334 | 335 | return $fields; 336 | 337 | } // End woocommerce_custom_fields() 338 | 339 | } // End Class 340 | 341 | new Projects_Integrations(); -------------------------------------------------------------------------------- /classes/class-projects-query.php: -------------------------------------------------------------------------------- 1 | init_query_vars(); 63 | } // End __construct() 64 | 65 | /** 66 | * Init query vars by loading options. 67 | */ 68 | public function init_query_vars() { 69 | // Query vars to add to WP 70 | $this->query_vars = array(); 71 | } 72 | 73 | /** 74 | * add_query_vars function. 75 | * 76 | * @access public 77 | * @param array $vars 78 | * @return array 79 | */ 80 | public function add_query_vars( $vars ) { 81 | foreach ( $this->query_vars as $key => $var ) { 82 | $vars[] = $key; 83 | } 84 | 85 | return $vars; 86 | } 87 | 88 | /** 89 | * Get query vars 90 | * 91 | * @return array 92 | */ 93 | public function get_query_vars() { 94 | return $this->query_vars; 95 | } 96 | 97 | /** 98 | * Parse the request and look for query vars - endpoints may not be supported 99 | */ 100 | public function parse_request() { 101 | global $wp; 102 | 103 | // Map query vars to their keys, or get them if endpoints are not supported 104 | foreach ( $this->query_vars as $key => $var ) { 105 | if ( isset( $_GET[ $var ] ) ) { 106 | $wp->query_vars[ $key ] = $_GET[ $var ]; 107 | } 108 | 109 | elseif ( isset( $wp->query_vars[ $var ] ) ) { 110 | $wp->query_vars[ $key ] = $wp->query_vars[ $var ]; 111 | } 112 | } 113 | } 114 | 115 | /** 116 | * Hook into pre_get_posts to do the main project query 117 | * 118 | * @param mixed $q query object 119 | */ 120 | public function pre_get_posts( $q ) { 121 | // We only want to affect the main query 122 | if ( ! $q->is_main_query() ) { 123 | return; 124 | } 125 | 126 | // Fix for verbose page rules 127 | if ( $GLOBALS['wp_rewrite']->use_verbose_page_rules && isset( $q->queried_object_id ) && $q->queried_object_id === projects_get_page_id( 'projects' ) ) { 128 | $q->set( 'post_type', 'project' ); 129 | $q->set( 'page', '' ); 130 | $q->set( 'pagename', '' ); 131 | 132 | // Fix conditional Functions 133 | $q->is_archive = true; 134 | $q->is_post_type_archive = true; 135 | $q->is_singular = false; 136 | $q->is_page = false; 137 | } 138 | 139 | // Fix for endpoints on the homepage 140 | if ( $q->is_home() && 'page' == get_option('show_on_front') && get_option('page_on_front') != $q->get('page_id') ) { 141 | $_query = wp_parse_args( $q->query ); 142 | if ( ! empty( $_query ) && array_intersect( array_keys( $_query ), array_keys( $this->query_vars ) ) ) { 143 | $q->is_page = true; 144 | $q->is_home = false; 145 | $q->is_singular = true; 146 | 147 | $q->set( 'page_id', get_option('page_on_front') ); 148 | } 149 | } 150 | 151 | // When orderby is set, WordPress shows posts. Get around that here. 152 | if ( $q->is_home() && 'page' == get_option('show_on_front') && get_option('page_on_front') == projects_get_page_id( 'projects' ) ) { 153 | $_query = wp_parse_args( $q->query ); 154 | if ( empty( $_query ) || ! array_diff( array_keys( $_query ), array( 'preview', 'page', 'paged', 'cpage', 'orderby' ) ) ) { 155 | $q->is_page = true; 156 | $q->is_home = false; 157 | $q->set( 'page_id', get_option('page_on_front') ); 158 | $q->set( 'post_type', 'project' ); 159 | } 160 | } 161 | 162 | // Special check for the project archive on front 163 | if ( $q->is_page() && 'page' == get_option( 'show_on_front' ) && $q->get('page_id') == projects_get_page_id( 'projects' ) ) { 164 | 165 | // This is a front-page projects 166 | $q->set( 'post_type', 'project' ); 167 | $q->set( 'page_id', '' ); 168 | if ( isset( $q->query['paged'] ) ) { 169 | $q->set( 'paged', $q->query['paged'] ); 170 | } 171 | 172 | // Define a variable so we know this is the front page projects later on 173 | define( 'PROJECT_IS_ON_FRONT', true ); 174 | 175 | // Get the actual WP page to avoid errors and let us use is_front_page() 176 | // This is hacky but works. Awaiting http://core.trac.wordpress.org/ticket/21096 177 | global $wp_post_types; 178 | 179 | $project_page = get_post( projects_get_page_id( 'projects' ) ); 180 | 181 | $wp_post_types['project']->ID = $project_page->ID; 182 | $wp_post_types['project']->post_title = $project_page->post_title; 183 | $wp_post_types['project']->post_name = $project_page->post_name; 184 | $wp_post_types['project']->post_type = $project_page->post_type; 185 | $wp_post_types['project']->ancestors = get_ancestors( $project_page->ID, $project_page->post_type ); 186 | 187 | // Fix conditional Functions like is_front_page 188 | $q->is_singular = false; 189 | $q->is_post_type_archive = true; 190 | $q->is_archive = true; 191 | $q->is_page = true; 192 | 193 | // Fix WP SEO 194 | if ( class_exists( 'WPSEO_Meta' ) ) { 195 | add_filter( 'wpseo_metadesc', array( $this, 'wpseo_metadesc' ) ); 196 | add_filter( 'wpseo_metakey', array( $this, 'wpseo_metakey' ) ); 197 | } 198 | 199 | // Only apply to project categories, the project post archive, the projects page, project tags, and project attribute taxonomies 200 | } elseif ( ! $q->is_post_type_archive( 'project' ) && ! $q->is_tax( get_object_taxonomies( 'project' ) ) ) { 201 | return; 202 | } 203 | 204 | $this->project_query( $q ); 205 | 206 | if ( is_search() ) { 207 | add_filter( 'posts_where', array( $this, 'search_post_excerpt' ) ); 208 | add_filter( 'wp', array( $this, 'remove_posts_where' ) ); 209 | } 210 | 211 | // We're on a projects page so queue the get_projects_in_view function 212 | add_action( 'wp', array( $this, 'get_projects_in_view' ), 2); 213 | 214 | // And remove the pre_get_posts hook 215 | $this->remove_project_query(); 216 | } 217 | 218 | /** 219 | * search_post_excerpt function. 220 | * 221 | * @access public 222 | * @param string $where (default: '') 223 | * @return string (modified where clause) 224 | */ 225 | public function search_post_excerpt( $where = '' ) { 226 | global $wp_the_query; 227 | 228 | // If this is not a WC Query, do not modify the query 229 | if ( empty( $wp_the_query->query_vars['projects_query'] ) || empty( $wp_the_query->query_vars['s'] ) ) 230 | return $where; 231 | 232 | $where = preg_replace( 233 | "/post_title\s+LIKE\s*(\'\%[^\%]+\%\')/", 234 | "post_title LIKE $1) OR (post_excerpt LIKE $1", $where ); 235 | 236 | return $where; 237 | } 238 | 239 | /** 240 | * wpseo_metadesc function. 241 | * Hooked into wpseo_ hook already, so no need for function_exist 242 | * 243 | * @access public 244 | * @return string 245 | */ 246 | public function wpseo_metadesc() { 247 | return WPSEO_Meta::get_value( 'metadesc', projects_get_page_id('projects') ); 248 | } 249 | 250 | /** 251 | * wpseo_metakey function. 252 | * Hooked into wpseo_ hook already, so no need for function_exist 253 | * 254 | * @access public 255 | * @return string 256 | */ 257 | public function wpseo_metakey() { 258 | return WPSEO_Meta::get_value( 'metakey', projects_get_page_id('projects') ); 259 | } 260 | 261 | /** 262 | * Hook into the_posts to do the main project query if needed - relevanssi compatibility 263 | * 264 | * @access public 265 | * @param array $posts 266 | * @param WP_Query|bool $query (default: false) 267 | * @return array 268 | */ 269 | public function the_posts( $posts, $query = false ) { 270 | // Abort if there's no query 271 | if ( ! $query ) 272 | return $posts; 273 | 274 | // Abort if we're not filtering posts 275 | if ( empty( $this->post__in ) ) 276 | return $posts; 277 | 278 | // Abort if this query has already been done 279 | if ( ! empty( $query->projects_query ) ) 280 | return $posts; 281 | 282 | // Abort if this isn't a search query 283 | if ( empty( $query->query_vars["s"] ) ) 284 | return $posts; 285 | 286 | // Abort if we're not on a post type archive/project taxonomy 287 | if ( ! $query->is_post_type_archive( 'project' ) && ! $query->is_tax( get_object_taxonomies( 'project' ) ) ) 288 | return $posts; 289 | 290 | $filtered_posts = array(); 291 | $queried_post_ids = array(); 292 | 293 | foreach ( $posts as $post ) { 294 | if ( in_array( $post->ID, $this->post__in ) ) { 295 | $filtered_posts[] = $post; 296 | $queried_post_ids[] = $post->ID; 297 | } 298 | } 299 | 300 | $query->posts = $filtered_posts; 301 | $query->post_count = count( $filtered_posts ); 302 | 303 | // Ensure filters are set 304 | $this->unfiltered_project_ids = $queried_post_ids; 305 | $this->filtered_project_ids = $queried_post_ids; 306 | 307 | if ( sizeof( $this->layered_nav_post__in ) > 0 ) { 308 | $this->layered_nav_project_ids = array_intersect( $this->unfiltered_project_ids, $this->layered_nav_post__in ); 309 | } else { 310 | $this->layered_nav_project_ids = $this->unfiltered_project_ids; 311 | } 312 | 313 | return $filtered_posts; 314 | } 315 | 316 | /** 317 | * Query the projects, applying sorting/ordering etc. This applies to the main wordpress loop 318 | * 319 | * @param mixed $q 320 | */ 321 | public function project_query( $q ) { 322 | 323 | // Meta query 324 | $meta_query = $this->get_meta_query( $q->get( 'meta_query' ) ); 325 | 326 | // Get a list of post id's which match the current filters set (in the layered nav and price filter) 327 | $post__in = array_unique( apply_filters( 'loop_projects_post_in', array() ) ); 328 | 329 | // Query vars that affect posts shown 330 | $q->set( 'meta_query', $meta_query ); 331 | $q->set( 'post__in', $post__in ); 332 | $q->set( 'posts_per_page', $q->get( 'posts_per_page' ) ? $q->get( 'posts_per_page' ) : apply_filters( 'loop_projects_per_page', get_option( 'posts_per_page' ) ) ); 333 | 334 | // Set a special variable 335 | $q->set( 'projects_query', 'project_query' ); 336 | 337 | // Store variables 338 | $this->post__in = $post__in; 339 | $this->meta_query = $meta_query; 340 | 341 | do_action( 'projects_project_query', $q, $this ); 342 | } 343 | 344 | /** 345 | * Remove the query 346 | */ 347 | public function remove_project_query() { 348 | remove_action( 'pre_get_posts', array( $this, 'pre_get_posts' ) ); 349 | } 350 | 351 | /** 352 | * Remove the posts_where filter 353 | */ 354 | public function remove_posts_where() { 355 | remove_filter( 'posts_where', array( $this, 'search_post_excerpt' ) ); 356 | } 357 | 358 | /** 359 | * Get an unpaginated list all project ID's (both filtered and unfiltered). 360 | */ 361 | public function get_projects_in_view() { 362 | global $wp_the_query; 363 | 364 | // Get main query 365 | $current_wp_query = $wp_the_query->query; 366 | 367 | // Get WP Query for current page (without 'paged') 368 | unset( $current_wp_query['paged'] ); 369 | 370 | // Get all visible posts, regardless of filters 371 | $unfiltered_project_ids = get_posts( 372 | array_merge( 373 | $current_wp_query, 374 | array( 375 | 'post_type' => 'project', 376 | 'numberposts' => -1, 377 | 'post_status' => 'publish', 378 | 'meta_query' => $this->meta_query, 379 | 'fields' => 'ids', 380 | 'no_found_rows' => true, 381 | 'update_post_meta_cache' => false, 382 | 'update_post_term_cache' => false, 383 | 'pagename' => '', 384 | 'projects_query' => 'get_projects_in_view' 385 | ) 386 | ) 387 | ); 388 | 389 | // Store the variable 390 | $this->unfiltered_project_ids = $unfiltered_project_ids; 391 | 392 | // Also store filtered posts ids... 393 | if ( sizeof( $this->post__in ) > 0 ) { 394 | $this->filtered_project_ids = array_intersect( $this->unfiltered_project_ids, $this->post__in ); 395 | } else { 396 | $this->filtered_project_ids = $this->unfiltered_project_ids; 397 | } 398 | 399 | // And filtered post ids which just take layered nav into consideration 400 | if ( sizeof( $this->layered_nav_post__in ) > 0 ) { 401 | $this->layered_nav_project_ids = array_intersect( $this->unfiltered_project_ids, $this->layered_nav_post__in ); 402 | } else { 403 | $this->layered_nav_project_ids = $this->unfiltered_project_ids; 404 | } 405 | } 406 | 407 | /** 408 | * Appends meta queries to an array. 409 | * @access public 410 | * @param array $meta_query 411 | * @return array 412 | */ 413 | public function get_meta_query( $meta_query = array() ) { 414 | if ( ! is_array( $meta_query ) ) 415 | $meta_query = array(); 416 | 417 | return array_filter( $meta_query ); 418 | } 419 | 420 | } // End Class -------------------------------------------------------------------------------- /classes/class-projects-settings.php: -------------------------------------------------------------------------------- 1 | get_settings_sections(); 51 | if ( isset ( $_GET['tab'] ) ) { 52 | $tab = $_GET['tab']; 53 | } else { 54 | list( $first_section ) = array_keys( $sections ); 55 | $tab = $first_section; 56 | } // End If Statement 57 | ?> 58 |
    59 | 60 |

    61 | 74 |
    75 | 76 | 80 | 81 |

    82 | 83 |

    84 | 85 |
    86 | 87 |
    88 | get_settings_sections(); 94 | if ( 0 < count( $sections ) ) { 95 | foreach ( $sections as $k => $v ) { 96 | $callback_array = explode( '-', $k ); 97 | if ( method_exists( $this, 'projects_' . $callback_array[0] . '_settings_validate' ) ) { 98 | register_setting( 'projects-settings-' . $k, 'projects-' . $k, array( $this, 'projects_' . $callback_array[0] . '_settings_validate' ) ); 99 | add_settings_section( $k, $v, array( $this, 'projects_' . $callback_array[0] . '_settings' ), 'projects-' . $k ); 100 | } elseif( function_exists( 'projects_' . $callback_array[0] . '_settings_validate' ) ) { 101 | register_setting( 'projects-settings-' . $k, 'projects-' . $k, 'projects_' . $callback_array[0] . '_settings_validate' ); 102 | add_settings_section( $k, $v, 'projects_' . $callback_array[0] . '_settings', 'projects-' . $k ); 103 | } // End If Statement 104 | } // End For Loop 105 | } // End If Statement 106 | 107 | } // End projects_options_init() 108 | 109 | public function projects_pages_settings() { 110 | ?> 111 |

    112 | 'projects-pages-fields[projects_page_id]', 116 | 'selected' => absint( $options['projects_page_id'] ), 117 | 'sort_column' => 'menu_order', 118 | 'sort_order' => 'ASC', 119 | 'show_option_none' => ' ', 120 | ); 121 | ?> 122 | 123 | 124 | 125 | 131 | 132 |
    126 | 127 |

    128 | 129 |

    130 |
    133 | 138 |

    .

    139 | array( 145 | 'width' => 300, 146 | 'height' => 300, 147 | 'crop' => 'no' 148 | ), 149 | 'project-single' => array( 150 | 'width' => 1024, 151 | 'height' => 1024, 152 | 'crop' => 'no' 153 | ), 154 | 'project-thumbnail' => array( 155 | 'width' => 100, 156 | 'height' => 100, 157 | 'crop' => 'yes' 158 | ) 159 | ) ); 160 | 161 | // Parse incomming $options into an array and merge it with $defaults 162 | $options = wp_parse_args( $options, $defaults ); 163 | 164 | ?> 165 | 166 | 167 | 170 | 174 | 175 | 176 | 179 | 183 | 184 | 185 | 188 | 192 | 193 |
    168 | 169 | 171 | 172 | /> 173 |
    177 | 178 | 180 | 181 | /> 182 |
    186 | 187 | 189 | 190 | /> 191 |
    194 | 'projects', 31 | 'before' => null, 32 | 'after' => null 33 | ) 34 | ){ 35 | ob_start(); 36 | 37 | $before = empty( $wrapper['before'] ) ? '
    ' : $wrapper['before']; 38 | $after = empty( $wrapper['after'] ) ? '
    ' : $wrapper['after']; 39 | 40 | echo $before; 41 | call_user_func( $function, $atts ); 42 | echo $after; 43 | 44 | return ob_get_clean(); 45 | } 46 | 47 | /** 48 | * Recent Products shortcode 49 | * 50 | * @access public 51 | * @param array $atts 52 | * @return string 53 | */ 54 | public function projects( $atts ) { 55 | 56 | global $projects_loop; 57 | 58 | extract( shortcode_atts( array( 59 | 'limit' => '12', 60 | 'columns' => '2', 61 | 'orderby' => 'date', 62 | 'order' => 'desc', 63 | 'exclude_categories' => null, 64 | 'include_children' => true 65 | ), $atts ) ); 66 | 67 | // Cater for fallback on false attribute 68 | if ( $include_children === 'false' ) { 69 | $include_children = false; 70 | } // End If Statement 71 | 72 | $args = array( 73 | 'post_type' => 'project', 74 | 'post_status' => 'publish', 75 | 'ignore_sticky_posts' => 1, 76 | 'posts_per_page' => $limit, 77 | 'orderby' => $orderby, 78 | 'order' => $order, 79 | 'tax_query' => array( 80 | array( 81 | 'taxonomy' => 'project-category', 82 | 'field' => 'id', 83 | 'terms' => explode( ',', $exclude_categories ), 84 | 'include_children' => $include_children, 85 | 'operator' => 'NOT IN' 86 | ) 87 | ) 88 | ); 89 | 90 | ob_start(); 91 | 92 | $projects = new WP_Query( apply_filters( 'projects_query', $args, $atts ) ); 93 | 94 | $projects_loop['columns'] = $columns; 95 | 96 | if ( $projects->have_posts() ) : ?> 97 | 98 | 99 | 100 | have_posts() ) : $projects->the_post(); ?> 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | ' . ob_get_clean() . ''; 113 | 114 | } 115 | 116 | } 117 | 118 | 119 | new Projects_Shortcodes(); -------------------------------------------------------------------------------- /classes/class-projects-taxonomy.php: -------------------------------------------------------------------------------- 1 | post_type = 'project'; 67 | $this->token = esc_attr( $token ); 68 | $this->singular = apply_filters( 'projects_taxonomy_' . $this->token . '_singular_name', esc_html($singular) ); 69 | $this->plural = apply_filters( 'projects_taxonomy_' . $this->token . '_plural_name', esc_html($plural) ); 70 | 71 | if ( '' == $this->singular ) $this->singular = __( 'Category', 'projects-by-woothemes' ); 72 | if ( '' == $this->plural ) $this->plural = __( 'Categories', 'projects-by-woothemes' ); 73 | 74 | $this->args = wp_parse_args( $args, $this->_get_default_args() ); 75 | } // End __construct() 76 | 77 | /** 78 | * Return an array of default arguments. 79 | * @access private 80 | * @since 1.0.0 81 | * @return array Default arguments. 82 | */ 83 | private function _get_default_args () { 84 | return array( 85 | 'labels' => $this->_get_default_labels(), 86 | 'public' => true, 87 | 'hierarchical' => true, 88 | 'show_ui' => true, 89 | 'show_admin_column' => true, 90 | 'query_var' => true, 91 | 'show_in_nav_menus' => true, 92 | 'show_tagcloud' => false, 93 | 'rewrite' => array( 'slug' => ( $projects_page_id = projects_get_page_id( 'projects' ) ) && get_page( $projects_page_id ) ? get_page_uri( $projects_page_id ) : 'projects', 'with_front' => false ) 94 | ); 95 | } // End _get_default_args() 96 | 97 | /** 98 | * Return an array of default labels. 99 | * @access private 100 | * @since 1.3.0 101 | * @return array Default labels. 102 | */ 103 | private function _get_default_labels () { 104 | return array( 105 | 'name' => sprintf( _x( 'Project %s', 'taxonomy general name', 'projects-by-woothemes' ), $this->plural ), 106 | 'singular_name' => sprintf( _x( '%s', 'taxonomy singular name', 'projects-by-woothemes' ), $this->singular ), 107 | 'search_items' => sprintf( __( 'Search %s', 'projects-by-woothemes' ), $this->plural ), 108 | 'all_items' => sprintf( __( 'All %s', 'projects-by-woothemes' ), $this->plural ), 109 | 'parent_item' => sprintf( __( 'Parent %s', 'projects-by-woothemes' ), $this->singular ), 110 | 'parent_item_colon' => sprintf( __( 'Parent %s:', 'projects-by-woothemes' ), $this->singular ), 111 | 'edit_item' => sprintf( __( 'Edit %s', 'projects-by-woothemes' ), $this->singular ), 112 | 'update_item' => sprintf( __( 'Update %s', 'projects-by-woothemes' ), $this->singular ), 113 | 'add_new_item' => sprintf( __( 'Add New %s', 'projects-by-woothemes' ), $this->singular ), 114 | 'new_item_name' => sprintf( __( 'New %s Name', 'projects-by-woothemes' ), $this->singular ), 115 | 'menu_name' => sprintf( __( '%s', 'projects-by-woothemes' ), $this->plural ) 116 | ); 117 | } // End _get_default_labels() 118 | 119 | /** 120 | * Register the taxonomy. 121 | * @access public 122 | * @since 1.0.0 123 | * @return void 124 | */ 125 | public function register () { 126 | $args = apply_filters( 'projects_register_taxonomy', $this->args ); 127 | register_taxonomy( esc_attr( $this->token ), esc_attr( $this->post_type ), (array) $args ); 128 | } // End register() 129 | } // End Class 130 | -------------------------------------------------------------------------------- /classes/class-projects-template-loader.php: -------------------------------------------------------------------------------- 1 | template_url = apply_filters( 'projects_template_url', 'projects/' ); 13 | } // End __construct() 14 | 15 | /** 16 | * Load a template. 17 | * 18 | * Handles template usage so that we can use our own templates instead of the themes. 19 | * 20 | * Templates are in the 'templates' folder. projects looks for theme 21 | * overrides in /theme/projects/ by default 22 | * 23 | * @access public 24 | * @param mixed $template 25 | * @return string 26 | */ 27 | public function template_loader ( $template ) { 28 | global $projects, $post; 29 | 30 | $find = array( 'projects.php' ); 31 | $file = ''; 32 | 33 | if ( is_single() && 'project' == get_post_type() ) { 34 | 35 | $file = 'single-project.php'; 36 | $find[] = $file; 37 | $find[] = $this->template_url . $file; 38 | 39 | } elseif ( is_tax( 'project-category' ) ) { 40 | 41 | $term = get_queried_object(); 42 | 43 | $file = 'taxonomy-' . $term->taxonomy . '.php'; 44 | $find[] = 'taxonomy-' . $term->taxonomy . '-' . $term->slug . '.php'; 45 | $find[] = $this->template_url . 'taxonomy-' . $term->taxonomy . '-' . $term->slug . '.php'; 46 | $find[] = $file; 47 | $find[] = $this->template_url . $file; 48 | 49 | } elseif ( is_post_type_archive( 'project' ) || is_page( projects_get_page_id( 'projects' ) ) ) { 50 | 51 | $file = 'archive-project.php'; 52 | $find[] = $file; 53 | $find[] = $this->template_url . $file; 54 | 55 | } 56 | 57 | if ( $file ) { 58 | $template = locate_template( $find ); 59 | if ( ! $template ) $template = $projects->plugin_path() . '/templates/' . $file; 60 | } 61 | 62 | return $template; 63 | } // End template_loader() 64 | } // End Class -------------------------------------------------------------------------------- /classes/class-widget-project-categories.php: -------------------------------------------------------------------------------- 1 | projects_widget_cssclass = 'widget_projects_categories'; 42 | $this->projects_widget_description = __( 'Project Categories', 'projects-by-woothemes' ); 43 | $this->projects_widget_idbase = 'woothemes-project-categories'; 44 | $this->projects_widget_title = __( 'Project Categories', 'projects-by-woothemes' ); 45 | 46 | /* Widget settings. */ 47 | $widget_ops = array( 48 | 'classname' => $this->projects_widget_cssclass, 49 | 'description' => $this->projects_widget_description 50 | ); 51 | 52 | /* Widget control settings. */ 53 | $control_ops = array( 54 | 'id_base' => $this->projects_widget_idbase 55 | ); 56 | 57 | /* Create the widget. */ 58 | parent::__construct( $this->projects_widget_idbase, $this->projects_widget_title, $widget_ops, $control_ops ); 59 | } // End __construct() 60 | 61 | /** 62 | * Display the widget on the frontend. 63 | * @since 1.0.0 64 | * @param array $args Widget arguments. 65 | * @param array $instance Widget settings for this instance. 66 | * @return void 67 | */ 68 | public function widget( $args, $instance ) { 69 | extract( $args, EXTR_SKIP ); 70 | 71 | /* Our variables from the widget settings. */ 72 | $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ); 73 | 74 | $args = array(); 75 | 76 | /* Display the widget title if one was input (before and after defined by themes). */ 77 | if ( $title ) { $args['title'] = $title; } 78 | 79 | /* Widget content. */ 80 | // Add actions for plugins/themes to hook onto. 81 | do_action( $this->projects_widget_cssclass . '_top' ); 82 | 83 | // Checkbox values. 84 | if ( isset( $instance['count'] ) ) { $args['count'] = $instance['count']; } 85 | if ( isset( $instance['hierarchical'] ) ) { $args['hierarchical'] = $instance['hierarchical']; } 86 | 87 | echo $before_widget; 88 | 89 | if ( $title ) { 90 | echo $before_title . $title . $after_title; 91 | } 92 | 93 | // Display the project categories 94 | $project_taxonomies = get_object_taxonomies( 'project' ); 95 | 96 | if ( count( $project_taxonomies ) > 0) { 97 | foreach ( $project_taxonomies as $project_tax ) { 98 | $args = array( 99 | 'orderby' => 'name', 100 | 'show_count' => $instance['count'], 101 | 'pad_counts' => 0, 102 | 'hierarchical' => $instance['hierarchical'], 103 | 'taxonomy' => $project_tax, 104 | 'title_li' => '', 105 | ); 106 | 107 | echo ''; 112 | } 113 | } 114 | 115 | echo $after_widget; 116 | 117 | // Add actions for plugins/themes to hook onto. 118 | do_action( $this->projects_widget_cssclass . '_bottom' ); 119 | 120 | } // End widget() 121 | 122 | /** 123 | * Method to update the settings from the form() method. 124 | * @since 1.0.0 125 | * @param array $new_instance New settings. 126 | * @param array $old_instance Previous settings. 127 | * @return array Updated settings. 128 | */ 129 | public function update ( $new_instance, $old_instance ) { 130 | $instance = $old_instance; 131 | 132 | /* Strip tags for title and name to remove HTML (important for text inputs). */ 133 | $instance['title'] = strip_tags( $new_instance['title'] ); 134 | 135 | /* Escape checkbox values */ 136 | $instance['count'] = esc_attr( $new_instance['count'] ); 137 | $instance['hierarchical'] = esc_attr( $new_instance['hierarchical'] ); 138 | 139 | return $instance; 140 | } // End update() 141 | 142 | /** 143 | * The form on the widget control in the widget administration area. 144 | * Make use of the get_field_id() and get_field_name() function when creating your form elements. This handles the confusing stuff. 145 | * @since 1.0.0 146 | * @param array $instance The settings for this instance. 147 | * @return void 148 | */ 149 | public function form( $instance ) { 150 | 151 | /* Set up some default widget settings. */ 152 | /* Make sure all keys are added here, even with empty string values. */ 153 | $defaults = array( 154 | 'title' => __( 'Project Categories', 'projects-by-woothemes' ), 155 | 'count' => 1, 156 | 'hierarchical' => 1, 157 | ); 158 | 159 | $instance = wp_parse_args( (array) $instance, $defaults ); 160 | ?> 161 | 162 |

    163 | 164 | 165 |

    166 | 167 | 168 |

    169 | /> 170 | 171 |

    172 | 173 | 174 |

    175 | /> 176 | 177 |

    178 | projects_widget_cssclass = 'widget_projects_items'; 41 | $this->projects_widget_description = __( 'Recent projects listed on your site.', 'projects-by-woothemes' ); 42 | $this->projects_widget_idbase = 'projects'; 43 | $this->projects_widget_title = __( 'Recent Projects', 'projects-by-woothemes' ); 44 | 45 | // Cache 46 | add_action( 'save_post', array($this, 'flush_widget_cache') ); 47 | add_action( 'deleted_post', array($this, 'flush_widget_cache') ); 48 | add_action( 'switch_theme', array($this, 'flush_widget_cache') ); 49 | 50 | /* Widget settings. */ 51 | $widget_ops = array( 52 | 'classname' => $this->projects_widget_cssclass, 53 | 'description' => $this->projects_widget_description 54 | ); 55 | 56 | /* Widget control settings. */ 57 | $control_ops = array( 58 | 'id_base' => $this->projects_widget_idbase 59 | ); 60 | 61 | /* Create the widget. */ 62 | parent::__construct( $this->projects_widget_idbase, $this->projects_widget_title, $widget_ops, $control_ops ); 63 | } // End __construct() 64 | 65 | /** 66 | * Display the widget on the frontend. 67 | * @since 1.0.0 68 | * @param array $args Widget arguments. 69 | * @param array $instance Widget settings for this instance. 70 | * @return void 71 | */ 72 | public function widget( $args, $instance ) { 73 | 74 | $cache = wp_cache_get( 'widget_projects_items', 'widget' ); 75 | 76 | if ( !is_array($cache) ) 77 | $cache = array(); 78 | 79 | if ( ! isset( $args['widget_id'] ) ) 80 | $args['widget_id'] = $this->id; 81 | 82 | if ( isset( $cache[ $args['widget_id'] ] ) ) { 83 | echo $cache[ $args['widget_id'] ]; 84 | return; 85 | } 86 | 87 | ob_start(); 88 | 89 | extract( $args, EXTR_SKIP ); 90 | 91 | /* Our variables from the widget settings. */ 92 | $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ); 93 | 94 | $args = array(); 95 | 96 | /* Display the widget title if one was input (before and after defined by themes). */ 97 | if ( $title ) { $args['title'] = $title; } 98 | 99 | /* Widget content. */ 100 | // Add actions for plugins/themes to hook onto. 101 | do_action( $this->projects_widget_cssclass . '_top' ); 102 | 103 | // Integer values. 104 | if ( isset( $instance['limit'] ) && ( 0 < count( $instance['limit'] ) ) ) { $args['limit'] = intval( $instance['limit'] ); } 105 | 106 | // Display the projects. 107 | 108 | $args = array( 109 | 'post_type' => 'project', 110 | 'post_status' => 'publish', 111 | 'ignore_sticky_posts' => 1, 112 | 'posts_per_page' => $args['limit'], 113 | 'orderby' => 'date', 114 | 'order' => 'DESC' 115 | ); 116 | 117 | $r = new WP_Query( $args ); 118 | 119 | if ( $r->have_posts() ) { 120 | 121 | echo $before_widget; 122 | 123 | if ( $title ) 124 | echo $before_title . $title . $after_title; 125 | 126 | echo ''; 134 | 135 | echo $after_widget; 136 | 137 | wp_reset_postdata(); 138 | } 139 | 140 | // Add actions for plugins/themes to hook onto. 141 | do_action( $this->projects_widget_cssclass . '_bottom' ); 142 | 143 | $cache[ $widget_id ] = ob_get_flush(); 144 | 145 | wp_cache_set('widget_projects_items', $cache, 'widget'); 146 | 147 | } // End widget() 148 | 149 | /** 150 | * Method to update the settings from the form() method. 151 | * @since 1.0.0 152 | * @param array $new_instance New settings. 153 | * @param array $old_instance Previous settings. 154 | * @return array Updated settings. 155 | */ 156 | public function update ( $new_instance, $old_instance ) { 157 | $instance = $old_instance; 158 | 159 | /* Strip tags for title and name to remove HTML (important for text inputs). */ 160 | $instance['title'] = strip_tags( $new_instance['title'] ); 161 | 162 | /* Make sure the integer values are definitely integers. */ 163 | $instance['limit'] = intval( $new_instance['limit'] ); 164 | 165 | /* Flush cache. */ 166 | $this->flush_widget_cache(); 167 | $alloptions = wp_cache_get( 'alloptions', 'options' ); 168 | if ( isset($alloptions['widget_projects_items']) ) 169 | delete_option('widget_projects_items'); 170 | 171 | return $instance; 172 | } // End update() 173 | 174 | /** 175 | * The form on the widget control in the widget administration area. 176 | * Make use of the get_field_id() and get_field_name() function when creating your form elements. This handles the confusing stuff. 177 | * @since 1.0.0 178 | * @param array $instance The settings for this instance. 179 | * @return void 180 | */ 181 | public function form( $instance ) { 182 | 183 | /* Set up some default widget settings. */ 184 | /* Make sure all keys are added here, even with empty string values. */ 185 | $defaults = array( 186 | 'title' => __( 'Recent Projects', 'projects-by-woothemes' ), 187 | 'limit' => 5, 188 | ); 189 | 190 | $instance = wp_parse_args( (array) $instance, $defaults ); 191 | ?> 192 | 193 |

    194 | 195 | 196 |

    197 | 198 |

    199 | 200 | 201 |

    202 | \n" 13 | "Language-Team: LANGUAGE \n" 14 | 15 | #: classes/class-projects-admin.php:175 16 | msgid "Cover Image" 17 | msgstr "" 18 | 19 | #: classes/class-projects-admin.php:209 20 | msgid "%s updated. View %s%s%s" 21 | msgstr "" 22 | 23 | #: classes/class-projects-admin.php:210 24 | msgid "Custom field updated." 25 | msgstr "" 26 | 27 | #: classes/class-projects-admin.php:211 28 | msgid "Custom field deleted." 29 | msgstr "" 30 | 31 | #: classes/class-projects-admin.php:212 32 | msgid "%s updated." 33 | msgstr "" 34 | 35 | #. translators: %s: date and time of the revision 36 | 37 | #: classes/class-projects-admin.php:214 38 | msgid "%s restored to revision from %s" 39 | msgstr "" 40 | 41 | #: classes/class-projects-admin.php:215 42 | msgid "%s published. View %s%s%s" 43 | msgstr "" 44 | 45 | #: classes/class-projects-admin.php:216 46 | msgid "%s saved." 47 | msgstr "" 48 | 49 | #: classes/class-projects-admin.php:217 50 | msgid "%s submitted. Preview %s%s%s" 51 | msgstr "" 52 | 53 | #: classes/class-projects-admin.php:218 54 | msgid "%s scheduled for: %s. Preview %s" 55 | msgstr "" 56 | 57 | #. translators: Publish box date format, see http:php.net/date 58 | 59 | #: classes/class-projects-admin.php:220 60 | msgid "M j, Y @ G:i" 61 | msgstr "" 62 | 63 | #: classes/class-projects-admin.php:221 64 | msgid "%s draft updated. Preview %s%s%s" 65 | msgstr "" 66 | 67 | #: classes/class-projects-admin.php:238 68 | msgid "%s Short Description" 69 | msgstr "" 70 | 71 | #: classes/class-projects-admin.php:241 72 | msgid "%s Details" 73 | msgstr "" 74 | 75 | #: classes/class-projects-admin.php:244 76 | msgid "%s Gallery" 77 | msgstr "" 78 | 79 | #: classes/class-projects-admin.php:429 classes/class-projects-admin.php:581 80 | msgid "Delete image" 81 | msgstr "" 82 | 83 | #: classes/class-projects-admin.php:430 84 | msgid "Edit image" 85 | msgstr "" 86 | 87 | #: classes/class-projects-admin.php:441 88 | msgid "Add %s gallery images" 89 | msgstr "" 90 | 91 | #: classes/class-projects-admin.php:527 templates/single-project/meta.php:43 92 | msgid "Client" 93 | msgstr "" 94 | 95 | #: classes/class-projects-admin.php:528 96 | msgid "Enter the client name. (Optional)" 97 | msgstr "" 98 | 99 | #: classes/class-projects-admin.php:535 100 | msgid "URL" 101 | msgstr "" 102 | 103 | #: classes/class-projects-admin.php:536 104 | msgid "Enter the project URL. (Optional)" 105 | msgstr "" 106 | 107 | #: classes/class-projects-admin.php:556 108 | msgid "Enter the %s title here" 109 | msgstr "" 110 | 111 | #: classes/class-projects-admin.php:579 112 | msgid "Add Images to Project Gallery" 113 | msgstr "" 114 | 115 | #: classes/class-projects-admin.php:580 116 | msgid "Add to gallery" 117 | msgstr "" 118 | 119 | #: classes/class-projects-admin.php:582 120 | msgid "Upload" 121 | msgstr "" 122 | 123 | #: classes/class-projects-admin.php:583 124 | msgid "Select this" 125 | msgstr "" 126 | 127 | #: classes/class-projects-admin.php:603 128 | msgid "%sProjects by WooThemes is almost ready.%s To get started, %sconfigure your projects page%s." 129 | msgstr "" 130 | 131 | #: classes/class-projects-admin.php:617 132 | msgid "%s Cover Image" 133 | msgstr "" 134 | 135 | #: classes/class-projects-admin.php:630 136 | msgid "Set featured image" 137 | msgstr "" 138 | 139 | #: classes/class-projects-admin.php:630 classes/class-projects-admin.php:662 140 | msgid "Set cover image" 141 | msgstr "" 142 | 143 | #: classes/class-projects-admin.php:646 144 | msgid "Remove featured image" 145 | msgstr "" 146 | 147 | #: classes/class-projects-admin.php:646 148 | msgid "Remove cover image" 149 | msgstr "" 150 | 151 | #: classes/class-projects-admin.php:661 152 | msgid "Set Cover Image" 153 | msgstr "" 154 | 155 | #: classes/class-projects-integrations.php:165 156 | msgid "Testimonial" 157 | msgstr "" 158 | 159 | #: classes/class-projects-integrations.php:166 160 | msgid "Search for Testimonial to link to this Project. (Optional)" 161 | msgstr "" 162 | 163 | #: classes/class-projects-integrations.php:173 164 | msgid "Testimonial ID" 165 | msgstr "" 166 | 167 | #: classes/class-projects-integrations.php:174 168 | msgid "Holds the id of the selected testimonial." 169 | msgstr "" 170 | 171 | #: classes/class-projects-integrations.php:320 172 | msgid "Product" 173 | msgstr "" 174 | 175 | #: classes/class-projects-integrations.php:321 176 | msgid "Search for Product to link to this Project. (Optional)" 177 | msgstr "" 178 | 179 | #: classes/class-projects-integrations.php:328 180 | msgid "Product ID" 181 | msgstr "" 182 | 183 | #: classes/class-projects-integrations.php:329 184 | msgid "Holds the id of the selected product." 185 | msgstr "" 186 | 187 | #: classes/class-projects-settings.php:31 188 | msgid "Settings" 189 | msgstr "" 190 | 191 | #: classes/class-projects-settings.php:43 192 | msgid "Pages" 193 | msgstr "" 194 | 195 | #: classes/class-projects-settings.php:44 196 | msgid "Images" 197 | msgstr "" 198 | 199 | #: classes/class-projects-settings.php:60 200 | msgid "Projects Settings" 201 | msgstr "" 202 | 203 | #: classes/class-projects-settings.php:82 204 | msgid "Save Changes" 205 | msgstr "" 206 | 207 | #: classes/class-projects-settings.php:111 208 | msgid "Configure projects pages." 209 | msgstr "" 210 | 211 | #: classes/class-projects-settings.php:124 212 | msgid "Projects Page" 213 | msgstr "" 214 | 215 | #: classes/class-projects-settings.php:128 216 | msgid "The base page of your projects. This is your projects archive." 217 | msgstr "" 218 | 219 | #: classes/class-projects-settings.php:138 220 | msgid "These settings control the dimensions of thumbnails in your projects. After updating these settings you may need to" 221 | msgstr "" 222 | 223 | #: classes/class-projects-settings.php:138 224 | msgid "regenerate your thumbnails" 225 | msgstr "" 226 | 227 | #: classes/class-projects-settings.php:168 228 | msgid "Archive Images" 229 | msgstr "" 230 | 231 | #: classes/class-projects-settings.php:172 232 | #: classes/class-projects-settings.php:181 233 | #: classes/class-projects-settings.php:190 234 | msgid "Width:" 235 | msgstr "" 236 | 237 | #: classes/class-projects-settings.php:172 238 | #: classes/class-projects-settings.php:181 239 | #: classes/class-projects-settings.php:190 240 | msgid "Height:" 241 | msgstr "" 242 | 243 | #: classes/class-projects-settings.php:172 244 | #: classes/class-projects-settings.php:181 245 | #: classes/class-projects-settings.php:190 246 | msgid "Crop:" 247 | msgstr "" 248 | 249 | #: classes/class-projects-settings.php:177 250 | msgid "Single Images" 251 | msgstr "" 252 | 253 | #: classes/class-projects-settings.php:186 254 | msgid "Thumbnails" 255 | msgstr "" 256 | 257 | #: classes/class-projects-taxonomy.php:71 258 | msgid "Category" 259 | msgstr "" 260 | 261 | #: classes/class-projects-taxonomy.php:72 templates/single-project/meta.php:31 262 | msgid "Categories" 263 | msgstr "" 264 | 265 | #: classes/class-projects-taxonomy.php:105 266 | msgctxt "taxonomy general name" 267 | msgid "Project %s" 268 | msgstr "" 269 | 270 | #: classes/class-projects-taxonomy.php:106 271 | msgctxt "taxonomy singular name" 272 | msgid "%s" 273 | msgstr "" 274 | 275 | #: classes/class-projects-taxonomy.php:107 276 | msgid "Search %s" 277 | msgstr "" 278 | 279 | #: classes/class-projects-taxonomy.php:108 280 | msgid "All %s" 281 | msgstr "" 282 | 283 | #: classes/class-projects-taxonomy.php:109 284 | msgid "Parent %s" 285 | msgstr "" 286 | 287 | #: classes/class-projects-taxonomy.php:110 288 | msgid "Parent %s:" 289 | msgstr "" 290 | 291 | #: classes/class-projects-taxonomy.php:111 projects.php:149 292 | msgid "Edit %s" 293 | msgstr "" 294 | 295 | #: classes/class-projects-taxonomy.php:112 296 | msgid "Update %s" 297 | msgstr "" 298 | 299 | #: classes/class-projects-taxonomy.php:113 projects.php:148 300 | msgid "Add New %s" 301 | msgstr "" 302 | 303 | #: classes/class-projects-taxonomy.php:114 304 | msgid "New %s Name" 305 | msgstr "" 306 | 307 | #: classes/class-projects-taxonomy.php:115 308 | msgid "%s" 309 | msgstr "" 310 | 311 | #: classes/class-widget-project-categories.php:42 312 | #: classes/class-widget-project-categories.php:44 313 | #: classes/class-widget-project-categories.php:154 314 | msgid "Project Categories" 315 | msgstr "" 316 | 317 | #: classes/class-widget-project-categories.php:163 318 | #: classes/class-widget-projects.php:194 319 | msgid "Title (optional):" 320 | msgstr "" 321 | 322 | #: classes/class-widget-project-categories.php:170 323 | msgid "Show Count:" 324 | msgstr "" 325 | 326 | #: classes/class-widget-project-categories.php:176 327 | msgid "Show Hierarchy:" 328 | msgstr "" 329 | 330 | #: classes/class-widget-projects.php:41 331 | msgid "Recent projects listed on your site." 332 | msgstr "" 333 | 334 | #: classes/class-widget-projects.php:43 classes/class-widget-projects.php:186 335 | msgid "Recent Projects" 336 | msgstr "" 337 | 338 | #: classes/class-widget-projects.php:199 339 | msgid "Limit:" 340 | msgstr "" 341 | 342 | #: projects-core-functions.php:254 343 | msgctxt "slug" 344 | msgid "uncategorized" 345 | msgstr "" 346 | 347 | #: projects-template.php:140 348 | msgid "Search Results: “%s”" 349 | msgstr "" 350 | 351 | #: projects-template.php:143 352 | msgid " – Page %s" 353 | msgstr "" 354 | 355 | #: projects-template.php:565 356 | msgid "Purchase" 357 | msgstr "" 358 | 359 | #: projects.php:132 360 | msgctxt "post type singular name" 361 | msgid "Project" 362 | msgstr "" 363 | 364 | #: projects.php:133 365 | msgctxt "post type general name" 366 | msgid "Projects" 367 | msgstr "" 368 | 369 | #: projects.php:150 370 | msgid "New %s" 371 | msgstr "" 372 | 373 | #: projects.php:152 374 | msgid "View %s" 375 | msgstr "" 376 | 377 | #: projects.php:153 378 | msgid "Search %a" 379 | msgstr "" 380 | 381 | #: projects.php:154 382 | msgid "No %s Found" 383 | msgstr "" 384 | 385 | #: projects.php:155 386 | msgid "No %s Found In Trash" 387 | msgstr "" 388 | 389 | #: templates/loop/no-projects-found.php:14 390 | msgid "No projects found which match your selection." 391 | msgstr "" 392 | 393 | #: templates/single-project/meta.php:53 394 | msgid "Link" 395 | msgstr "" 396 | 397 | #: templates/single-project/meta.php:54 398 | msgid "Visit project" 399 | msgstr "" 400 | #. Plugin Name of the plugin/theme 401 | msgid "Projects" 402 | msgstr "" 403 | 404 | #. Plugin URI of the plugin/theme 405 | msgid "http://woothemes.com/" 406 | msgstr "" 407 | 408 | #. Description of the plugin/theme 409 | msgid "Hi, I'm your project showcase plugin for WordPress. Show off your recent work using our shortcode, widget or template tag." 410 | msgstr "" 411 | 412 | #. Author of the plugin/theme 413 | msgid "WooThemes" 414 | msgstr "" 415 | 416 | #. Author URI of the plugin/theme 417 | msgid "http://woothemes.com/" 418 | msgstr "" 419 | -------------------------------------------------------------------------------- /projects-core-functions.php: -------------------------------------------------------------------------------- 1 | tag. 42 | */ 43 | function projects_get_image ( $id, $size = 'projects-thumbnail' ) { 44 | $response = ''; 45 | 46 | if ( has_post_thumbnail( $id ) ) { 47 | // If not a string or an array, and not an integer, default to 150x9999. 48 | if ( is_int( $size ) || ( 0 < intval( $size ) ) ) { 49 | $size = array( intval( $size ), intval( $size ) ); 50 | } elseif ( ! is_string( $size ) && ! is_array( $size ) ) { 51 | $size = array( 150, 9999 ); 52 | } 53 | $response = get_the_post_thumbnail( intval( $id ), $size ); 54 | } 55 | 56 | return $response; 57 | } // End projects_get_image() 58 | 59 | } 60 | 61 | /** 62 | * is_projects - Returns true if on a page which uses WooThemes Projects templates 63 | * 64 | * @access public 65 | * @return bool 66 | */ 67 | function is_projects () { 68 | return ( is_projects_archive() || is_project_category() || is_project() ) ? true : false; 69 | } // End is_projects() 70 | 71 | if ( ! function_exists( 'is_projects_archive' ) ) { 72 | 73 | /** 74 | * is_projects_archive - Returns true when viewing the project type archive. 75 | * 76 | * @access public 77 | * @return bool 78 | */ 79 | function is_projects_archive() { 80 | return ( is_post_type_archive( 'project' ) || is_project_taxonomy() || is_page( projects_get_page_id( 'projects' ) ) ) ? true : false; 81 | } // End is_projects_archive() 82 | } 83 | 84 | if ( ! function_exists( 'is_project_taxonomy' ) ) { 85 | 86 | /** 87 | * is_project_taxonomy - Returns true when viewing a project taxonomy archive. 88 | * 89 | * @access public 90 | * @return bool 91 | */ 92 | function is_project_taxonomy() { 93 | return is_tax( get_object_taxonomies( 'project' ) ); 94 | } // End is_project_taxonomy() 95 | } 96 | 97 | if ( ! function_exists( 'is_project_category' ) ) { 98 | 99 | /** 100 | * is_project_category - Returns true when viewing a project category. 101 | * 102 | * @access public 103 | * @param string $term (default: '') The term slug your checking for. Leave blank to return true on any. 104 | * @return bool 105 | */ 106 | function is_project_category( $term = '' ) { 107 | return is_tax( 'project-category', $term ); 108 | } // End is_project_category() 109 | } 110 | 111 | if ( ! function_exists( 'is_project' ) ) { 112 | 113 | /** 114 | * is_project - Returns true when viewing a single project. 115 | * 116 | * @access public 117 | * @return bool 118 | */ 119 | function is_project() { 120 | return is_singular( array( 'project' ) ); 121 | } // End is_project() 122 | } 123 | 124 | if ( ! function_exists( 'is_ajax' ) ) { 125 | 126 | /** 127 | * is_ajax - Returns true when the page is loaded via ajax. 128 | * 129 | * @access public 130 | * @return bool 131 | */ 132 | function is_ajax() { 133 | if ( defined('DOING_AJAX') ) 134 | return true; 135 | 136 | return ( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) == 'xmlhttprequest' ) ? true : false; 137 | } 138 | } 139 | 140 | /** 141 | * Get template part (for templates like the projects-loop). 142 | * 143 | * @access public 144 | * @param mixed $slug 145 | * @param string $name (default: '') 146 | * @return void 147 | */ 148 | function projects_get_template_part( $slug, $name = '' ) { 149 | global $projects; 150 | $template = ''; 151 | 152 | // Look in yourtheme/slug-name.php and yourtheme/projects/slug-name.php 153 | if ( $name ) 154 | $template = locate_template( array ( "{$slug}-{$name}.php", "{$projects->template_url}{$slug}-{$name}.php" ) ); 155 | 156 | // Get default slug-name.php 157 | if ( !$template && $name && file_exists( $projects->plugin_path() . "/templates/{$slug}-{$name}.php" ) ) 158 | $template = $projects->plugin_path() . "/templates/{$slug}-{$name}.php"; 159 | 160 | // If template file doesn't exist, look in yourtheme/slug.php and yourtheme/projects/slug.php 161 | if ( !$template ) 162 | $template = locate_template( array ( "{$slug}.php", "{$projects->template_url}{$slug}.php" ) ); 163 | 164 | if ( $template ) 165 | load_template( $template, false ); 166 | } // End projects_get_template_part() 167 | 168 | 169 | /** 170 | * Get other templates and including the file. 171 | * 172 | * @access public 173 | * @param mixed $template_name 174 | * @param array $args (default: array()) 175 | * @param string $template_path (default: '') 176 | * @param string $default_path (default: '') 177 | * @return void 178 | */ 179 | function projects_get_template ( $template_name, $args = array(), $template_path = '', $default_path = '' ) { 180 | global $projects; 181 | 182 | if ( $args && is_array($args) ) 183 | extract( $args ); 184 | 185 | $located = projects_locate_template( $template_name, $template_path, $default_path ); 186 | 187 | do_action( 'projects_before_template_part', $template_name, $template_path, $located, $args ); 188 | 189 | include( $located ); 190 | 191 | do_action( 'projects_after_template_part', $template_name, $template_path, $located, $args ); 192 | } // End projects_get_template() 193 | 194 | 195 | /** 196 | * Locate a template and return the path for inclusion. 197 | * 198 | * This is the load order: 199 | * 200 | * yourtheme / $template_path / $template_name 201 | * yourtheme / $template_name 202 | * $default_path / $template_name 203 | * 204 | * @access public 205 | * @param mixed $template_name 206 | * @param string $template_path (default: '') 207 | * @param string $default_path (default: '') 208 | * @return string 209 | */ 210 | function projects_locate_template( $template_name, $template_path = '', $default_path = '' ) { 211 | global $projects; 212 | 213 | if ( ! $template_path ) $template_path = $projects->template_url; 214 | if ( ! $default_path ) $default_path = $projects->plugin_path() . '/templates/'; 215 | 216 | // Look within passed path within the theme - this is priority 217 | $template = locate_template( 218 | array( 219 | trailingslashit( $template_path ) . $template_name, 220 | $template_name 221 | ) 222 | ); 223 | 224 | // Get default template 225 | if ( ! $template ) 226 | $template = $default_path . $template_name; 227 | 228 | // Return what we found 229 | return apply_filters( 'projects_locate_template', $template, $template_name, $template_path ); 230 | } // End projects_locate_template() 231 | 232 | /** 233 | * Filter to allow project-category in the permalinks for projects. 234 | * 235 | * @access public 236 | * @param string $permalink The existing permalink URL. 237 | * @param object $post 238 | * @return string 239 | */ 240 | function projects_project_post_type_link( $permalink, $post ) { 241 | // Abort if post is not a project 242 | if ( $post->post_type !== 'project' ) 243 | return $permalink; 244 | 245 | // Abort early if the placeholder rewrite tag isn't in the generated URL 246 | if ( false === strpos( $permalink, '%' ) ) 247 | return $permalink; 248 | 249 | // Get the custom taxonomy terms in use by this post 250 | $terms = get_the_terms( $post->ID, 'project-category' ); 251 | 252 | if ( empty( $terms ) ) { 253 | // If no terms are assigned to this post, use a string instead (can't leave the placeholder there) 254 | $project_cat = _x( 'uncategorized', 'slug', 'projects-by-woothemes' ); 255 | } else { 256 | // Replace the placeholder rewrite tag with the first term's slug 257 | $first_term = array_shift( $terms ); 258 | $project_cat = $first_term->slug; 259 | } 260 | 261 | $find = array( 262 | '%year%', 263 | '%monthnum%', 264 | '%day%', 265 | '%hour%', 266 | '%minute%', 267 | '%second%', 268 | '%post_id%', 269 | '%category%', 270 | '%project_category%' 271 | ); 272 | 273 | $replace = array( 274 | date_i18n( 'Y', strtotime( $post->post_date ) ), 275 | date_i18n( 'm', strtotime( $post->post_date ) ), 276 | date_i18n( 'd', strtotime( $post->post_date ) ), 277 | date_i18n( 'H', strtotime( $post->post_date ) ), 278 | date_i18n( 'i', strtotime( $post->post_date ) ), 279 | date_i18n( 's', strtotime( $post->post_date ) ), 280 | $post->ID, 281 | $project_cat, 282 | $project_cat 283 | ); 284 | 285 | $replace = array_map( 'sanitize_title', $replace ); 286 | 287 | $permalink = str_replace( $find, $replace, $permalink ); 288 | 289 | return $permalink; 290 | } // End projects_project_post_type_link() 291 | 292 | add_filter( 'post_type_link', 'projects_project_post_type_link', 10, 2 ); 293 | 294 | /** 295 | * projects_get_gallery_attachment_ids function. 296 | * 297 | * @access public 298 | * @return array 299 | */ 300 | function projects_get_gallery_attachment_ids ( $post_id = 0 ) { 301 | global $post; 302 | if ( 0 == $post_id ) $post_id = get_the_ID(); 303 | $project_image_gallery = get_post_meta( $post_id, '_project_image_gallery', true ); 304 | if ( '' == $project_image_gallery ) { 305 | // Backwards compat 306 | $attachment_ids = get_posts( 'post_parent=' . intval( $post_id ) . '&numberposts=-1&post_type=attachment&orderby=menu_order&order=ASC&post_mime_type=image&fields=ids' ); 307 | $attachment_ids = array_diff( $attachment_ids, array( get_post_thumbnail_id() ) ); 308 | $project_image_gallery = implode( ',', $attachment_ids ); 309 | } 310 | return array_filter( (array) explode( ',', $project_image_gallery ) ); 311 | } // End projects_get_gallery_attachment_ids() 312 | 313 | 314 | /** 315 | * Add body classes for Projects pages 316 | * 317 | * @param array $classes 318 | * @return array 319 | */ 320 | function woo_projects_body_class( $classes ) { 321 | $classes = (array) $classes; 322 | 323 | if ( is_projects() ) { 324 | $classes[] = 'projects'; 325 | $classes[] = 'projects-page'; 326 | } 327 | 328 | if ( is_project() ) { 329 | 330 | $attachments = count( projects_get_gallery_attachment_ids() ); 331 | 332 | if ( $attachments > 0 ) { 333 | $classes[] = 'has-gallery'; 334 | } else { 335 | $classes[] = 'no-gallery'; 336 | } 337 | 338 | if ( !has_post_thumbnail() ) { 339 | $classes[] = 'no-cover-image'; 340 | } 341 | 342 | } 343 | 344 | return array_unique( $classes ); 345 | } 346 | 347 | 348 | /** 349 | * Find a category image. 350 | * @since 1.0.0 351 | * @return string 352 | */ 353 | function projects_category_image ( $cat_id = 0 ) { 354 | 355 | global $post; 356 | 357 | if ( 0 == $cat_id ) return; 358 | 359 | $image = ''; 360 | 361 | if ( false === ( $image = get_transient( 'projects_category_image_' . $cat_id ) ) ) { 362 | 363 | $cat = get_term( $cat_id, 'project-category' ); 364 | 365 | $query_args = array( 366 | 'post_type' => 'project', 367 | 'posts_per_page' => -1, 368 | 'no_found_rows' => 1, 369 | 'tax_query' => array( 370 | array( 371 | 'taxonomy' => 'project-category', 372 | 'field' => 'id', 373 | 'terms' => array( $cat->term_id ) 374 | ) 375 | ) 376 | ); 377 | 378 | $query = new WP_Query( $query_args ); 379 | 380 | while ( $query->have_posts() && $image == '' ) : $query->the_post(); 381 | 382 | $image = projects_get_image( get_the_ID() ); 383 | 384 | if ( $image ) { 385 | $image = '' . $image . ''; 386 | set_transient( 'projects_category_image_' . $cat->term_id, $image, 60 * 60 ); // 1 Hour. 387 | } 388 | 389 | endwhile; 390 | 391 | wp_reset_postdata(); 392 | 393 | } // get transient 394 | 395 | return $image; 396 | 397 | } // End projects_category_image() 398 | 399 | /** 400 | * When a post is saved, flush the transient used to store the category images. 401 | * @since 1.0.0 402 | * @return void 403 | */ 404 | function projects_category_image_flush_transient ( $post_id ) { 405 | if ( get_post_type( $post_id ) != 'project' ) return; // we only want projects 406 | $categories = get_the_terms( $post_id, 'project-category' ); 407 | if ( $categories ) { 408 | foreach ($categories as $category ) { 409 | delete_transient( 'projects_category_image_' . $category->term_id ); 410 | } 411 | } 412 | } // End projects_category_image_flush_transient() 413 | add_action( 'save_post', 'projects_category_image_flush_transient' ); 414 | 415 | /** 416 | * Enqueue styles 417 | */ 418 | function projects_script() { 419 | 420 | // Register projects CSS 421 | wp_register_style( 'projects-styles', plugins_url( '/assets/css/woo-projects.css', __FILE__ ), array(), PROJECTS_VERSION ); 422 | wp_register_style( 'projects-handheld', plugins_url( '/assets/css/woo-projects-handheld.css', __FILE__ ), array(), PROJECTS_VERSION ); 423 | 424 | if ( apply_filters( 'projects_enqueue_styles', true ) ) { 425 | 426 | // Load Main styles 427 | wp_enqueue_style( 'projects-styles' ); 428 | 429 | // Load styles applied to handheld devices 430 | wp_enqueue_style( 'projects-handheld' ); 431 | 432 | // Load Dashicons 433 | if ( is_project() ) { 434 | wp_enqueue_style( 'dashicons' ); 435 | } 436 | } 437 | 438 | } -------------------------------------------------------------------------------- /projects-hooks.php: -------------------------------------------------------------------------------- 1 | $menu_item ) { 51 | 52 | $classes = (array) $menu_item->classes; 53 | 54 | // Unset active class for blog page 55 | if ( $page_for_posts == $menu_item->object_id ) { 56 | $menu_items[$key]->current = false; 57 | 58 | if ( in_array( 'current_page_parent', $classes ) ) 59 | unset( $classes[ array_search('current_page_parent', $classes) ] ); 60 | 61 | if ( in_array( 'current-menu-item', $classes ) ) 62 | unset( $classes[ array_search('current-menu-item', $classes) ] ); 63 | 64 | // Set active state if this is the shop page link 65 | } elseif ( is_projects() && $projects_page == $menu_item->object_id ) { 66 | $menu_items[$key]->current = true; 67 | $classes[] = 'current-menu-item'; 68 | $classes[] = 'current_page_item'; 69 | 70 | // Set parent state if this is a product page 71 | } elseif ( is_singular( 'project' ) && $projects_page == $menu_item->object_id ) { 72 | $classes[] = 'current_page_parent'; 73 | } 74 | 75 | $menu_items[$key]->classes = array_unique( $classes ); 76 | 77 | } 78 | 79 | return $menu_items; 80 | } 81 | 82 | if ( ! function_exists( 'projects_output_content_wrapper' ) ) { 83 | 84 | /** 85 | * Output the start of the page wrapper. 86 | * 87 | * Hooked into projects_before_main_content 88 | * 89 | * @access public 90 | * @return void 91 | */ 92 | function projects_output_content_wrapper() { 93 | projects_get_template( 'layout/wrapper-start.php' ); 94 | } 95 | } 96 | 97 | if ( ! function_exists( 'projects_output_content_wrapper_end' ) ) { 98 | 99 | /** 100 | * Output the end of the page wrapper. 101 | * 102 | * Hooked into projects_after_main_content 103 | * 104 | * @access public 105 | * @return void 106 | */ 107 | function projects_output_content_wrapper_end() { 108 | projects_get_template( 'layout/wrapper-end.php' ); 109 | } 110 | } 111 | 112 | if ( ! function_exists( 'projects_get_sidebar' ) ) { 113 | 114 | /** 115 | * Get the projects sidebar template. 116 | * 117 | * Hooked into projects_sidebar 118 | * 119 | * @access public 120 | * @return void 121 | */ 122 | function projects_get_sidebar() { 123 | projects_get_template( 'layout/sidebar.php' ); 124 | } 125 | } 126 | 127 | /** Loop ******************************************************************/ 128 | 129 | if ( ! function_exists( 'projects_page_title' ) ) { 130 | 131 | /** 132 | * projects_page_title function. 133 | * 134 | * @access public 135 | * @return void 136 | */ 137 | function projects_page_title() { 138 | 139 | if ( is_search() ) { 140 | $page_title = sprintf( __( 'Search Results: “%s”', 'projects-by-woothemes' ), get_search_query() ); 141 | 142 | if ( get_query_var( 'paged' ) ) 143 | $page_title .= sprintf( __( ' – Page %s', 'projects-by-woothemes' ), get_query_var( 'paged' ) ); 144 | 145 | } elseif ( is_tax() ) { 146 | 147 | $page_title = single_term_title( '', false ); 148 | 149 | } else { 150 | 151 | $projects_page_id = projects_get_page_id( 'projects' ); 152 | $page_title = get_the_title( $projects_page_id ); 153 | 154 | } 155 | 156 | echo apply_filters( 'projects_page_title', $page_title ); 157 | } 158 | } 159 | 160 | if ( ! function_exists( 'projects_project_loop_start' ) ) { 161 | 162 | /** 163 | * Output the start of a project loop. By default this is a UL 164 | * 165 | * @access public 166 | * @return void 167 | */ 168 | function projects_project_loop_start( $echo = true ) { 169 | ob_start(); 170 | projects_get_template( 'loop/loop-start.php' ); 171 | if ( $echo ) 172 | echo ob_get_clean(); 173 | else 174 | return ob_get_clean(); 175 | } 176 | } 177 | if ( ! function_exists( 'projects_project_loop_end' ) ) { 178 | 179 | /** 180 | * Output the end of a project loop. By default this is a UL 181 | * 182 | * @access public 183 | * @return void 184 | */ 185 | function projects_project_loop_end( $echo = true ) { 186 | ob_start(); 187 | 188 | projects_get_template( 'loop/loop-end.php' ); 189 | 190 | if ( $echo ) 191 | echo ob_get_clean(); 192 | else 193 | return ob_get_clean(); 194 | } 195 | } 196 | if ( ! function_exists( 'projects_taxonomy_archive_description' ) ) { 197 | 198 | /** 199 | * Show an archive description on taxonomy archives 200 | * 201 | * Hooked into projects_archive_description 202 | * 203 | * @access public 204 | * @subpackage Archives 205 | * @return void 206 | */ 207 | function projects_taxonomy_archive_description() { 208 | if ( is_tax( array( 'project-category', 'project-tag' ) ) && get_query_var( 'paged' ) == 0 ) { 209 | $description = apply_filters( 'the_content', term_description() ); 210 | if ( $description ) { 211 | echo '
    ' . $description . '
    '; 212 | } 213 | } 214 | } 215 | } 216 | if ( ! function_exists( 'projects_project_archive_description' ) ) { 217 | 218 | /** 219 | * Show a projects page description on project archives 220 | * 221 | * Hooked into projects_archive_description 222 | * 223 | * @access public 224 | * @subpackage Archives 225 | * @return void 226 | */ 227 | function projects_project_archive_description() { 228 | if ( is_post_type_archive( 'project' ) && get_query_var( 'paged' ) == 0 || is_page( projects_get_page_id( 'projects' ) ) ) { 229 | $projects_page = get_post( projects_get_page_id( 'projects' ) ); 230 | $page_content = ''; 231 | if ( isset( $projects_page->post_content ) ) { 232 | $page_content = $projects_page->post_content; 233 | } 234 | $description = apply_filters( 'the_content', $page_content ); 235 | if ( $description ) { 236 | echo '
    ' . $description . '
    '; 237 | } 238 | } 239 | } 240 | } 241 | 242 | if ( ! function_exists( 'projects_template_loop_project_thumbnail' ) ) { 243 | 244 | /** 245 | * Get the project thumbnail for the loop. 246 | * 247 | * Hooked into projects_loop_item 248 | * 249 | * @access public 250 | * @subpackage Loop 251 | * @return void 252 | */ 253 | function projects_template_loop_project_thumbnail() { 254 | echo '
    ' . projects_get_project_thumbnail() . '
    '; 255 | } 256 | } 257 | 258 | if ( ! function_exists( 'projects_template_loop_project_title' ) ) { 259 | 260 | /** 261 | * Display the project title in the loop. 262 | * 263 | * Hooked into projects_loop_item 264 | * 265 | * @access public 266 | * @subpackage Loop 267 | * @return void 268 | */ 269 | function projects_template_loop_project_title() { 270 | echo '

    ' . get_the_title() . '

    '; 271 | } 272 | } 273 | 274 | if ( ! function_exists( 'projects_reset_loop' ) ) { 275 | 276 | /** 277 | * Reset the loop's index and columns when we're done outputting a project loop. 278 | * 279 | * @access public 280 | * @subpackage Loop 281 | * @return void 282 | */ 283 | function projects_reset_loop() { 284 | global $projects_loop; 285 | // Reset loop/columns globals when starting a new loop 286 | $projects_loop['loop'] = $projects_loop['column'] = ''; 287 | } 288 | } 289 | 290 | add_filter( 'loop_end', 'projects_reset_loop' ); 291 | 292 | 293 | if ( ! function_exists( 'projects_get_project_thumbnail' ) ) { 294 | 295 | /** 296 | * Get the project thumbnail, or the placeholder if not set. 297 | * 298 | * @access public 299 | * @subpackage Loop 300 | * @param string $size (default: 'project-archive') 301 | * @param int $placeholder_width (default: 0) 302 | * @param int $placeholder_height (default: 0) 303 | * @return string 304 | */ 305 | function projects_get_project_thumbnail( $size = 'project-archive' ) { 306 | global $post; 307 | 308 | if ( has_post_thumbnail() ) 309 | return get_the_post_thumbnail( $post->ID, $size ); 310 | } 311 | } 312 | 313 | if ( ! function_exists( 'projects_pagination' ) ) { 314 | 315 | /** 316 | * Output the pagination. 317 | * 318 | * Hooked into projects_after_loop 319 | * 320 | * @access public 321 | * @subpackage Loop 322 | * @return void 323 | */ 324 | function projects_pagination() { 325 | projects_get_template( 'loop/pagination.php' ); 326 | } 327 | } 328 | 329 | if ( ! function_exists( 'projects_template_short_description' ) ) { 330 | 331 | /** 332 | * Output the project short description. 333 | * 334 | * Hooked into projects_after_loop_item 335 | * 336 | * @access public 337 | * @subpackage Project 338 | * @return void 339 | */ 340 | function projects_template_short_description() { 341 | projects_get_template( 'loop/short-description.php' ); 342 | } 343 | } 344 | 345 | /** Single Project ********************************************************/ 346 | 347 | if ( ! function_exists( 'projects_template_single_feature' ) ) { 348 | 349 | /** 350 | * Output the project feature before the single project summary. 351 | * 352 | * Hooked into projects_before_single_project_summary 353 | * 354 | * @access public 355 | * @subpackage Project 356 | * @return void 357 | */ 358 | function projects_template_single_feature() { 359 | projects_get_template( 'single-project/project-feature.php' ); 360 | } 361 | } 362 | 363 | if ( ! function_exists( 'projects_template_single_gallery' ) ) { 364 | 365 | /** 366 | * Output the project gallery before the single project summary. 367 | * 368 | * Hooked into projects_before_single_project_summary 369 | * 370 | * @access public 371 | * @subpackage Project 372 | * @return void 373 | */ 374 | function projects_template_single_gallery() { 375 | projects_get_template( 'single-project/project-gallery.php' ); 376 | } 377 | } 378 | 379 | if ( ! function_exists( 'projects_template_single_title' ) ) { 380 | 381 | /** 382 | * Output the project title. 383 | * 384 | * Hooked into projects_before_single_project_summary 385 | * 386 | * @access public 387 | * @subpackage Project 388 | * @return void 389 | */ 390 | function projects_template_single_title() { 391 | projects_get_template( 'single-project/title.php' ); 392 | } 393 | } 394 | 395 | if ( ! function_exists( 'projects_template_single_short_description' ) ) { 396 | 397 | /** 398 | * Output the project short description (excerpt). 399 | * 400 | * Hooked into projects_before_single_project_summary 401 | * 402 | * @access public 403 | * @subpackage Project 404 | * @return void 405 | */ 406 | function projects_template_single_short_description() { 407 | projects_get_template( 'single-project/short-description.php' ); 408 | } 409 | } 410 | 411 | if ( ! function_exists( 'projects_template_single_description' ) ) { 412 | 413 | /** 414 | * Output the project description. 415 | * 416 | * Hooked into projects_single_project_summary 417 | * 418 | * @access public 419 | * @subpackage Project 420 | * @return void 421 | */ 422 | function projects_template_single_description() { 423 | projects_get_template( 'single-project/description.php' ); 424 | } 425 | } 426 | 427 | if ( ! function_exists( 'projects_template_single_meta' ) ) { 428 | 429 | /** 430 | * Output the project meta. 431 | * 432 | * Hooked into projects_single_project_summary 433 | * 434 | * @access public 435 | * @subpackage Project 436 | * @return void 437 | */ 438 | function projects_template_single_meta() { 439 | projects_get_template( 'single-project/meta.php' ); 440 | } 441 | } 442 | 443 | if ( ! function_exists( 'projects_single_pagination' ) ) { 444 | 445 | /** 446 | * Output the project pagination. 447 | * 448 | * Hooked into projects_after_single_project 449 | * 450 | * @access public 451 | * @subpackage Project 452 | * @return void 453 | */ 454 | function projects_single_pagination() { 455 | projects_get_template( 'single-project/pagination.php' ); 456 | } 457 | } 458 | 459 | if ( ! function_exists( 'projects_content' ) ) { 460 | 461 | /** 462 | * Output Projects content. 463 | * 464 | * This function is only used in the optional 'projects.php' template 465 | * which people can add to their themes to add basic projects support 466 | * without hooks or modifying core templates. 467 | * 468 | * @access public 469 | * @return void 470 | */ 471 | function projects_content() { 472 | 473 | if ( is_singular( 'project' ) ) { 474 | 475 | while ( have_posts() ) : the_post(); 476 | 477 | projects_get_template_part( 'content', 'single-project' ); 478 | 479 | endwhile; 480 | 481 | } else { ?> 482 | 483 | 484 | 485 |

    486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | ID, '_testimonials_id', true ) ); 535 | if ( isset( $testimonial_id ) && '' != $testimonial_id && '0' != $testimonial_id ) { 536 | $args = apply_filters( 'projects_testimonials_args', array( 537 | 'id' => $testimonial_id, 538 | 'per_row' => 1, 539 | ) ); 540 | echo '
    '; 541 | woothemes_testimonials( $args ); 542 | echo '
    '; 543 | } 544 | 545 | } 546 | } 547 | } 548 | 549 | if ( ! function_exists( 'projects_output_product' ) ) { 550 | 551 | /** 552 | * Output Projects Product. 553 | * 554 | * This function is only used if WooCommerce is enabled. 555 | * It can be used to output a 'buy now' button for a product associated with a project. 556 | * 557 | * Hooked into projects_after_meta 558 | * 559 | * @access public 560 | * @return void 561 | * @since 1.2.0 562 | */ 563 | function projects_output_product() { 564 | if ( class_exists( 'WooCommerce' ) && is_singular( 'project' ) ) { 565 | global $post; 566 | $product_id = esc_attr( get_post_meta( $post->ID, '_products_id', true ) ); 567 | if ( isset( $product_id ) && '' != $product_id && '0' != $product_id ) { 568 | echo '
    '; 569 | echo '

    ' . apply_filters( 'projects_meta_woocommerce_title', __( 'Purchase', 'projects-by-woothemes' ) ) . '

    '; 570 | echo do_shortcode( '[add_to_cart id="' . $product_id . '" style=""]' ); 571 | echo '
    '; 572 | } 573 | 574 | } 575 | } 576 | } 577 | 578 | if ( ! function_exists( 'projects_woocommerce_messages' ) ) { 579 | 580 | /** 581 | * Output Projects WooCommerce Messages. 582 | * 583 | * Displays WooCommerce Messages on the single project page - for feedback adding products to the cart when js is disabled 584 | * 585 | * Hooked into projects_before_single_project 586 | * 587 | * @access public 588 | * @return void 589 | * @since 1.2.0 590 | */ 591 | function projects_woocommerce_messages() { 592 | if ( class_exists( 'WooCommerce' ) && is_singular( 'project' ) ) { 593 | global $post; 594 | $product_id = esc_attr( get_post_meta( $post->ID, '_products_id', true ) ); 595 | if ( isset( $product_id ) && '' != $product_id && '0' != $product_id ) { 596 | echo do_shortcode( '[woocommerce_messages]' ); 597 | } 598 | 599 | } 600 | } 601 | } -------------------------------------------------------------------------------- /projects.php: -------------------------------------------------------------------------------- 1 | dir = dirname( $file ); 60 | $this->file = $file; 61 | $this->assets_dir = trailingslashit( $this->dir ) . 'assets'; 62 | $this->assets_url = esc_url( trailingslashit( plugins_url( '/assets/', $file ) ) ); 63 | $this->token = 'projects'; 64 | $this->post_type = apply_filters( 'projects_post_type_designation', 'project' ); 65 | 66 | // Upgrade data 67 | $this->upgrade_data( true ); 68 | 69 | // Variables 70 | $this->template_url = apply_filters( 'projects_template_url', 'projects/' ); 71 | 72 | $this->load_plugin_textdomain(); 73 | add_action( 'init', array( $this, 'load_localisation' ), 0 ); 74 | 75 | // Define constants 76 | $this->define_constants(); 77 | 78 | // Include required files 79 | $this->includes(); 80 | 81 | // Run this on activation. 82 | register_activation_hook( $this->file, array( $this, 'activation' ) ); 83 | 84 | // Run this on deactivation. 85 | register_deactivation_hook( $this->file, array( $this, 'deactivation' ) ); 86 | 87 | add_action( 'init', array( $this, 'post_type_names' ) ); 88 | add_action( 'init', array( $this, 'register_rewrite_tags' ) ); 89 | add_action( 'init', array( $this, 'register_post_type' ) ); 90 | add_action( 'init', array( $this, 'register_taxonomy' ) ); 91 | 92 | add_action( 'widgets_init', array( $this, 'include_widgets' ) ); 93 | 94 | add_action( 'after_setup_theme', array( $this, 'ensure_post_thumbnails_support' ) ); 95 | add_action( 'after_setup_theme', array( $this, 'register_image_sizes' ) ); 96 | 97 | if ( is_admin() ) { 98 | require_once( 'classes/class-projects-admin.php' ); 99 | $this->admin = new Projects_Admin( $file ); 100 | } else { 101 | require_once( 'classes/class-projects-frontend.php' ); 102 | $this->frontend = new Projects_Frontend( $file ); 103 | } 104 | 105 | } // End __construct() 106 | 107 | /** 108 | * Register custom rewrite tags. 109 | * @access public 110 | * @since 1.0.0 111 | * @return void 112 | */ 113 | public function register_rewrite_tags () { 114 | add_rewrite_tag( '%project_category%','([^&]+)' ); 115 | } // End register_rewrite_tags() 116 | 117 | /** 118 | * Define Projects Constants 119 | */ 120 | private function define_constants() { 121 | define( 'PROJECTS_PLUGIN_FILE', __FILE__ ); 122 | define( 'PROJECTS_VERSION', $this->version ); 123 | } // End define_constants() 124 | 125 | /** 126 | * Change the UI names in the admin 127 | * 128 | * @access public 129 | * @since 1.1.0 130 | * @return void 131 | */ 132 | public function post_type_names () { 133 | $this->singular_name = apply_filters( 'projects_post_type_singular_name', _x( 'Project', 'post type singular name', 'projects-by-woothemes' ) ); 134 | $this->plural_name = apply_filters( 'projects_post_type_plural_name', _x( 'Projects', 'post type general name', 'projects-by-woothemes' ) ); 135 | } // End post_type_names() 136 | 137 | /** 138 | * Register the post type. 139 | * 140 | * @access public 141 | * @return void 142 | */ 143 | public function register_post_type () { 144 | 145 | $labels = array( 146 | 'name' => $this->plural_name, 147 | 'singular_name' => $this->singular_name, 148 | 'add_new' => _x( 'Add New', $this->post_type, 'projects-by-woothemes' ), 149 | 'add_new_item' => sprintf( __( 'Add New %s', 'projects-by-woothemes' ), $this->singular_name ), 150 | 'edit_item' => sprintf( __( 'Edit %s', 'projects-by-woothemes' ), $this->singular_name ), 151 | 'new_item' => sprintf( __( 'New %s', 'projects-by-woothemes' ), $this->singular_name ), 152 | 'all_items' => sprintf( _x( 'All %s', $this->post_type, 'projects-by-woothemes' ), $this->plural_name ), 153 | 'view_item' => sprintf( __( 'View %s', 'projects-by-woothemes' ), $this->singular_name ), 154 | 'search_items' => sprintf( __( 'Search %a', 'projects-by-woothemes' ), $this->plural_name ), 155 | 'not_found' => sprintf( __( 'No %s Found', 'projects-by-woothemes' ), $this->plural_name ), 156 | 'not_found_in_trash' => sprintf( __( 'No %s Found In Trash', 'projects-by-woothemes' ), $this->plural_name ), 157 | 'parent_item_colon' => '', 158 | 'menu_name' => $this->plural_name 159 | 160 | ); 161 | $args = array( 162 | 'labels' => apply_filters( 'projects_post_type_labels', $labels, $labels ), 163 | 'public' => true, 164 | 'publicly_queryable' => true, 165 | 'show_ui' => true, 166 | 'show_in_menu' => true, 167 | 'query_var' => true, 168 | 'rewrite' => apply_filters( 'projects_post_type_rewrite', true ), 169 | 'capability_type' => 'post', 170 | 'has_archive' => ( $projects_page_id = projects_get_page_id( 'projects' ) ) && get_page( $projects_page_id ) ? get_page_uri( $projects_page_id ) : 'projects', 171 | 'hierarchical' => false, 172 | 'supports' => array( 173 | 'title', 174 | 'editor', 175 | 'thumbnail', 176 | 'excerpt' 177 | ), 178 | 'menu_position' => 5, 179 | 'menu_icon' => 'dashicons-portfolio' 180 | ); 181 | 182 | $args = apply_filters( 'projects_register_post_type', $args ); 183 | 184 | register_post_type( $this->post_type, (array) $args ); 185 | } // End register_post_type() 186 | 187 | /** 188 | * Register the "project-category" taxonomy. 189 | * @access public 190 | * @since 1.3.0 191 | * @return void 192 | */ 193 | public function register_taxonomy () { 194 | $this->taxonomy_category = new Projects_Taxonomy(); // Leave arguments empty, to use the default arguments. 195 | $this->taxonomy_category->register(); 196 | } // End register_taxonomy() 197 | 198 | /** 199 | * Register image sizes. 200 | * @since 1.0.0 201 | * @return void 202 | */ 203 | public function register_image_sizes () { 204 | if ( function_exists( 'add_image_size' ) ) { 205 | 206 | $options = get_option( 'projects-images-fields' ); 207 | 208 | $defaults = apply_filters( 'projects_default_image_size', array( 209 | 'project-archive' => array( 210 | 'width' => 300, 211 | 'height' => 300, 212 | 'crop' => 'no' 213 | ), 214 | 'project-single' => array( 215 | 'width' => 1024, 216 | 'height' => 1024, 217 | 'crop' => 'no' 218 | ), 219 | 'project-thumbnail' => array( 220 | 'width' => 100, 221 | 'height' => 100, 222 | 'crop' => 'yes' 223 | ) 224 | ) ); 225 | 226 | // Parse incomming $options into an array and merge it with $defaults 227 | $options = wp_parse_args( $options, $defaults ); 228 | 229 | // Register each image size 230 | foreach ( $options as $image_size => $size ) { 231 | $crop = isset( $size['crop'] ) && 'yes' == $size['crop'] ? true : false; 232 | add_image_size( $image_size, $size['width'], $size['height'], $crop ); 233 | } 234 | 235 | } 236 | } // End register_image_sizes() 237 | 238 | /** 239 | * Get projects. 240 | * @param string/array $args Arguments to be passed to the query. 241 | * @since 1.0.0 242 | * @return array/boolean Array if true, boolean if false. 243 | */ 244 | public function get_projects ( $args = '' ) { 245 | $defaults = array( 246 | 'limit' => 5, 247 | 'orderby' => 'menu_order', 248 | 'order' => 'DESC', 249 | 'id' => 0 250 | ); 251 | 252 | $args = wp_parse_args( $args, $defaults ); 253 | 254 | // Allow child themes/plugins to filter here. 255 | $args = apply_filters( 'projects_get_projects_args', $args ); 256 | 257 | // The Query Arguments. 258 | $query_args = array(); 259 | $query_args['post_type'] = 'project'; 260 | $query_args['numberposts'] = $args['limit']; 261 | $query_args['orderby'] = $args['orderby']; 262 | $query_args['order'] = $args['order']; 263 | 264 | if ( is_numeric( $args['id'] ) && ( intval( $args['id'] ) > 0 ) ) { 265 | $query_args['p'] = intval( $args['id'] ); 266 | } 267 | 268 | // Whitelist checks. 269 | if ( ! in_array( $query_args['orderby'], array( 'none', 'ID', 'author', 'title', 'date', 'modified', 'parent', 'rand', 'comment_count', 'menu_order', 'meta_value', 'meta_value_num' ) ) ) { 270 | $query_args['orderby'] = 'date'; 271 | } 272 | 273 | if ( ! in_array( $query_args['order'], array( 'ASC', 'DESC' ) ) ) { 274 | $query_args['order'] = 'DESC'; 275 | } 276 | 277 | if ( ! in_array( $query_args['post_type'], get_post_types() ) ) { 278 | $query_args['post_type'] = 'project'; 279 | } 280 | 281 | // The Query. 282 | $query = get_posts( $query_args ); 283 | 284 | // The Display. 285 | if ( ! is_wp_error( $query ) && is_array( $query ) && count( $query ) > 0 ) { 286 | foreach ( $query as $k => $v ) { 287 | $meta = get_post_custom( $v->ID ); 288 | 289 | // Get the image. 290 | $query[$k]->image = projects_get_image( $v->ID, $args['size'] ); 291 | 292 | // Get the URL. 293 | if ( isset( $meta['_url'][0] ) && '' != $meta['_url'][0] ) { 294 | $query[$k]->url = esc_url( $meta['_url'][0] ); 295 | } else { 296 | $query[$k]->url = get_permalink( $v->ID ); 297 | } 298 | } 299 | } else { 300 | $query = false; 301 | } 302 | 303 | return $query; 304 | } // End get_projects() 305 | 306 | /** 307 | * Load the plugin's localisation file. 308 | * @access public 309 | * @since 1.0.0 310 | * @return void 311 | */ 312 | public function load_localisation () { 313 | load_plugin_textdomain( 'projects-by-woothemes', false, dirname( plugin_basename( $this->file ) ) . '/lang/' ); 314 | } // End load_localisation() 315 | 316 | /** 317 | * Load the plugin textdomain from the main WordPress "languages" folder. 318 | * @since 1.0.0 319 | * @return void 320 | */ 321 | public function load_plugin_textdomain () { 322 | $domain = 'projects-by-woothemes'; 323 | // The "plugin_locale" filter is also used in load_plugin_textdomain() 324 | $locale = apply_filters( 'plugin_locale', get_locale(), $domain ); 325 | 326 | load_textdomain( $domain, WP_LANG_DIR . '/' . $domain . '/' . $domain . '-' . $locale . '.mo' ); 327 | load_plugin_textdomain( $domain, FALSE, dirname( plugin_basename( $this->file ) ) . '/lang/' ); 328 | } // End load_plugin_textdomain() 329 | 330 | /** 331 | * Run on activation. 332 | * @access public 333 | * @since 1.0.0 334 | * @return void 335 | */ 336 | public function activation () { 337 | $this->register_plugin_version(); 338 | 339 | // Flush rewrite rules 340 | flush_rewrite_rules(); 341 | } // End activation() 342 | 343 | /** 344 | * Run on deactivation. 345 | * @access public 346 | * @since 1.0.0 347 | * @return void 348 | */ 349 | public function deactivation () { 350 | // Flush rewrite rules 351 | flush_rewrite_rules(); 352 | } // End deactivation() 353 | 354 | /** 355 | * Register the plugin's version. 356 | * @access public 357 | * @since 1.0.0 358 | * @return void 359 | */ 360 | private function register_plugin_version () { 361 | if ( $this->version != '' ) { 362 | update_option( 'projects' . '-version', $this->version ); 363 | } 364 | } // End register_plugin_version() 365 | 366 | /** 367 | * Ensure that "post-thumbnails" support is available for those themes that don't register it. 368 | * @since 1.0.0 369 | * @return void 370 | */ 371 | public function ensure_post_thumbnails_support () { 372 | if ( ! current_theme_supports( 'post-thumbnails' ) ) { add_theme_support( 'post-thumbnails' ); } 373 | } // End ensure_post_thumbnails_support() 374 | 375 | /** 376 | * Get the plugin url. 377 | * @access public 378 | * @since 1.0.0 379 | * @return string 380 | */ 381 | public function plugin_url () { 382 | return untrailingslashit( plugins_url( '/', $this->file ) ); 383 | } // End plugin_url() 384 | 385 | 386 | /** 387 | * Get the plugin path. 388 | * @access public 389 | * @since 1.0.0 390 | * @return string 391 | */ 392 | public function plugin_path () { 393 | return untrailingslashit( plugin_dir_path( $this->file ) ); 394 | } // End plugin_path() 395 | 396 | 397 | /** 398 | * Get an image size. 399 | * 400 | * Variable is filtered by projects_get_image_size_{image_size} 401 | * 402 | * @access public 403 | * @since 1.0.0 404 | * @param mixed $image_size 405 | * @return string 406 | */ 407 | public function get_image_size ( $image_size ) { 408 | // Only return sizes we define in settings 409 | if ( ! in_array( $image_size, array( 'project-thumbnail', 'project-archive', 'project-single' ) ) ) 410 | return apply_filters( 'projects_get_image_size_' . $image_size, '' ); 411 | 412 | // Get image size from options 413 | $options = get_option( 'projects-images-fields', array() ); 414 | $size = $options[ $image_size ]; 415 | 416 | $size['width'] = isset( $size['width'] ) ? $size['width'] : '300'; 417 | $size['height'] = isset( $size['height'] ) ? $size['height'] : '300'; 418 | $size['crop'] = isset( $size['crop'] ) ? $size['crop'] : 1; 419 | 420 | return apply_filters( 'projects_get_image_size_' . $image_size, $size ); 421 | } // End get_image_size() 422 | 423 | /** 424 | * Include Projects widgets. 425 | * 426 | * @access public 427 | * @since 1.2.2 428 | */ 429 | public function include_widgets() { 430 | include_once( 'classes/class-widget-projects.php' ); 431 | include_once( 'classes/class-widget-project-categories.php' ); 432 | } // End include_widgets() 433 | 434 | /** 435 | * Include required files. 436 | * @since 1.2.2 437 | */ 438 | private function includes() { 439 | require_once( 'classes/class-projects-taxonomy.php' ); 440 | require_once( 'classes/class-projects-shortcodes.php' ); 441 | require_once( 'classes/class-projects-settings.php' ); 442 | require_once( 'classes/class-projects-integrations.php' ); 443 | 444 | require_once( 'projects-template.php' ); 445 | require_once( 'projects-core-functions.php' ); 446 | require_once( 'projects-hooks.php' ); 447 | } // End includes() 448 | 449 | /** 450 | * upgrade_data upgrades old data structure to the new data structure 451 | * @param boolean $upgrade_data override setting to run the function 452 | * @since 1.2.3 453 | * @return void 454 | */ 455 | private function upgrade_data( $upgrade_data = false ) { 456 | if ( $upgrade_data ) { 457 | // Get old data 458 | $old_options = get_option( 'projects' ); 459 | if ( isset( $old_options['projects_page_id'] ) && is_array( $old_options ) && !empty( $old_options ) ) { 460 | // Check if new pages data exists 461 | $new_pages_options = get_option( 'projects-pages-fields' ); 462 | if ( !isset( $new_pages_options['projects_page_id'] ) ) { 463 | update_option( 'projects-pages-fields', array( 'projects_page_id' => $old_options['projects_page_id'] ) ); 464 | } // End If Statement 465 | // Check if new images data exists 466 | $new_images_options = get_option( 'projects-images-fields' ); 467 | if ( !isset( $new_images_options['project-archive'] ) && !isset( $new_images_options['project-single'] ) && !isset( $new_images_options['project-thumbnail'] ) ) { 468 | update_option( 'projects-images-fields', array( 'project-archive' => $old_options['project-archive'], 469 | 'project-single' => $old_options['project-single'], 470 | 'project-thumbnail' => $old_options['project-thumbnail'] 471 | ) ); 472 | } // End If Statement 473 | // Remove old data 474 | delete_option( 'projects' ); 475 | } // End If Statement 476 | } // End If Statement 477 | } // End upgrade_data() 478 | 479 | } // End Class 480 | 481 | global $projects; 482 | 483 | $projects = new Projects( __FILE__ ); -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | === Projects by WooThemes === 2 | Contributors: woothemes, mattyza, jameskoster, tiagonoronha, jeffikus 3 | Donate link: http://woothemes.com/ 4 | Tags: portfolio, projects, project, showcase, artwork, work, creative, photography, art, images, woocommerce 5 | Requires at least: 4.0 6 | Tested up to: 4.3.1 7 | Stable tag: 1.5.0 8 | License: GPLv2 or later 9 | License URI: http://www.gnu.org/licenses/gpl-2.0.html 10 | 11 | Hi, I'm your projects showcase plugin for WordPress. Use me to show off a portfolio of your latest work. 12 | 13 | == Description == 14 | 15 | = Create and display a portfolio of projects = 16 | 17 | "Projects" by WooThemes is a clean and easy-to-use portfolio showcase management system for WordPress. Load in your recent projects, and display them on a specified page using our template system, or via a shortcode, widget or template tag. 18 | 19 | Projects integrates with our [testimonials plugin](http://wordpress.org/plugins/testimonials-by-woothemes/) allowing you to associate a testimonial with a project and display it on the single project page. 20 | 21 | You can even assign a project to a product you've created in [WooCommerce](http://wordpress.org/plugins/woocommerce/) and let customers add it to their cart from the project page. 22 | 23 | = Easy to use = 24 | 25 | Publish and categorise your portfolio of projects using the familiar WordPress interface. 26 | 27 | = Detailed project information = 28 | 29 | Include full project details such as cover images, galleries, categories, client details and projects URLs. 30 | 31 | = Fully integrated with WordPress = 32 | 33 | Display your portfolio of projects using native WordPress architecture (project archives & single pages). 34 | 35 | = Widgets & Shortcodes included = 36 | 37 | Use Widgets & Shortcodes for situational project display. 38 | 39 | = Mobile friendly = 40 | 41 | Projects includes a responsive layout to integrate with any theme. 42 | 43 | = Customisable = 44 | 45 | Get your hands dirty! Customise & extend Projects via a vast array of hooks, filters & templates. 46 | 47 | = WooCommerce = 48 | Assign projects to products and give visitors an easy way to add products to their cart using [WooCommerce](http://wordpress.org/plugins/woocommerce/) functionality. 49 | 50 | = Testimonials = 51 | 52 | Integrated with our [testimonials plugin](http://wordpress.org/plugins/testimonials-by-woothemes/) allowing you to assign a client testimonial to a project and display it on the single project page. 53 | 54 | = Documentation = 55 | 56 | Extensive [documentation](http://docs.woothemes.com/documentation/plugins/projects/) to help you out if you get stuck. 57 | 58 | == Usage == 59 | 60 | Once installed you can begin adding projects to your portfolio right away via the 'Projects' item in the main menu. But before you do that you should go ahead and create a page for your projects (via the Pages menu item) and specify that page as your projects base page in the projects settings. The interface for adding projects is very similar to adding posts so you should feel right at home. 61 | 62 | For more detailed usage instructions take a look at the [Projects Documentation](http://docs.woothemes.com/documentation/plugins/projects/). 63 | 64 | == Installation == 65 | 66 | Installing "Projects" can be done either by searching for "Projects by WooThemes" via the "Plugins > Add New" screen in your WordPress dashboard, or by using the following steps: 67 | 68 | 1. Download the plugin via WordPress.org. 69 | 2. Upload the ZIP file through the "Plugins > Add New > Upload" screen in your WordPress dashboard. 70 | 3. Activate the plugin through the 'Plugins' menu in WordPress 71 | 72 | == Frequently Asked Questions == 73 | 74 | = My project images are blurry / distorted, how do I fix that? = 75 | 76 | It's possible that your theme is scaling images to fit their container by setting `width: 100%;`. If this is the case, and your project thumbnails are too small they will become distored / blurred as they are scaled up. To fix this change the project thumbnail size options in the Projects settings then regenerate your thumbnails using the [Regenerate Thumbnails plugin](http://wordpress.org/plugins/regenerate-thumbnails/). 77 | 78 | = How do I integrate projects into my theme? = 79 | 80 | If you run into layout issues on Projects pages then you will need to peruse one of two methods to make your theme compatible. You can read all about this in the [documentation](http://docs.woothemes.com/document/third-party-theme-compatibility/). 81 | 82 | = I want to change X = 83 | 84 | Projects uses template files to control the display of it's various components. These templates can be safely editied so that your customisations are not lost during updates as described in the [documentation](http://docs.woothemes.com/document/editing-projects-templates-safely/). 85 | 86 | = Is it possible to add cusstom fields to the Project details meta box? = 87 | 88 | Yes! You can follow this tutorial to [add custom fields to projects](http://docs.woothemes.com/document/add-a-project-meta-field/) and display them. 89 | 90 | = How do I contribute? = 91 | 92 | We encourage everyone to contribute their ideas, thoughts and code snippets. This can be done by forking the [repository over at GitHub](http://github.com/woothemes/projects/). 93 | 94 | = Can I display a tesitmonial on a project page? = 95 | 96 | You sure can! Read about how in the [documentation](http://docs.woothemes.com/document/adding-testimonials-to-projects/). 97 | 98 | == Screenshots == 99 | 100 | 1. The projects base page 101 | 2. A single project page 102 | 3. The projects management screen within the WordPress dashboard. 103 | 104 | == Upgrade Notice == 105 | 106 | = 1.5.0 = 107 | * Fixes projects page not loading - please resave permalinks after updating! 108 | 109 | = 1.4.2 = 110 | * Removes deprecated constructor call for WP_Widget 111 | 112 | = 1.4.0 = 113 | * The default permalink structure has been tweaked to remove the project category. So http://localhost/network/project/landscapes/the-barrow-downs/ becomes http://localhost/network/project/the-barrow-downs/. Any old links will automatically redirect to their newer counterparts. You may have to re-save your permalink settings after performing this update. You can use the `projects_post_type_rewrite` filter to adjust this. 114 | 115 | = 1.3.0 = 116 | * The project category urls have been improved to use the base page title as the slug opposed to the `project-category` default. So, previously your project cateogry urls will have looked like: yoursite.com/project-category/illustration. Now, `project-category` is replaced with the slug of your projects base page. So if you're using a page called 'Portfolio' that url will now look like: yoursite.com/portfolio/illustration. You will have to create custom redirects if you want the old urls work. 117 | * This version adds admin tabs to the settings screens, and will run an update to your existing settings data. If your data is not retained, simply resave your settings. 118 | 119 | = 1.2.0 = 120 | * The project archive slug now mirrors your projects base page slug isntead of being fixed as 'projects'. If you're using a base page with a slug other than 'projects' you may want to check any static links to your projects page. For example if your base page is 'portfolio' your projects post type archive will now exist at http://yoursite.com/portfolio rather than http://yoursite.com/projects. 121 | 122 | = 1.0.0 = 123 | * Initial release. Woo! 124 | 125 | == Changelog == 126 | 127 | = 1.5.0 = 128 | * 2015.12.07 129 | * New/Fix - Adds query class to modify the query to fix the Project page not loading. 130 | 131 | = 1.4.2 = 132 | * 2015.07.07 133 | * Tweak - Allow attribute for include_children inside taxonomy query. 134 | * Removes deprecated constructor call for WP_Widget 135 | 136 | = 1.4.1 = 137 | * 2014.12.05 138 | * Fix - Redirect issue when setting projects page as homepage. 139 | 140 | = 1.4.0 = 141 | * 2014-11-11 142 | * Fix - Project gallery thumbnail sizes in admin. (Props @corvannoorloos). 143 | * Fix - Undefined index notice when trashing/untrashing projects. (Props @johnbuck). 144 | * Tweak - Improvements to `projects_template_redirect()`. 145 | * Tweak - Added `rel="lightbox"` to project galleries for compatibility with lightbox plugins. 146 | * Tweak - Project post type default url structure no longer includes project category (resolves attachment page 404's. 147 | 148 | = 1.3.0 = 149 | * 2014-08-26 150 | * New - Adds admin tabs to the settings screens for better UX. 151 | * New - Category permalinks use base page for structure. 152 | 153 | = 1.2.2 = 154 | * 2014-06-06 155 | * Tweak - Product linking label now includes sku / id. 156 | * Tweak - Widgets now called via a single function and other minor refactoring. 157 | * Tweak - Project Category taxonomy names filterable. (Props @abouolia) 158 | * Fix - Reset post data in projects widget. 159 | 160 | = 1.2.1 = 161 | * 2014-04-24 162 | * Fix - Javascript error in admin 163 | * Fix - Select box save method. (Props @anija). 164 | 165 | = 1.2.0 = 166 | * 2014-04-09 167 | * New - Replaced .less files with .scss. 168 | * New - Integrated with WooCommerce. 169 | * New - Added config.codekit. 170 | * New - Project images can now be cropped. (Props @helgatheviking). 171 | * New - Project archive slug is now retreived from base page slug. 172 | * Tweak - Added css for multi column layouts when using the shortcode to display projects. 173 | * Tweak - Project categories can now be added to navigation menus. 174 | * Tweak - Various new input types can now be easily added using projects_custom_fields filter. (Props @helgatheviking). 175 | * Tweak - Menu icon added in register_post_type() and now filterable. (Props @helgatheviking). 176 | * Tweak - Added an edit media link to the project gallery meta box. 177 | 178 | = 1.1.0 = 179 | * 2014-03-25 180 | * New - Integration with Testimonials plugin. 181 | * New - dummy_data.xml containing dummy projects content. 182 | * New - Project excerpt replaced with new short description meta box with tinymce support. 183 | * New - Projects can now be filtered by category on the project management screen. 184 | * Fix - Project category widget list items are now wrapped in a ul. 185 | * Tweak - Shortcodes in project descriptions now work as expected. Shortcodes in excerpts will need to be enabled. 186 | * Tweak - Gallery images link to full size versions. Disable with projects_gallery_link_images filter. 187 | * Tweak - Projects Post Type / Taxonomy args are now filterable. (Props @helgatheviking). 188 | * Tweak - Projects post type single/plural names are now filterable. (Props @helgatheviking). 189 | * Tweak - Several UI tweaks and improvements. 190 | * Tweak - It's now possible to add select and radio custom fields using the projects_custom_fields filter (Props @helgatheviking). 191 | 192 | = 1.0.1 = 193 | * 2014-02-24 194 | * Localization - Replaces incorrect language files. 195 | * Tweak - Localized some strings (props Vaclad) 196 | 197 | = 1.0.0 = 198 | * 2014-02-17 199 | * Initial release. Woo! 200 | -------------------------------------------------------------------------------- /templates/archive-project.php: -------------------------------------------------------------------------------- 1 | 21 | 22 | 30 | 31 | 32 | 33 |

    34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 48 | 49 |
    50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 |
    62 | 63 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 86 | 87 | 95 | 96 | -------------------------------------------------------------------------------- /templates/content-project-category.php: -------------------------------------------------------------------------------- 1 | 27 |
  • 33 | 34 | 35 | 36 | 37 | 38 | 46 | 47 |

    48 | name; 50 | 51 | if ( $category->count > 0 ) 52 | echo apply_filters( 'projects_subcategory_count_html', ' (' . $category->count . ')', $category ); 53 | ?> 54 |

    55 | 56 | 62 | 63 |
    64 | 65 | 66 | 67 |
  • -------------------------------------------------------------------------------- /templates/content-project-widget.php: -------------------------------------------------------------------------------- 1 | 16 |
  • 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
  • -------------------------------------------------------------------------------- /templates/content-project.php: -------------------------------------------------------------------------------- 1 | 34 |
  • > 35 | 36 | 37 | 38 | 39 | 40 | 49 | 50 | 51 | 52 | 60 | 61 |
  • -------------------------------------------------------------------------------- /templates/content-single-project.php: -------------------------------------------------------------------------------- 1 | 14 | 15 | 22 | 23 |
    > 24 | 25 | 35 | 36 |
    37 | 38 | 47 | 48 |
    49 | 50 | 57 | 58 |
    59 | 60 | '; 15 | break; 16 | case 'twentytwelve' : 17 | echo ''; 18 | break; 19 | case 'twentythirteen' : 20 | echo ''; 21 | break; 22 | case 'twentyfourteen' : 23 | echo ''; 24 | get_sidebar( 'content' ); 25 | break; 26 | default : 27 | echo ''; 28 | break; 29 | } -------------------------------------------------------------------------------- /templates/layout/wrapper-start.php: -------------------------------------------------------------------------------- 1 |
    '; 17 | break; 18 | case 'twentytwelve' : 19 | echo '
    '; 20 | break; 21 | case 'twentythirteen' : 22 | echo '
    '; 23 | break; 24 | case 'twentyfourteen' : 25 | echo '
    '; 26 | break; 27 | default : 28 | echo '
    '; 29 | break; 30 | } -------------------------------------------------------------------------------- /templates/loop/loop-end.php: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /templates/loop/loop-start.php: -------------------------------------------------------------------------------- 1 | 10 |
      -------------------------------------------------------------------------------- /templates/loop/no-projects-found.php: -------------------------------------------------------------------------------- 1 | 14 |

      -------------------------------------------------------------------------------- /templates/loop/pagination.php: -------------------------------------------------------------------------------- 1 | max_num_pages <= 1 ) 15 | return; 16 | ?> 17 | -------------------------------------------------------------------------------- /templates/loop/short-description.php: -------------------------------------------------------------------------------- 1 | post_excerpt ) ) { 15 | $excerpt_raw = $post->post_excerpt; 16 | } // End If Statement 17 | if ( '' === trim( $excerpt_raw ) ) { 18 | $excerpt_raw = get_the_excerpt(); 19 | } // End If Statement 20 | ?> 21 |
      22 | 23 |
      -------------------------------------------------------------------------------- /templates/single-project.php: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 39 | 40 | 48 | 49 | post_content ) return; 15 | ?> 16 |
      17 | 18 |
      -------------------------------------------------------------------------------- /templates/single-project/meta.php: -------------------------------------------------------------------------------- 1 | 14 |
      15 | 16 | ID, 'project-category', '
    • ', '
    • ', '
    • ' ); 19 | 20 | // Meta 21 | $client = esc_attr( get_post_meta( $post->ID, '_client', true ) ); 22 | $url = esc_url( get_post_meta( $post->ID, '_url', true ) ); 23 | 24 | do_action( 'projects_before_meta' ); 25 | 26 | /** 27 | * Display categories if they're set 28 | */ 29 | if ( $terms_as_text ) { 30 | echo '
      '; 31 | echo '

      ' . __( 'Categories', 'projects-by-woothemes' ) . '

      '; 32 | echo '
        '; 33 | echo $terms_as_text; 34 | echo '
      '; 35 | echo '
      '; 36 | } 37 | 38 | /** 39 | * Display client if set 40 | */ 41 | if ( $client ) { 42 | echo '
      '; 43 | echo '

      ' . __( 'Client', 'projects-by-woothemes' ) . '

      '; 44 | echo '' . $client . ''; 45 | echo '
      '; 46 | } 47 | 48 | /** 49 | * Display link if set 50 | */ 51 | if ( $url ) { 52 | echo '
      '; 53 | echo '

      ' . __( 'Link', 'projects-by-woothemes' ) . '

      '; 54 | echo '' . apply_filters( 'projects_visit_project_link', __( 'Visit project', 'projects-by-woothemes' ) ) . ''; 55 | echo '
      '; 56 | } 57 | 58 | do_action( 'projects_after_meta' ); 59 | ?> 60 |
      -------------------------------------------------------------------------------- /templates/single-project/pagination.php: -------------------------------------------------------------------------------- 1 | 12 | 20 | -------------------------------------------------------------------------------- /templates/single-project/project-feature.php: -------------------------------------------------------------------------------- 1 | 15 | 43 | -------------------------------------------------------------------------------- /templates/single-project/project-gallery.php: -------------------------------------------------------------------------------- 1 | 15 | 61 | -------------------------------------------------------------------------------- /templates/single-project/short-description.php: -------------------------------------------------------------------------------- 1 | post_excerpt ) return; 15 | ?> 16 |
      17 | post_excerpt ) ) ?> 18 |
      -------------------------------------------------------------------------------- /templates/single-project/title.php: -------------------------------------------------------------------------------- 1 | 13 |

      -------------------------------------------------------------------------------- /templates/taxonomy-project-category.php: -------------------------------------------------------------------------------- 1 |