├── .distignore
├── .editorconfig
├── .github
└── workflows
│ ├── assets-readme.yml
│ └── main.yml
├── .wordpress-org
├── banner-1544x500.jpg
├── banner-772-250.jpg
├── icon-128x128.jpg
├── icon-256x256.jpg
└── screenshot-1.png
├── README.md
├── README.txt
├── admin
├── admin.php
├── ajax.php
├── css
│ └── query-wrangler.css
├── default_editors.php
├── editors
│ ├── picnic
│ │ ├── picnic-editor.php
│ │ ├── picnic.css
│ │ └── picnic.js
│ └── views
│ │ ├── views-editor.php
│ │ ├── views.css
│ │ └── views.js
├── images
│ ├── handle2.png
│ ├── loading.gif
│ └── white-grad.png
├── js
│ ├── jquery.unserialize-form.js
│ ├── query-wrangler-list.js
│ └── query-wrangler.js
├── query-admin-pages.php
└── templates
│ ├── form-create.php
│ ├── form-editor.php
│ ├── form-export.php
│ ├── form-import.php
│ ├── form-settings.php
│ ├── handler-field.php
│ ├── handler-filter.php
│ ├── handler-override.php
│ ├── handler-sort.php
│ ├── page-admin-wrapper.php
│ ├── page-query-list.php
│ └── preview-json.php
├── docs
└── examples
│ ├── field.md
│ ├── filter.md
│ ├── hooks.md
│ └── sort.md
├── includes
├── basics
│ ├── display_title.php
│ ├── empty.php
│ ├── footer.php
│ ├── header.php
│ ├── ignore_sticky_posts.php
│ ├── offset.php
│ ├── page_path.php
│ ├── page_template.php
│ ├── pager.php
│ ├── post_status.php
│ ├── posts_per_page.php
│ ├── row_styles.php
│ ├── template_styles.php
│ └── wrapper_settings.php
├── class-qw-override.php
├── class-qw-query.php
├── class-qw-settings.php
├── class-qw-shortcodes.php
├── exposed.php
├── fields
│ ├── callback_field.php
│ ├── default_fields.php
│ ├── featured_image.php
│ ├── file_attachment.php
│ ├── image_attachment.php
│ ├── meta_value.php
│ ├── meta_value_new.php
│ ├── post_author.php
│ ├── post_author_avatar.php
│ └── taxonomy_terms.php
├── filters
│ ├── author.php
│ ├── callback.php
│ ├── categories.php
│ ├── meta_key.php
│ ├── meta_key_value.php
│ ├── meta_query.php
│ ├── meta_value.php
│ ├── post_id.php
│ ├── post_parent.php
│ ├── post_types.php
│ ├── search.php
│ ├── tags.php
│ ├── taxonomies.php
│ └── taxonomy_relation.php
├── handlers.php
├── hooks.php
├── overrides
│ ├── categories.php
│ ├── post_type_archive.php
│ ├── tags.php
│ └── taxonomies.php
├── pages.php
├── php-polyfill.php
├── query.php
├── sorts
│ └── default_sorts.php
└── theme.php
├── query-wrangler.php
├── template-wrangler.php
├── templates
├── query-complete.php
├── query-excerpt.php
├── query-ordered_list.php
├── query-table.php
├── query-unformatted.php
├── query-unordered_list.php
└── query-wrapper.php
├── upgrade.php
└── widget.query.php
/.distignore:
--------------------------------------------------------------------------------
1 | /.wordpress-org
2 | /.git
3 | /.github
4 | /node_modules
5 |
6 | .distignore
7 | .gitignore
8 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # @see http://editorconfig.org/
2 |
3 | # This is the top-most .editorconfig file; do not search in parent directories.
4 | root = true
5 |
6 | # All files.
7 | [*]
8 | end_of_line = LF
9 | indent_style = tab
10 | charset = utf-8
11 | trim_trailing_whitespace = true
12 | insert_final_newline = true
13 |
14 | [*.{yml,yaml}]
15 | indent_size = 2
16 |
17 | [composer.{json,lock}]
18 | indent_size = 4
19 |
--------------------------------------------------------------------------------
/.github/workflows/assets-readme.yml:
--------------------------------------------------------------------------------
1 | name: Plugin asset/readme update
2 | on:
3 | push:
4 | branches:
5 | - master
6 | jobs:
7 | master:
8 | name: Push to master
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@master
12 | - name: WordPress.org plugin asset/readme update
13 | uses: 10up/action-wordpress-plugin-asset-update@stable
14 | env:
15 | SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
16 | SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
17 | README_NAME: 'README.txt'
18 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Deploy to WordPress.org
2 | on:
3 | push:
4 | tags:
5 | - "*"
6 | jobs:
7 | tag:
8 | name: New tag
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@master
12 |
13 | # - name: Validate composer.json and composer.lock
14 | # run: composer validate
15 |
16 | # - name: Install dependencies
17 | # run: composer install --prefer-dist --no-progress --no-suggest --no-dev
18 |
19 | # - name: Build
20 | # run: |
21 | # npm install
22 | # npm run build
23 | - name: WordPress Plugin Deploy
24 | uses: 10up/action-wordpress-plugin-deploy@1.5.0
25 | env:
26 | SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
27 | SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
28 | SLUG: query-wrangler
29 |
--------------------------------------------------------------------------------
/.wordpress-org/banner-1544x500.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daggerhart/query-wrangler/55e368ff94e63bcdc8ded5ad4701791fb78a6f6a/.wordpress-org/banner-1544x500.jpg
--------------------------------------------------------------------------------
/.wordpress-org/banner-772-250.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daggerhart/query-wrangler/55e368ff94e63bcdc8ded5ad4701791fb78a6f6a/.wordpress-org/banner-772-250.jpg
--------------------------------------------------------------------------------
/.wordpress-org/icon-128x128.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daggerhart/query-wrangler/55e368ff94e63bcdc8ded5ad4701791fb78a6f6a/.wordpress-org/icon-128x128.jpg
--------------------------------------------------------------------------------
/.wordpress-org/icon-256x256.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daggerhart/query-wrangler/55e368ff94e63bcdc8ded5ad4701791fb78a6f6a/.wordpress-org/icon-256x256.jpg
--------------------------------------------------------------------------------
/.wordpress-org/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daggerhart/query-wrangler/55e368ff94e63bcdc8ded5ad4701791fb78a6f6a/.wordpress-org/screenshot-1.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Query Wrangler
2 |
3 | Query Wrangler is a WordPress plugin that provides an intuitive interface for creating complex WP queries as shortcodes and widgets. UI based on Drupal Views.
4 |
5 | This plugin lets you create new WP queries as widgets, and use shortcodes for to show queries in your content. Additionally, it allows you to override the way category and tag pages display without editing tempalte files.
6 |
7 | Supports:
8 |
9 | * Most post data, including meta fields
10 | * Taxonomy data
11 | * Advanced Custom Fields
12 | * Custom Content Type Manager
13 | * Some exposed filters
14 |
15 | Some examples of how you would use this plugin include:
16 |
17 | * Create a list posts with featured images
18 | * Create a list of pages or posts within a specific category or tag
19 | * Create an image gallery
20 | * Modify the way your category pages look
21 |
22 |
23 | ## Frequently Asked Questions
24 |
25 | ### How do I use query shortcodes?
26 |
27 | Easy, the code you're looking for is like this. `[query id=2]` , where the number 2 is the query id. When viewing the list of queries each one will have 2 options for shortcode. One that uses the query's id, and the other using the query's slug. I recommend using the query's slug for future maintainability.
28 |
29 | * By id: `[query id=2]`
30 | * By slug: `[query slug="my-query"]`
31 | * Customize WP_Query arguments: `[query id=2 args="posts_per_page=1&post_type=page"]`
32 | * Customize WP_Query arguments with contextual data: `[query id=1 args="author={{post:post_author}}&post_type={{post:post_type}}"]`
33 |
34 | ### What are overrides and how do I use them?
35 |
36 | Overrides allow you to alter the display and information given on category and tag archive pages.
37 |
38 | For a simple example, add a new query and chose the type `override`. Choose how you want the content to display, then examine the `Overrides` box in the center column. From there you can add taxonomies and terms this query will override.
39 |
40 |
41 | ### Other
42 |
43 | * [Meta Field Display Handler: Advanced Custom Fields](https://wordpress.org/support/topic/how-to-get-he-image-url-instead-of-image-id?replies=5#post-5411991 "Meta Field Display Handler: Advanced Custom Fields")
44 | * [Sort by Meta value](https://wordpress.org/support/topic/orderby-meta_value-1#post-6719953 "Sort a query by meta values")
45 | * [Meta Field Display Handler: Custom Content Type Manager](http://wordpress.org/support/topic/cant-put-php-code-into-rewrite-results-field?replies=4#post-5411970 "Meta Field Display Handler: Custom Content Type Manager")
46 | * [Custom field example](https://gist.github.com/daggerhart/10417309 "Custom field example")
47 | * [Field callback usage: wp_get_attachment_url](http://wordpress.org/support/topic/add-php-in-rewrite-output-of-this-field?replies=3#post-5480638 "Callback field usage")
48 | * [Field callback usage: the_tags](http://wordpress.org/support/topic/callback-field-plugin-version-1524?replies=1#post-5487515 "Callback field usage 2")
49 | * [Filter callback usage: ](https://wordpress.org/support/topic/filter-by-subquery?replies=3#post-6719945 "Filter Callback usage")
50 | * [Query Slideshow](http://wordpress.org/extend/plugins/query-slideshow/ "Query Slideshow") - Example of creating a custom style. Turn your queries into slideshows using jquery.cycle
51 |
52 |
--------------------------------------------------------------------------------
/admin/ajax.php:
--------------------------------------------------------------------------------
1 | $options['qw-query-options'],
17 | 'query_id' => $_POST['query_id'],
18 | );
19 | print theme( 'query_preview', $args );
20 | exit;
21 | break;
22 |
23 | case 'sort_form':
24 | $template = 'query_sort';
25 | $all = qw_all_sort_options();
26 | break;
27 |
28 | case 'field_form':
29 | $template = 'query_field';
30 | $all = qw_all_fields();
31 | break;
32 |
33 | case 'filter_form':
34 | $template = 'query_filter';
35 | $all = qw_all_filters();
36 | break;
37 |
38 | case 'override_form':
39 | $template = 'query_override';
40 | $all = qw_all_overrides();
41 | break;
42 |
43 | case 'sort_sortable':
44 | $template = 'query_sort_sortable';
45 | $all = qw_all_sort_options();
46 | break;
47 |
48 | case 'field_sortable':
49 | $template = 'query_field_sortable';
50 | $all = qw_all_fields();
51 | break;
52 |
53 | case 'filter_sortable':
54 | $template = 'query_filter_sortable';
55 | $all = qw_all_filters();
56 | break;
57 | }
58 |
59 | /*
60 | * Generate handler item forms and data
61 | */
62 | $handler = $_POST['handler'];
63 | $item = array();
64 |
65 | $hook_key = qw_get_hook_key( $all, $_POST );
66 | $item = $all[ $hook_key ];
67 | $item['name'] = $_POST['name'];
68 | $item['form_prefix'] = qw_make_form_prefix( $handler, $item['name'] );
69 |
70 | // handler item's form
71 | if ( isset( $item['form_callback'] ) && function_exists( $item['form_callback'] ) ) {
72 | ob_start();
73 | $item['form_callback']( $item );
74 | $item['form'] = ob_get_clean();
75 | } // provide template wrangler support
76 | else if ( isset( $item['form_template'] ) ) {
77 | $item['form'] = theme( $item['form_template'],
78 | array( $handler => $item ) );
79 | }
80 |
81 | $args = array(
82 | $handler => $item,
83 | );
84 | // weight for sortable handler items
85 | if ( isset( $_POST['next_weight'] ) ) {
86 | $args['weight'] = $_POST['next_weight'];
87 | }
88 |
89 | wp_send_json( array( 'template' => theme( $template, $args ) ) );
90 | }
91 |
92 | /*
93 | * Random data grabs
94 | */
95 | function qw_data_ajax() {
96 | if ( isset( $_POST['data'] ) ) {
97 | switch ( $_POST['data'] ) {
98 | case 'all_hooks':
99 | $query_id = isset( $_POST['queryId'] ) ? $_POST['queryId'] : NULL;
100 | $data = qw_edit_json( $query_id );
101 |
102 | wp_send_json( $data );
103 | break;
104 | }
105 | }
106 | }
--------------------------------------------------------------------------------
/admin/css/query-wrangler.css:
--------------------------------------------------------------------------------
1 |
2 | textarea.qw-meta-value {
3 | width: 500px;
4 | height: 120px;
5 | }
6 |
7 | #export-query {
8 | width: 94%;
9 | height: 600px;
10 | font-family: monospace;
11 | }
12 |
13 | #import-query {
14 | width: 94%;
15 | height: 300px;
16 | font-family: monospace;
17 | display: block;
18 | }
19 |
20 | #query-preview-controls {
21 | float: right;
22 | line-height: 40px;
23 | margin-right: 20px;
24 | }
25 |
26 | #query-preview-target {
27 | padding: 4px 8px;
28 | }
29 |
30 | .query-preview-inactive {
31 | background: transparent url('../images/loading.gif') -40px center no-repeat;
32 | }
33 |
34 | .query-preview-active {
35 | padding-left: 40px;
36 | background: transparent url('../images/loading.gif') left center no-repeat;
37 | }
38 |
39 | #query-preview-controls .qw-button {
40 | float: right;
41 | margin-left: 20px;
42 | }
43 |
44 | #query-preview {
45 | border: 1px solid #bbb;
46 | background: #fff;
47 | padding: 3px;
48 | }
49 |
50 | #preview-title {
51 | margin: 0px 0px 12px;
52 | padding: 0px 12px;
53 | background-color: #efefef;
54 | font-size: 1.1em;
55 | line-height: 2.8em;
56 | }
57 |
58 | #query-preview .qw-options-group-content {
59 | border: 1px solid #ddd;
60 | }
61 |
62 | .qw-button {
63 | display: block;
64 | float: left;
65 | border-color: #BBBBBB;
66 | color: #464646;
67 | -moz-box-sizing: content-box;
68 | border-radius: 11px 11px 11px 11px;
69 | border-style: solid;
70 | border-width: 1px;
71 | cursor: pointer;
72 | font-size: 12px !important;
73 | line-height: 13px;
74 | padding: 5px 8px;
75 | margin: 6px 0px;
76 | text-decoration: none;
77 | background: url("../images/white-grad.png") repeat-x scroll left top #F2F2F2;
78 | text-shadow: 0 1px 0 #FFFFFF;
79 | }
80 |
81 | .qw-create {
82 | margin-top: 12px;
83 | }
84 |
85 | label.qw-label {
86 | font-weight: bold;
87 | line-height: 1.8em;
88 | min-width: 120px;
89 | display: block;
90 | float: left;
91 | margin-right: 12px;
92 | }
93 |
94 | .qw-setting {
95 | padding-bottom: 12px;
96 | margin-bottom: 12px;
97 | border-bottom: 1px solid #bbb;
98 | }
99 |
100 | .qw-setting-header {
101 | display: block;
102 | padding: .4em .5em .4em 2em;
103 | }
104 |
105 | label.qw-query-checkbox,
106 | label.qw-field-checkbox,
107 | label.qw-filter-checkbox,
108 | label.qw-sort-checkbox {
109 | display: block;
110 | margin: 3px 0px;
111 | padding: 0px;
112 | }
113 |
114 | label.qw-query-checkbox input,
115 | label.qw-field-checkbox input {
116 | margin-right: 6px;
117 | }
118 |
119 | .qw-desc {
120 | padding-left: 24px;
121 | margin: 0px;
122 | }
123 |
124 | #qw-query-action-buttons {
125 | width: 93%;
126 | margin-left: 1%;
127 | }
128 |
129 | #query-actions {
130 | float: right;
131 | }
132 |
133 | .qw-weight-container {
134 | float: right;
135 | clear: right;
136 | margin-top: 16px;
137 | display: none;
138 | }
139 |
140 | .qw-remove {
141 | float: right;
142 | margin-left: 12px;
143 | }
144 |
145 | #qw-edit-query-form textarea {
146 | font-family: monospace;
147 | }
148 |
149 | #row-style-settings h3.qw-setting-header {
150 | padding-left: 0;
151 | }
152 |
153 | #row-style-settings .qw-setting-group {
154 | padding-left: 1em;
155 | padding-bottom: 1em;
156 | border-bottom: 1px solid #ddd;
157 | margin-bottom: .5em;
158 | }
159 | #row-style-settings .qw-query-content:last-of-type .qw-setting-group {
160 | border: none;
161 | }
162 |
163 | a.toplevel_page_query-wrangler {
164 | letter-spacing: -1px;
165 | }
166 |
167 | #qw-create {
168 | width: 30%;
169 | float: left;
170 | border: 1px solid #888;
171 | padding: 8px;
172 | -webkit-border-radius: 8px;
173 | -moz-border-radius: 8px;
174 | border-radius: 8px;
175 | }
176 |
177 | #qw-create-description {
178 | width: 50%;
179 | float: left;
180 | margin-left: 7%;
181 | }
182 |
183 | #qw-create-description div {
184 | border-left: 1px solid #bbb;
185 | border-right: 1px solid #bbb;
186 | border-bottom: 1px solid #bbb;
187 | background: #f6f6f6;
188 | margin-bottom: 6px;
189 | }
190 |
191 | #qw-create-description div p {
192 | padding: 8px;
193 | }
194 |
195 | #qw-create-description h3 {
196 | margin: 0px;
197 | padding: 8px;
198 | border-bottom: 1px solid #bbb;
199 | border-top: 1px solid #bbb;
200 | background-color: #efefef;
201 | }
202 |
203 | #qw-settings-page {
204 | border: 1px solid #444;
205 | padding: 1em 2em;
206 | margin-top: 1em;
207 | }
208 |
209 | .qw-hidden {
210 | display: none;
211 | }
212 |
213 | .qw-field-textarea {
214 | width: 60%;
215 | height: 180px;
216 | }
217 |
218 | .qw-text-long {
219 | width: 60%;
220 | }
221 |
222 | .qw-text-short {
223 | width: 48px;
224 | }
225 |
226 | .qw-field-wrapper {
227 | padding: 8px 0;
228 | }
229 |
230 | .qw-dialog .ui-dialog-titlebar-close span {
231 | margin: -8px 0 0 -8px;
232 | }
233 |
234 | .qw-dialog .ui-dialog-buttonset .ui-widget {
235 | display: inline-block;
236 | text-decoration: none;
237 | font-size: 13px;
238 | line-height: 1.5;
239 | min-height: 30px;
240 | margin: 0 0 0 6px;
241 | padding: 0 6px;
242 | cursor: pointer;
243 | border-width: 1px;
244 | border-style: solid;
245 | -webkit-appearance: none;
246 | border-radius: 3px;
247 | white-space: nowrap;
248 | box-sizing: border-box;
249 | background: #f1f1f1;
250 | border-color: #016087;
251 | color: #016087;
252 | }
253 | .qw-dialog .ui-dialog-buttonset .ui-widget:first-of-type {
254 | background: #0071a1;
255 | border-color: #0071a1;
256 | color: #fff;
257 | }
258 |
259 | .ui-autocomplete {
260 | z-index: 999999;
261 | }
262 |
--------------------------------------------------------------------------------
/admin/default_editors.php:
--------------------------------------------------------------------------------
1 | 'Nice Name for Theme',
10 |
11 | // callback for admin_init actions when theme is loaded
12 | // useful for loading js and css files
13 | 'init_callback' => 'my_init_callback',
14 | );
15 | */
16 | function qw_default_edit_themes( $themes ) {
17 | // $themes['picnic'] = array(
18 | // 'title' => 'Picnic',
19 | // 'init_callback' => 'qw_edit_theme_picnic',
20 | // );
21 | $themes['views'] = array(
22 | 'title' => 'Drupal Views',
23 | 'init_callback' => 'qw_edit_theme_views',
24 | );
25 |
26 | return $themes;
27 | }
28 |
29 | // add default fields to the hook filter
30 | add_filter( 'qw_edit_themes', 'qw_default_edit_themes', 0 );
31 |
32 | /**
33 | * load jquery ui style from cdn
34 | */
35 | function qw_load_jquery_ui_css_from_cdn() {
36 | global $wp_scripts;
37 | $ui = $wp_scripts->query( 'jquery-ui-core' );
38 | $protocol = is_ssl() ? 'https' : 'http';
39 | $url = "$protocol://ajax.googleapis.com/ajax/libs/jqueryui/{$ui->ver}/themes/smoothness/jquery-ui.min.css";
40 | wp_enqueue_style( 'jquery-ui-smoothness', $url, FALSE, NULL );
41 | }
42 |
43 | /*
44 | * Edit Theme: Drupal Views clone
45 | */
46 | function qw_edit_theme_views() {
47 | qw_load_jquery_ui_css_from_cdn();
48 |
49 | add_action( 'admin_head', 'qw_edit_theme_views_css' );
50 |
51 | if ( $_GET['page'] == 'query-wrangler' ) {
52 | add_action( 'admin_enqueue_scripts', 'qw_edit_theme_views_js' );
53 | }
54 | }
55 |
56 | // views css
57 | function qw_edit_theme_views_css() {
58 | print ' ';
59 | }
60 |
61 | // views js
62 | function qw_edit_theme_views_js() {
63 | wp_enqueue_script( 'qw-edit-theme-views',
64 | plugins_url( '/admin/editors/views/views.js', dirname( __FILE__ ) ),
65 | array(),
66 | QW_VERSION,
67 | TRUE );
68 | }
69 |
70 | /* --------------------------
71 | * Edit Theme: New editor with focus on division of "type" or choices
72 | */
73 | function qw_edit_theme_picnic() {
74 | qw_load_jquery_ui_css_from_cdn();
75 |
76 | add_action( 'admin_head', 'qw_edit_theme_picnic_css' );
77 |
78 | if ( $_GET['page'] == 'query-wrangler' ) {
79 | add_action( 'admin_enqueue_scripts', 'qw_edit_theme_picnic_js' );
80 | }
81 | }
82 |
83 | // css
84 | function qw_edit_theme_picnic_css() {
85 | print ' ';
86 | }
87 |
88 | // js
89 | function qw_edit_theme_picnic_js() {
90 | // my js script
91 | wp_enqueue_script( 'qw-edit-theme-new',
92 | plugins_url( '/admin/editors/picnic/picnic.js', dirname( __FILE__ ) ),
93 | array(),
94 | QW_VERSION,
95 | TRUE );
96 | }
97 |
--------------------------------------------------------------------------------
/admin/editors/picnic/picnic.css:
--------------------------------------------------------------------------------
1 |
2 | .qw-handler-item {
3 | background: white;
4 | padding: 12px;
5 | border: 1px solid #bbb;
6 | }
7 |
8 | .qw-add-new-items {
9 | background: white;
10 | padding: 12px;
11 | border: 1px solid #bbb;
12 | }
13 |
14 | .qw-add-items-controls {
15 | text-align: right;
16 | }
17 |
18 | .qw-handler-item {
19 | position: relative;
20 | }
21 |
22 | .qw-handler-item .group {
23 | display: none;
24 | }
25 |
26 | .qw-handler-item .group .description {
27 | margin: 12px 0;
28 | }
29 |
30 | .sortable-handle {
31 | background: transparent url('../../images/handle2.png') left top no-repeat;
32 | float: left;
33 | margin-right: 8px;
34 | width: 16px;
35 | height: 16px;
36 | cursor: row-resize;
37 | }
38 |
39 | .qw-add-items-controls {
40 | margin-bottom: 12px;
41 | }
42 |
43 | .qw-setting-header {
44 | padding: 0;
45 | color: #0074a2;
46 | font-weight: bold;
47 | display: block;
48 | cursor: pointer;
49 | }
50 |
51 | .qw-setting-header .details {
52 | color: #222;
53 | font-weight: normal;
54 | }
55 |
56 | .qw-setting-header .details:before {
57 | content: "- ";
58 | color: #222;
59 | }
60 |
61 | .qw-remove {
62 | position: absolute;
63 | top: 6px;
64 | right: 6px;
65 | }
66 |
67 | textarea.qw-field-textarea {
68 | width: 98%;
69 | height: 240px;
70 | }
71 |
72 | textarea.qw-field-textarea.blurred {
73 | height: 1.6em;
74 | width: 240px;
75 | }
76 |
77 | label.qw-field-checkbox {
78 | margin: 8px 0;
79 | }
--------------------------------------------------------------------------------
/admin/editors/picnic/picnic.js:
--------------------------------------------------------------------------------
1 | (
2 | function ( $ ) {
3 |
4 | QWPicnic = {
5 | // prevent queuing toggles
6 | is_toggling: false,
7 |
8 | /**
9 | *
10 | */
11 | init: function () {
12 | // sortable item lists
13 | QueryWrangler.sortables.init( '.qw-handler-items',
14 | '.qw-handler-item' );
15 | QueryWrangler.optionGroups.init();
16 |
17 | // freshen the ui js
18 | QWPicnic.refresh_ui();
19 |
20 | // open and close the 'add new' checkbox groups
21 | $( '.qw-add-item' ).click( function () {
22 | QWPicnic.toggle( $( this ).parent().next( '.qw-add-new-items' ) );
23 | } );
24 |
25 | // open and close single handler items
26 | $( '.qw-handler-items' ).on( 'click',
27 | '.qw-setting-header',
28 | function () {
29 | $( this ).parent().find( '.group' ).toggle();
30 | } );
31 |
32 | // delegated events
33 | $( '#qw-edit-query-form' )
34 | // focus and blur for textareas
35 | .on( 'focus', 'textarea.qw-field-textarea', function () {
36 | $( this ).removeClass( 'blurred' );
37 | } )
38 | .on( 'blur', 'textarea.qw-field-textarea', function () {
39 | $( this ).addClass( 'blurred' );
40 | } )
41 | // remove buttons
42 | .on( 'click', '.qw-remove', function () {
43 | $( this ).closest( '.qw-handler-item' ).remove();
44 | QueryWrangler.sortables.updateItemWeights();
45 | } );
46 |
47 | // get new handler items forms
48 | $( '.qw-add-items-submit' ).click( QWPicnic.addHandlerItems );
49 | },
50 |
51 | /**
52 | * Toggle an element if no other element is toggling
53 | *
54 | * @param element - the element to toggle
55 | */
56 | toggle: function ( element ) {
57 | if ( ! QWPicnic.is_toggling ) {
58 | QWPicnic.is_toggling = true;
59 |
60 | $( element ).toggle( 300, function () {
61 | QWPicnic.is_toggling = false;
62 | } );
63 | }
64 | },
65 |
66 | /**
67 | * Refresh the UI components on the page
68 | * @private
69 | */
70 | refresh_ui: function () {
71 | $( '.qw-add-new-items' ).hide();
72 | $( 'textarea.qw-field-textarea' ).addClass( 'blurred' );
73 |
74 | QueryWrangler.jsTitles.refresh();
75 | QueryWrangler.optionGroups.refresh();
76 | QueryWrangler.sortables.refresh();
77 | },
78 |
79 | /**
80 | * Loop through handler item checkboxes,
81 | * get the template for the item, and append to the list
82 | */
83 | addHandlerItems: function () {
84 | var handler = $( this ).data( 'handler-type' );
85 | var checkedboxes = $( this ).closest( '.qw-add-new-items' ).find( 'input[type=checkbox]:checked' );
86 |
87 | $.each( checkedboxes, function ( index, box ) {
88 | var $box = $( box );
89 | var item_type = $box.val();
90 | var hook_key = $box.next( 'input[type=hidden]' ).val();
91 |
92 | QueryWrangler.ajax.getHandlerItemTemplate( handler,
93 | item_type,
94 | hook_key,
95 | function ( results, original_handler ) {
96 | // append the results
97 | $( '#query-' + handler + 's' ).append( '
' + results.template + '
' );
98 |
99 | // uncheck the box
100 | $box.removeAttr( 'checked' );
101 |
102 | if ( handler == 'field' ) {
103 | // Update Field tokens
104 | QueryWrangler.generateFieldTokens();
105 | }
106 | } );
107 | } );
108 |
109 | QWPicnic.toggle( $( this ).closest( '.qw-add-new-items' ) );
110 | QWPicnic.refresh_ui();
111 | }
112 | };
113 |
114 |
115 | // init
116 | $( document ).ready( function () {
117 | QWPicnic.init();
118 | } );
119 |
120 | }
121 | )( jQuery );
--------------------------------------------------------------------------------
/admin/editors/views/views.css:
--------------------------------------------------------------------------------
1 | body.toplevel_page_query-wrangler,
2 | .ui-dialog {
3 | font-family: "Open Sans", sans-serif !important;
4 | }
5 |
6 | #display-style-settings .qw-setting-header,
7 | #row-style-settings .qw-setting-header {
8 | display: block;
9 | }
10 |
11 | #qw-options-forms,
12 | .qw-field-title,
13 | .qw-sort-filter-name,
14 | .qw-sort-sort-name,
15 | .qw-hidden,
16 | .qw-item-form .qw-setting-header,
17 | .qw-changes,
18 | .qw-remove,
19 | .qw-handler-item-form,
20 | .sortable-handle,
21 | .ui-dialog .ui-dialog-titlebar-close span.ui-button-text {
22 | display: none;
23 | }
24 |
25 | #qw-query-admin-options-wrap {
26 | margin: 6px;
27 | padding: 4px 8px;
28 | font-size: 1.1em;
29 | }
30 |
31 | #qw-list-title {
32 | width: 70%;
33 | }
34 |
35 | #qw-query-args,
36 | #qw-page-settings {
37 | padding: 0px;
38 | }
39 |
40 | #qw-show-arguments {
41 | margin-top: 32px;
42 | padding: 16px;
43 | border: 1px solid #bbb;
44 | }
45 |
46 | div.qw-handler-item-title {
47 | display: block;
48 | padding: 4px 8px;
49 | color: #21759B;
50 | cursor: pointer;
51 | border-bottom: 1px solid #ccc;
52 | margin-bottom: 1px;
53 | text-decoration: underline;
54 | font-weight: bold;
55 | }
56 |
57 | div.qw-handler-item-title span.details {
58 | display: inline-block;
59 | color: #444;
60 | font-weight: normal;
61 | text-decoration: none;
62 | }
63 |
64 | div.qw-handler-item-title span.details:before {
65 | content: ': ';
66 | }
67 |
68 | div.qw-handler-item-title:hover,
69 | div.qw-handler-item-title:hover span.qw-setting-value {
70 | background: #fff;
71 | color: #d54e21;
72 | }
73 |
74 | .qw-checkboxes {
75 | border: 1px solid #bbb;
76 | background: #fff;
77 | margin: 4px;
78 | padding: 6px;
79 | height: 100px;
80 | overflow-y: scroll;
81 | }
82 |
83 | .qw-query-admin-column {
84 | width: 30%;
85 | float: left;
86 | margin-right: 3%;
87 | margin-top: 6px;
88 | }
89 |
90 | .qw-query-admin-options {
91 | background: #f6f6f6;
92 | border: 1px solid #bbb;
93 | margin-bottom: 12px;
94 | }
95 |
96 | .qw-query-admin-options h4 {
97 | margin: 0px 0px 4px;
98 | padding: 0px 4px 0px 8px;
99 | line-height: 32px;
100 | border-bottom: 1px solid #444;
101 | font-family: HelveticaNeue-Light, "Helvetica Neue Light", "Helvetica Neue", sans-serif;
102 | background: linear-gradient(to top, #ECECEC, #F9F9F9) repeat scroll 0 0 #F1F1F1;
103 | }
104 |
105 | .qw-clear-gone {
106 | float: none;
107 | clear: both;
108 | line-height: 0px;
109 | height: 0px;
110 | font-size: 0px;
111 | }
112 |
113 | ul.qw-field-tokens-list li {
114 | font-weight: bold;
115 | }
116 |
117 | .qw-field-options {
118 | margin: 4px 0px;
119 | padding: 4px;
120 | }
121 |
122 | .qw-query-add-titles {
123 | float: right;
124 | background: transparent;
125 | }
126 |
127 | .qw-query-add-titles span {
128 | display: block;
129 | float: right;
130 | padding: 0px 6px;
131 | color: #21759B;
132 | cursor: pointer;
133 | line-height: 32px
134 | }
135 |
136 | .qw-query-add-titles span:hover {
137 | background: #fff;
138 | color: #d54e21;
139 | }
140 |
141 | span.qw-rearrange-title {
142 | }
143 |
144 | .qw-query-add-titles span.qw-add-title {
145 | border-right: 1px solid #bbb;
146 | border-left: 1px solid #bbb;
147 | }
148 |
149 | .qw-checkboxes {
150 | border: 1px solid #bbb;
151 | background: #fff;
152 | margin: 4px;
153 | padding: 6px;
154 | height: 86%;
155 | width: 60%;
156 | overflow-y: scroll;
157 | }
158 |
159 | .ui-dialog-content .qw-checkboxes {
160 | width: auto;
161 | }
162 |
163 | .qw-options-group {
164 | }
165 |
166 | .qw-options-group-title {
167 | }
168 |
169 | .qw-options-group-content {
170 | padding: 4px 20px;
171 | }
172 |
173 | .qw-field-textarea {
174 | width: 100%;
175 | height: 300px;
176 | }
177 |
178 | .qw-modified {
179 | background-color: #FFFFE0;
180 | }
181 |
182 | .qw-sortable {
183 | padding: .4em .5em;
184 | }
185 |
186 | li.qw-sortable span.qw-setting-value {
187 | color: #000;
188 | text-decoration: none;
189 | cursor: default;
190 | }
191 |
192 | .qw-sortable .qw-handler-item-title {
193 | border-bottom: none;
194 | }
195 |
196 | .ui-dialog .qw-weight {
197 | }
198 |
199 | .ui-dialog {
200 | z-index: 9991;
201 | top: 0px !important;
202 | margin-top: 58px;
203 | left: 8%;
204 | max-width: 85%;
205 | min-width: 85%;
206 | }
207 |
208 | .ui-dialog label {
209 | font-weight: bold;
210 | }
211 |
212 | .ui-widget-overlay {
213 | position: fixed;
214 | }
215 |
216 | .qw-disabled-add-handler {
217 | background: #eee;
218 | color: #666;
219 | }
220 |
221 | .qw-setting input[type=text] {
222 | width: 100%;
223 | max-width: 650px;
224 | }
225 |
226 | .qw-field-row,
227 | .qw-setting > div {
228 | margin-bottom: 18px !important;
229 | }
--------------------------------------------------------------------------------
/admin/images/handle2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daggerhart/query-wrangler/55e368ff94e63bcdc8ded5ad4701791fb78a6f6a/admin/images/handle2.png
--------------------------------------------------------------------------------
/admin/images/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daggerhart/query-wrangler/55e368ff94e63bcdc8ded5ad4701791fb78a6f6a/admin/images/loading.gif
--------------------------------------------------------------------------------
/admin/images/white-grad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daggerhart/query-wrangler/55e368ff94e63bcdc8ded5ad4701791fb78a6f6a/admin/images/white-grad.png
--------------------------------------------------------------------------------
/admin/js/jquery.unserialize-form.js:
--------------------------------------------------------------------------------
1 | // https://github.com/cthielen/unserialize-to-form/blob/master/jQuery.unserializeForm.js
2 | // Unserialize (to) form plugin
3 | // Version 1.0.4
4 | // Copyright (C) 2010-2011 Christopher Thielen, others (see ChangeLog below)
5 | // Dual-licensed under GPLv2 and the MIT open source licenses
6 |
7 | // Notes: Will recurse fieldsets and p tags as they are commonly used in forms.
8 | // Form elements must have a 'name' attribute
9 |
10 | // Usage: var s = $("form").serialize(); // save form settings
11 | // $("form").unserializeForm(s); // restore form settings
12 |
13 | // Alternatively, you can provide a second parameter to unserializeForm,
14 | // a callback which takes the element and the value, allowing you to build
15 | // dynamic forms via callback. If you return false, unserializeForm will
16 | // try to find and set the DOM element, otherwise, (on true) it assumes you've
17 | // handled that attribute and moves onto the next. E.g.:
18 | //
19 | // var callback = function(el, val) { $(el).val(val); };
20 |
21 | // See ChangeLog at end of file for history.
22 |
23 | (
24 | function ( $ ) {
25 | // takes a GET-serialized string, e.g. first=5&second=3&a=b and sets input tags (e.g. input name="first") to their values (e.g. 5)
26 | $.fn.unserializeForm = function ( _values, _callback ) {
27 | // this small bit of unserializing borrowed from James Campbell's "JQuery Unserialize v1.0"
28 | _values = _values.split( "&" );
29 |
30 | if ( _callback && typeof(
31 | _callback
32 | ) !== "function" ) {
33 | _callback = undefined; // whatever they gave us wasn't a function, act as though it wasn't given
34 | }
35 |
36 | var serialized_values = new Array();
37 | $.each( _values, function () {
38 | var properties = this.split( "=" );
39 |
40 | if ( (
41 | typeof properties[0] != 'undefined'
42 | ) && (
43 | typeof properties[1] != 'undefined'
44 | ) ) {
45 | serialized_values[properties[0].replace( /\+/g,
46 | " " )] = properties[1].replace( /\+/g, " " );
47 | }
48 | } );
49 |
50 | // _values is now a proper array with values[hash_index] = associated_value
51 | _values = serialized_values;
52 |
53 | // Start with all checkboxes and radios unchecked, since an unchecked box will not show up in the serialized form
54 | $( this ).find( ":checked" ).attr( "checked", false );
55 |
56 | // Iterate through each saved element and set the corresponding element
57 | for ( var key in _values ) {
58 | var el = $( this ).add( "input,select,textarea" ).find( "[name=\"" + unescape( key ) + "\"]" );
59 | var _value = unescape( _values[key] );
60 |
61 | if ( _callback == undefined ) {
62 | // No callback specified - assume DOM elements exist
63 | _unserializeFormSetValue( el, _value );
64 | } else {
65 | // Callback specified - don't assume DOM elements already exist
66 | var result = _callback.call( this, unescape( key ), _value );
67 |
68 | // If they return true, it means they handled it. If not, we will handle it.
69 | // Returning false then allows for DOM building without setting values.
70 | if ( result == false ) {
71 | // Try and find the element again as it may have just been created by the callback
72 | var el = $( this ).add( "input,select,textarea" ).find( "[name=\"" + unescape( key ) + "\"]" );
73 | _unserializeFormSetValue( el, _value );
74 | }
75 | }
76 | }
77 | }
78 | }
79 | )( jQuery );
80 |
81 | // Modified to use jQuery noConflict: jonathan
82 | function _unserializeFormSetValue( el, _value ) {
83 | if ( jQuery( el ).length > 1 ) {
84 | // Assume multiple elements of the same name are radio buttons
85 | jQuery.each( el, function ( i ) {
86 | if ( jQuery( this ).attr( "value" ) == _value ) {
87 | // Check it
88 | jQuery( this ).attr( "checked", true );
89 | } else {
90 | // Uncheck it
91 | jQuery( this ).attr( "checked", false );
92 | }
93 | } );
94 | } else {
95 | // Assume, if only a single element, it is not a radio button
96 | if ( jQuery( el ).attr( "type" ) == "checkbox" ) {
97 | jQuery( el ).attr( "checked", true );
98 | } else {
99 | jQuery( el ).val( _value );
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/admin/js/query-wrangler-list.js:
--------------------------------------------------------------------------------
1 | jQuery( document ).ready( function () {
2 |
3 | // delete confirm
4 | jQuery( '.qw-delete-query, .tablenav #doaction' ).click( function () {
5 | var ask = confirm( 'Are you sure you want to delete?' );
6 | if ( ask ) {
7 | return true;
8 | }
9 | else {
10 | return false;
11 | }
12 | } );
13 | } );
--------------------------------------------------------------------------------
/admin/templates/form-create.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | Choose the name and the type of your query.
4 |
5 |
6 |
7 |
38 |
39 |
40 |
41 |
Widget Queries
42 |
43 |
44 | The Query Wrangler comes with a reusable Wordpress Widget that an be
45 | places in sidebars.
46 | When you create a query of the this type, that query becomes
47 | selectable in the Widget settings.
48 |
49 |
50 |
51 |
Page Queries
52 |
53 |
54 | Currently disabled. For using Queries as a page, create a normal WP
55 | Page and place the query shortcode on it.
56 |
62 |
63 |
64 |
65 |
Override Queries
66 |
67 |
68 | An Override Query allows you to alter the way existing Wordpress
69 | pages such as Category and Tag pages display.
70 |
71 | This feature is still in beta development. It has only
72 | been tested with permalinks set to
73 | /%category%/%postname%/
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/admin/templates/form-editor.php:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 |
29 |
30 |
31 | get( 'live_preview'); ?>
32 | />
35 | Live Preview
36 |
37 |
38 |
Preview
39 |
40 |
41 |
Preview Query
42 |
43 |
This preview does not include your theme's CSS stylesheet.
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
58 |
64 |
70 |
76 |
82 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/admin/templates/form-export.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/admin/templates/form-import.php:
--------------------------------------------------------------------------------
1 |
23 |
--------------------------------------------------------------------------------
/admin/templates/form-settings.php:
--------------------------------------------------------------------------------
1 |
14 |
17 |
18 |
19 |
20 |
21 |
164 |
165 |
--------------------------------------------------------------------------------
/admin/templates/handler-filter.php:
--------------------------------------------------------------------------------
1 |
6 |
7 |
149 |
--------------------------------------------------------------------------------
/admin/templates/handler-override.php:
--------------------------------------------------------------------------------
1 |
6 |
7 |
46 |
--------------------------------------------------------------------------------
/admin/templates/handler-sort.php:
--------------------------------------------------------------------------------
1 |
6 |
7 |
46 |
--------------------------------------------------------------------------------
/admin/templates/page-admin-wrapper.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/admin/templates/preview-json.php:
--------------------------------------------------------------------------------
1 |
27 | To override a query's template, copy the corresponding template from the query-wrangler/templates folder to your theme folder (or THEME/templates) and rename it.
28 | " . print_r( qw_template_scan( $options ), 1 ) . " ";
29 |
30 | // php wp_query
31 | $php_wpquery = '$query = ' . var_export( $args, 1 ) . '; ';
32 | // args
33 | $args = "" . print_r( $args, TRUE ) . " ";
34 | // display
35 | $display = "" . htmlentities( print_r( $options['display'],
36 | TRUE ) ) . " ";
37 |
38 | $new_query = "" . htmlentities( print_r( $wp_query, TRUE ) ) . " ";
39 |
40 | $all_options = "" . htmlentities( print_r( $options, TRUE ) ) . " ";
41 |
42 | // return
43 | $preview = array(
44 | 'preview' => $preview,
45 | 'php_wpquery' => $php_wpquery,
46 | 'args' => $args,
47 | 'display' => $display,
48 | 'options' => $all_options,
49 | 'wpquery' => $new_query,
50 | 'templates' => $templates,
51 | );
52 |
53 | do_action_ref_array( 'qw_post_preview', array( &$preview ) );
54 |
55 | print json_encode( $preview );
56 |
57 | /*
58 | * Scan for all templates used by a single query
59 | */
60 | function qw_template_scan( $options ) {
61 | global $wpdb;
62 | $query_id = $options['meta']['id'];
63 | $slug = $options['meta']['slug'];
64 | $all_styles = qw_all_styles();
65 | $all_row_styles = qw_all_row_styles();
66 | $style = $all_styles[ $options['display']['style'] ];
67 | $row_style = $all_row_styles[ $options['display']['row_style'] ];
68 | //print_r($row_style);
69 | $output = array();
70 | $templates = array();
71 |
72 | //$options['display']['types']['this_instance']
73 |
74 | // start building theme arguments
75 | $wrapper_args = array(
76 | 'slug' => $slug,
77 | 'tw_action' => 'find_only',
78 | );
79 | // template with wrapper
80 | $templates['wrapper'] = theme( 'query_display_wrapper',
81 | $wrapper_args,
82 | TRUE );
83 |
84 | $style_settings = array();
85 | if ( isset( $options['display']['style_settings'][ $style['hook_key'] ] ) ) {
86 | $style_settings = $options['display']['style_settings'][ $style['hook_key'] ];
87 | }
88 | // setup row template arguments
89 | $template_args = array(
90 | 'template' => $style['template'],
91 | 'slug' => $slug,
92 | 'style' => $style['hook_key'],
93 | 'style_settings' => $style_settings,
94 | 'tw_action' => 'find_only',
95 | );
96 | // template the query rows
97 | $templates['style'] = theme( 'query_display_rows', $template_args );
98 |
99 | if ( $row_style['hook_key'] == "posts" ) {
100 |
101 | $row_style_settings = array( 'size' => 'complete' );
102 |
103 | if ( isset( $options['display'][ $row_style['hook_key'] . '_settings' ] ) ) {
104 | $row_style_settings = $options['display'][ $row_style['hook_key'] . '_settings' ];
105 | }
106 |
107 | $template_args = array(
108 | 'template' => 'query-' . $row_style_settings['size'],
109 | 'slug' => $slug,
110 | 'style' => $row_style_settings['size'],
111 | 'tw_action' => 'find_only',
112 | );
113 | $templates['row_style'] = theme( 'query_display_rows', $template_args );
114 | }
115 |
116 | if ( $row_style['hook_key'] == "fields" ) {
117 |
118 | $template_args = array(
119 | 'template' => 'query-field',
120 | 'slug' => $slug,
121 | 'style' => $options['display']['row_style'],
122 | 'tw_action' => 'find_only',
123 | );
124 | $templates['row_style'] = theme( 'query_display_rows', $template_args );
125 | }
126 |
127 | foreach ( $templates as $k => $template ) {
128 | foreach ( $template['suggestions'] as $suggestion ) {
129 | if ( isset( $template['found_suggestion'] ) && $suggestion == $template['found_suggestion'] ) {
130 | $output[ $k ][] = '' . $suggestion . ' ';
131 | } else {
132 | $output[ $k ][] = $suggestion;
133 | }
134 | }
135 |
136 | // see if this is the default template
137 | if ( isset( $template['found_path'] ) ) {
138 | if ( stripos( $template['found_path'], QW_PLUGIN_DIR ) !== FALSE ) {
139 | $output[ $k ]['found'] = '(default) ' . $template['found_path'] . ' ';
140 | } else {
141 | $output[ $k ]['found'] = '' . $template['found_path'] . ' ';
142 | }
143 | }
144 | //$output[$k]['template'] = $template;
145 | }
146 |
147 | return $output;
148 | }
--------------------------------------------------------------------------------
/docs/examples/field.md:
--------------------------------------------------------------------------------
1 | # Example Query Wrangler field
2 |
3 | ### Simple Field
4 |
5 | This field will output: "This post is authored by: (the author's name)";
6 |
7 | ```php
8 | add_filter('qw_fields', 'custom_qw_field');
9 |
10 | function custom_qw_field($fields)
11 | {
12 | $fields['custom_qw_field'] = array(
13 | 'title' => 'Custom QW Field',
14 | 'description' => 'Just an example of making your own custom fields with callbacks.',
15 | 'output_callback' => 'get_custom_qw_field',
16 | 'output_arguments' => true, // this provides the $post and $field parameters to the output_callback
17 | );
18 | return $fields;
19 | }
20 |
21 | /*
22 | * This is just a random custom function that returns some html.
23 | *
24 | * @param object $this_post - the WP post object
25 | * @param array $field - the QW field. Useful if a field has custom settings (not shown in this example).
26 | * @param array $tokens - Available output values from other fields
27 | */
28 | function get_custom_qw_field($this_post, $field, $tokens){
29 | // since this field is executed with "the loop", you can use most WP "template tags" as normal
30 | // you can do anything you need here, as long as you return (not echo) the HTML you want to display.
31 |
32 | $author = get_the_author();
33 | // this would provide the same results
34 | // $author = get_the_author_meta('display_name', $this_post->post_author);
35 |
36 | return "This post is authored by: ".$author;
37 | }
38 | ```
39 |
40 | ### Field with settings
41 |
42 | This field has a setting that changes the output. The user can choose to show the post title, or the post status.
43 |
44 | ```php
45 | // hook
46 | add_filter('qw_fields', 'qw_field_example');
47 |
48 | /*
49 | * My new field definition
50 | */
51 | function qw_field_example($fields)
52 | {
53 | // new field
54 | $fields['example_field'] = array(
55 |
56 | // title displayed to query-wrangler user
57 | 'title' => 'Example: Field',
58 |
59 | // description on the field form
60 | 'description' => 'Just a useful description of this field',
61 |
62 | // optional) callback for outputting a field, must return the results
63 | 'output_callback' => 'qw_field_example_output',
64 |
65 | // (optional) where or not to pass $post and $field into the output_callback
66 | // useful for custom functions
67 | 'output_arguments' => true,
68 |
69 | // (optional) callback function for field forms
70 | 'form_callback' => 'qw_field_example_form_callback',
71 | );
72 | return $fields;
73 | }
74 |
75 | /*
76 | * Example output callback with output_arguments = true
77 | *
78 | * @param $post The WP $post object
79 | * @param $field This field's settings and values. Values stored in $field['values']
80 | */
81 | function qw_field_example_output($post, $field){
82 | $output = '';
83 | // adjust output according to my custom field settings
84 | if ($field['values']['my_setting'] == 'title'){
85 | $output = $post->post_title;
86 | }
87 | else if ($field['values']['my_setting'] == 'status'){
88 | $output = $post->post_status;
89 | }
90 | return $output;
91 | }
92 |
93 | /*
94 | * Provide a settings form for this field
95 | *
96 | * Output is expected of all forms, because they are executed within a buffer
97 | *
98 | * @param $field - this field's settings and values
99 | Values stored in $field['values']
100 | */
101 | function qw_field_example_form_callback($field)
102 | {
103 | // retrieve the value from the field for retaining settings values
104 | $value = $field['values']['my_setting'];
105 | ?>
106 |
107 | >Show Post Title
108 | >Show Post Status
109 |
110 | 'Coauthor Posts Links',
125 | 'description' => 'Outputs the co-authors display names, with links to their posts.',
126 | // If the coauthors plugin didn't echo the data by default we wouldn't even need this custom function,
127 | // we could have set the output_callback to 'coauthors_posts_links' instead.
128 | 'output_callback' => 'get_coauthors_posts_links',
129 | );
130 | return $fields;
131 | }
132 |
133 | /*
134 | * http://vip.wordpress.com/documentation/incorporate-co-authors-plus-template-tags-into-your-theme/#available-template-tags
135 | */
136 | function get_coauthors_posts_links(){
137 | return coauthors_posts_links(null,null,null,null,false);
138 | }
139 | ````
--------------------------------------------------------------------------------
/docs/examples/filter.md:
--------------------------------------------------------------------------------
1 | # Example Query Wrangler filter
2 |
3 | This filter doesn't really accomplish anything. It just places some random key/value pairs in the args sent to WP_Query().
4 |
5 | ```php
6 | 'Example: Filter',
19 |
20 | // help text for the user
21 | 'description' => 'Description of this filter',
22 |
23 | // (optional) the query argument key
24 | // if doesn't exist, defaults to the hook_key.
25 | // if confused what this is for, don't use this
26 | 'type' => 'filter_type',
27 |
28 | // ! This or a form_template must be used
29 | // * (optional) callback for form
30 | 'form_callback' => 'qw_filter_example_form_callback',
31 |
32 | // * (optional) template wrangler theme function or template file
33 | 'form_template' => 'my_tw_template_hook',
34 |
35 | // (optional) generate_args callback
36 | // determines how form data becomes WP_Query arguments
37 | // defaults to form key as WP_Query argument key
38 | 'query_args_callback' => 'qw_filter_example_query_args',
39 |
40 | // (optional) the form exposed to a user above the query
41 | 'exposed_form' => 'qw_filter_example_exposed_form',
42 |
43 | // (optional) process the exposed filter's values into the query args
44 | 'exposed_process' => 'qw_filter_example_exposed_process',
45 |
46 | // (optional) a form for gather settings for the exposed filter
47 | 'exposed_settings_form' => 'qw_filter_example_exposed_settings_form',
48 | );
49 | return $filters;
50 | }
51 |
52 | /*
53 | * Example of custom filter form.
54 | *
55 | * @param $filter - This filter's settings and saved values
56 | * Values stored in $filter['values']
57 | */
58 | function qw_filter_example_form_callback($filter)
59 | { ?>
60 | My filter setting
61 | ' />
64 |
94 |
97 | 'Example: Sort Option',
21 |
22 | // some help text for the user about how this sort option works
23 | 'description' => 'A description of how this sort option works.',
24 |
25 | // (optional) This is the value of the WP_Query argument orderby_key
26 | // defaults to: the hook_key
27 | // $args[$sort['orderby_key']] = $sort['type'];
28 | 'type' => 'wp_query_argument_key',
29 |
30 | // (optional) the WP_Query argument key equivalent to WP_Query's 'orderby'
31 | // defaults to: 'orderby'
32 | 'orderby_key' => 'my_orderby_key',
33 |
34 | // (optional) the WP_Query argument key equivalent to WP_Query's 'order'
35 | // defaults to: 'order'
36 | 'order_key' => 'my_order_key',
37 |
38 | // (optional) order options provided in a select menu
39 | // defaults to: below values
40 | 'order_options' => array(
41 | 'ASC' => 'Ascending',
42 | 'DESC' => 'Descending',
43 | ),
44 |
45 | // (optional) a custom callback function for placing form values into a WP_Query as arguments
46 | // defaults to:
47 | // $args[$sort['orderby_key']] = $sort['type'];
48 | // $args[$sort['order_key']] = $sort['order_value'];
49 | 'query_args_callback' => 'qw_sort_example_query_args',
50 |
51 | // (optional) a custom callback for sort options forms
52 | // if callback and template both aren't set,
53 | // defaults to: 'qw_sorts_default_form_callback'
54 | 'form_callback' => 'my_sort_option_form_callback',
55 |
56 | // (optional) a template wrangler form template
57 | 'form_template' => 'my_tw_form_template',
58 | );
59 | return $sort_options;
60 | }
61 |
62 | /*
63 | * Doing this is so simple that qw will do it for you if you don't provide a callback.
64 | * But this is what it looks like if you were to do it yourself
65 | *
66 | * @param &$args - The WP_Query arguments we are building
67 | * @param $sort - This sort's settings and values
68 | Values stored in $sort['values']
69 | */
70 | function qw_sort_example_query_args(&$args, $sort){
71 | $args[$sort['orderby_key']] = $sort['type'];
72 | $args[$sort['order_key']] = $sort['values']['order_value'];
73 | }
74 | ````
75 |
--------------------------------------------------------------------------------
/includes/basics/display_title.php:
--------------------------------------------------------------------------------
1 | 'Display Title',
11 | 'option_type' => 'display',
12 | 'description' => 'The title above the query page or widget',
13 | 'form_callback' => 'qw_basic_display_title_form',
14 | 'weight' => 0,
15 | );
16 |
17 | return $basics;
18 | }
19 |
20 | function qw_basic_display_title_form( $basic, $display ) {
21 | $title = isset( $display['title'] ) ? $display['title'] : "";
22 | ?>
23 |
24 |
28 | 'Empty Text',
11 | 'option_type' => 'display',
12 | 'description' => 'The content placed here will appear if the query has no results.',
13 | 'form_callback' => 'qw_basic_empty_form',
14 | 'weight' => 0,
15 | );
16 |
17 | return $basics;
18 | }
19 |
20 |
21 | function qw_basic_empty_form( $basic, $display ) {
22 | $empty = isset( $display['empty'] ) ? $display['empty'] : "";
23 | ?>
24 |
25 |
27 | 'Footer',
12 | 'option_type' => 'display',
13 | 'description' => 'The content placed here will appear below the resulting query.',
14 | 'form_callback' => 'qw_basic_footer_form',
15 | 'weight' => 0,
16 | );
17 |
18 | return $basics;
19 | }
20 |
21 | function qw_basic_footer_form( $basic, $display ) {
22 | $footer = isset( $display['footer'] ) ? $display['footer'] : "";
23 | $settings = !empty( $display['footer_settings'] ) ? $display['footer_settings'] : [];
24 | ?>
25 |
26 |
28 |
29 |
30 |
36 | >
37 |
38 |
39 |
40 | posts) ) {
48 | $options['meta']['footer'] = '';
49 | }
50 |
51 | return $options;
52 | }, 0, 2 );
53 |
--------------------------------------------------------------------------------
/includes/basics/header.php:
--------------------------------------------------------------------------------
1 | 'Header',
11 | 'option_type' => 'display',
12 | 'description' => 'The content placed here will appear above the resulting query.',
13 | 'form_callback' => 'qw_basic_header_form',
14 | 'weight' => 0,
15 | );
16 |
17 | return $basics;
18 | }
19 |
20 | function qw_basic_header_form( $basic, $display ) {
21 | $header = isset( $display['header'] ) ? $display['header'] : "";
22 | $settings = !empty( $display['header_settings'] ) ? $display['header_settings'] : [];
23 | ?>
24 |
25 |
27 |
28 |
29 |
35 | >
36 |
37 |
38 |
39 | posts) ) {
47 | $options['meta']['header'] = '';
48 | }
49 |
50 | return $options;
51 | }, 0, 2 );
52 |
--------------------------------------------------------------------------------
/includes/basics/ignore_sticky_posts.php:
--------------------------------------------------------------------------------
1 | 'Ignore Sticky Posts',
12 | 'option_type' => 'args',
13 | 'description' => 'Do not enforce stickiness in the resulting query.',
14 | 'form_callback' => 'qw_basic_ignore_sticky_posts_form',
15 | );
16 |
17 | return $basics;
18 | }
19 |
20 | function qw_basic_ignore_sticky_posts_form( $basic, $args ) {
21 | $value = isset( $args['ignore_sticky_posts'] ) ? $args['ignore_sticky_posts'] : 0;
22 | ?>
23 |
24 |
28 | value="1"/>
29 |
30 |
31 | 'Offset',
12 | 'option_type' => 'args',
13 | 'description' => 'Number of post to skip, or pass over. For example, if this field is 3, the first 3 items will be skipped and not displayed.',
14 | 'form_callback' => 'qw_basic_offset_form',
15 | 'weight' => 0,
16 | );
17 |
18 | return $basics;
19 | }
20 |
21 | function qw_basic_offset_form( $basic, $args ) {
22 | ?>
23 |
24 |
28 | 'Page path',
11 | 'option_type' => 'display',
12 | 'description' => 'The path or permalink you want this page to use. Avoid using spaces and capitalization for best results.',
13 | 'form_callback' => 'qw_basic_page_path_form',
14 | 'query_display_types' => array( 'page', ),
15 | 'weight' => 0,
16 | );
17 |
18 | return $basics;
19 | }
20 |
21 | function qw_basic_page_path_form( $basic, $display ) {
22 | $query_page_path = isset( $display['page']['path'] ) ? $display['page']['path'] : "";
23 | ?>
24 |
25 |
30 | 'Page Template',
11 | 'option_type' => 'display',
12 | 'description' => 'Select which page template should wrap this query page.',
13 | 'form_callback' => 'qw_basic_page_template_form',
14 | 'query_display_types' => array( 'page', 'override' ),
15 | 'weight' => 0,
16 | );
17 |
18 | return $basics;
19 | }
20 |
21 | function qw_basic_page_template_form( $basic, $display ) {
22 | $page_templates = get_page_templates();
23 | ?>
24 |
27 | None - Allow theme to determine template
28 |
29 | Default - index.php
30 | $file ) {
32 | $selected = ( $file == $display['page']['template-file'] ) ? 'selected="selected"' : '';
33 | ?>
34 | >
36 |
37 |
38 |
41 |
42 | 'Posts Status',
15 | 'option_type' => 'args',
16 | 'description' => 'Select the post status of the items displayed.',
17 | 'form_callback' => 'qw_basic_post_status_form',
18 | 'weight' => 0,
19 | );
20 |
21 | return $basics;
22 | }
23 |
24 | /*
25 | * Post statuses as a hook for contributions
26 | */
27 | function qw_default_post_statuses( $post_statuses ) {
28 | $post_statuses['publish'] = array(
29 | 'title' => 'Published',
30 | );
31 | $post_statuses['pending'] = array(
32 | 'title' => 'Pending',
33 | );
34 | $post_statuses['draft'] = array(
35 | 'title' => 'Draft',
36 | );
37 | $post_statuses['future'] = array(
38 | 'title' => 'Future (Scheduled)',
39 | );
40 | $post_statuses['trash'] = array(
41 | 'title' => 'Trashed',
42 | );
43 | $post_statuses['private'] = array(
44 | 'title' => 'Private',
45 | );
46 | $post_statuses['any'] = array(
47 | 'title' => 'Any',
48 | );
49 |
50 | return $post_statuses;
51 | }
52 |
53 | function qw_basic_post_status_form( $basic, $args ) {
54 | $post_statuses = qw_all_post_statuses();
55 | ?>
56 |
57 |
60 | $post_status ) { ?>
62 | >
66 |
67 |
68 |
71 |
72 | 'Posts Per Page',
12 | 'option_type' => 'args',
13 | 'description' => 'Number of posts to show per page. Use -1 to display all results.',
14 | 'form_callback' => 'qw_basic_posts_per_page_form',
15 | 'weight' => 0,
16 | );
17 |
18 | return $basics;
19 | }
20 |
21 | function qw_basic_posts_per_page_form( $basic, $args ) {
22 | $posts_per_page = isset( $args['posts_per_page'] ) ? $args['posts_per_page'] : 5;
23 | ?>
24 |
25 |
29 | 'Row Style',
20 | 'option_type' => 'display',
21 | 'description' => 'How should each post in this query be presented?',
22 | 'form_callback' => 'qw_basic_display_row_style_form',
23 | 'weight' => 0,
24 | );
25 |
26 | return $basics;
27 | }
28 |
29 | /*
30 | * Default Row Styles
31 | */
32 | function qw_default_row_styles( $row_styles ) {
33 | $row_styles['posts'] = array(
34 | 'title' => 'Posts',
35 | 'settings_callback' => 'qw_row_style_posts_settings',
36 | 'settings_key' => 'post',
37 | );
38 | $row_styles['fields'] = array(
39 | 'title' => 'Fields',
40 | 'settings_callback' => 'qw_row_style_fields_settings',
41 | 'settings_key' => 'field',
42 | );
43 | $row_styles['template_part'] = array(
44 | 'title' => 'Template Part',
45 | 'settings_callback' => 'qw_row_style_template_part_settings',
46 | 'settings_key' => 'template_part',
47 | );
48 |
49 | return $row_styles;
50 | }
51 |
52 |
53 | /*
54 | * Default Row 'Posts' Styles
55 | */
56 | function qw_default_row_complete_styles( $row_complete_styles ) {
57 | $row_complete_styles['complete'] = array(
58 | 'title' => 'Complete Post',
59 | );
60 | $row_complete_styles['excerpt'] = array(
61 | 'title' => 'Excerpt',
62 | );
63 |
64 | return $row_complete_styles;
65 | }
66 |
67 | function qw_basic_display_row_style_form( $basic, $display ) {
68 | $row_styles = qw_all_row_styles();
69 | ?>
70 |
71 |
74 | $row_style ) { ?>
76 | >
80 |
81 |
82 |
85 |
86 |
87 |
88 | Some Row Styles have additional settings.
89 |
90 | $row_style ) {
92 | if ( isset( $row_style['settings_callback'] ) && function_exists( $row_style['settings_callback'] ) ) {
93 | $row_style['values'] = ( isset( $row_style['settings_key'] ) && isset( $display[ $row_style['settings_key'] . '_settings' ] ) ) ? $display[ $row_style['settings_key'] . '_settings' ] : array();
94 | ?>
95 |
98 |
100 |
101 |
102 |
104 |
105 |
106 |
110 |
111 |
116 | Select the amount of the post to be shown.
117 |
119 | >
123 | Complete Post
124 |
125 | >
129 | Excerpt
130 |
131 |
132 |
144 |
145 | Group by field
146 |
148 | - None -
149 | $field ) {
152 | ?>
153 | >
156 |
160 |
161 |
162 |
163 |
166 |
167 |
171 | > - Strip tags from Group by field
172 |
173 |
174 |
184 | Path:
185 |
188 |
189 | Name:
190 |
193 | 'Template Style',
13 | 'option_type' => 'display',
14 | 'description' => 'How should this query be styled?',
15 | 'form_callback' => 'qw_basic_display_style_form',
16 | 'weight' => 0,
17 | );
18 |
19 | return $basics;
20 | }
21 |
22 | /*
23 | * All Field Styles and settings
24 | *
25 | * @return array Field Styles
26 | */
27 | function qw_template_styles_default( $styles ) {
28 | $styles['unformatted'] = array(
29 | 'title' => 'Unformatted',
30 | 'template' => 'query-unformatted',
31 | 'default_path' => QW_PLUGIN_DIR, // do not include last slash
32 | );
33 | $styles['unordered_list'] = array(
34 | 'title' => 'Unordered List',
35 | 'template' => 'query-unordered_list',
36 | 'default_path' => QW_PLUGIN_DIR, // do not include last slash
37 | );
38 | $styles['ordered_list'] = array(
39 | 'title' => 'Ordered List',
40 | 'template' => 'query-ordered_list',
41 | 'default_path' => QW_PLUGIN_DIR, // do not include last slash
42 | );
43 | $styles['table'] = array(
44 | 'title' => 'Table',
45 | 'template' => 'query-table',
46 | 'default_path' => QW_PLUGIN_DIR, // do not include last slash
47 | );
48 |
49 | return $styles;
50 | }
51 |
52 | function qw_basic_display_style_form( $basic, $display ) {
53 | $styles = qw_all_styles();
54 | ?>
55 |
56 |
59 | $style ) {
62 | ?>
63 | >
67 |
68 |
69 |
72 |
73 |
74 |
75 |
76 | $style ) {
78 | if ( isset( $style['settings_callback'] ) && function_exists( $style['settings_callback'] ) ) {
79 | $style['values'] = $display[ $style['settings_key'] ];
80 | ?>
81 |
83 |
86 |
87 |
88 |
89 |
90 |
91 |
95 |
96 | 'Wrapper Classes',
11 | 'option_type' => 'display',
12 | 'description' => 'The CSS class names will be added to the query. This enables you to use specific CSS code for each query. You may define multiples classes separated by spaces.',
13 | 'form_callback' => 'qw_basic_wrapper_classes_form',
14 | 'weight' => 0,
15 | );
16 |
17 | return $basics;
18 | }
19 |
20 | function qw_basic_wrapper_classes_form( $basic, $display ) {
21 | $wrapper_classes = isset( $display['wrapper-classes'] ) ? $display['wrapper-classes'] : "";
22 | ?>
23 |
24 |
28 | is_main_query() ) {
36 | return;
37 | }
38 |
39 | $overrides = qw_all_overrides();
40 |
41 | // Loop through all override types and let them look for their own active overrides
42 | foreach ( $overrides as $override ) {
43 | if ( isset( $override['get_query_callback'] ) && is_callable( $override['get_query_callback'] ) ) {
44 |
45 | // override get_query_callbacks should return a QW_Query object
46 | $qw_query = call_user_func( $override['get_query_callback'],
47 | $wp_query );
48 |
49 | if ( $qw_query && is_a( $qw_query, 'QW_Query' ) ) {
50 | $this->override_query = $qw_query;
51 |
52 | // go ahead and correct pagination
53 | $wp_query->set( 'posts_per_page',
54 | $qw_query->data['args']['posts_per_page'] );
55 |
56 | // !first one wins
57 | break;
58 | }
59 | }
60 | }
61 | }
62 |
63 | /**
64 | * WordPress action 'wp'
65 | *
66 | * After the main query has been executed but no output has been generated,
67 | * execute an override query that was found during pre_get_posts
68 | *
69 | * @param $wp
70 | */
71 | function action_wp( $wp ) {
72 | if ( $this->override_query ) {
73 | // execute the override
74 | $this->execute( $this->override_query );
75 | }
76 | }
77 |
78 | /**
79 | * Inject our $qw_query into the global $wp_query as a single post. That
80 | * way
81 | * we have full control over the output of the content, while not
82 | * interrupting the theme's template hierarchy.
83 | *
84 | * @param $qw_query
85 | */
86 | function execute( $qw_query ) {
87 | // process the query and get the output
88 | $themed_query = $qw_query->execute()->output;
89 |
90 | // The title of the query
91 | $title = ( $qw_query->options['display']['title'] ) ? $qw_query->options['display']['title'] : $qw_query->name;
92 |
93 | // Make the post object
94 | $faux_post = new stdClass();
95 | $faux_post->ID = -42; // Arbitrary post id
96 | $faux_post->post_title = $title;
97 | $faux_post->post_content = $themed_query;
98 | $faux_post->post_status = 'publish';
99 | $faux_post->post_type = 'qw-override';
100 | $faux_post->post_category = array( 'uncategorized' );
101 | $faux_post->post_excerpt = '';
102 | $faux_post->ancestors = array();
103 |
104 | // hack the gibson
105 | global $wp_query;
106 | $wp_query->posts = array( $faux_post );
107 | // $wp_query->post = $faux_post;
108 | $wp_query->found_posts = 1;
109 | $wp_query->post_count = 1;
110 |
111 | // allow for page templates
112 | if ( $qw_query->options['display']['page']['template-file'] !== '__none__' ) {
113 | add_filter( 'template_include', array( $this, 'hijack_template' ), 99 );
114 | }
115 | }
116 |
117 | /**
118 | * Take over the page with a given template file.
119 | * Include the template and exit immediately
120 | *
121 | * @param $template_file
122 | *
123 | * @return string
124 | */
125 | function hijack_template( $template_file ) {
126 | $template_file = locate_template( $this->override_query->options['display']['page']['template-file'] );
127 |
128 | if ( ! file_exists( $template_file ) ) {
129 | $template_file = locate_template( qw_default_template_file() );
130 | }
131 |
132 | return $template_file;
133 | }
134 | }
--------------------------------------------------------------------------------
/includes/class-qw-query.php:
--------------------------------------------------------------------------------
1 | row = $query;
48 |
49 | // copy all the db row info
50 | $this->id = $id;
51 | $this->name = $query->name;
52 | $this->slug = $query->slug;
53 | $this->type = $query->type;
54 | $this->path = $query->path;
55 | $this->data = $query->data;
56 | }
57 | else {
58 | // new query object with default values
59 | $this->is_new = TRUE;
60 | $this->data = qw_default_query_data();
61 | $this->row['data'] = $this->data;
62 | }
63 | }
64 |
65 | /**
66 | * Execute the entire query process
67 | *
68 | * @return mixed|string|void
69 | */
70 | function execute() {
71 | $this
72 | ->process_options()
73 | ->execute_query()
74 | ->theme_query();
75 |
76 | return $this;
77 | }
78 |
79 | /**
80 | * Allow array of option values to replace existing qw_query options.
81 | * -- Should be executed before process_options()
82 | *
83 | * @param $options_override
84 | *
85 | * @return $this
86 | */
87 | function override_options( $options_override, $full_override = FALSE ) {
88 | if ( $full_override ) {
89 | $this->data = $options_override;
90 | }
91 | else {
92 | // combine data and options_override to get $options
93 | $this->data = array_replace_recursive( (array) $this->data, $options_override );
94 | }
95 |
96 | return $this;
97 | }
98 |
99 | /**
100 | * Process the row->data array into options and args
101 | *
102 | * @return $this
103 | */
104 | function process_options() {
105 | // get the query options
106 | if ( ! $this->options ) {
107 | $this->options = $this->data;
108 |
109 | // build query_details
110 | $this->options['meta'] = array(
111 | 'id' => $this->id,
112 | 'slug' => $this->slug,
113 | 'name' => $this->name,
114 | 'type' => $this->type,
115 | 'pagination' => isset( $this->options['display']['page']['pager']['active'] ) ? 1 : 0,
116 | 'header' => $this->options['display']['header'],
117 | 'footer' => $this->options['display']['footer'],
118 | 'empty' => $this->options['display']['empty'],
119 | );
120 | }
121 |
122 | // get formatted query arguments
123 | if ( ! $this->args ) {
124 | $this->args = qw_generate_query_args( $this->options );
125 | }
126 |
127 | return $this;
128 | }
129 |
130 | /**
131 | * Create the WP_Query()
132 | */
133 | function execute_query() {
134 | $this->args = apply_filters( 'qw_pre_query', $this->args, $this->options );
135 |
136 | // set the new query
137 | $this->wp_query = new WP_Query( $this->args );
138 |
139 | return $this;
140 | }
141 |
142 | /**
143 | * Template the qw_query output
144 | */
145 | function theme_query() {
146 | // pre_render hook
147 | $this->options = apply_filters( 'qw_pre_render', $this->options, $this->wp_query );
148 |
149 | // get the themed content
150 | $this->output = qw_template_query( $this->wp_query, $this->options );
151 |
152 | return $this;
153 | }
154 |
155 | /**
156 | * Simple wrapper for wp_reset_postdata()
157 | */
158 | function reset_postdata() {
159 | wp_reset_postdata();
160 |
161 | return $this;
162 | }
163 |
164 | /**
165 | * Add a new handler item to the query
166 | *
167 | * @param $handler_type
168 | * @param $item_type
169 | * @param $values
170 | *
171 | * @return $this
172 | */
173 | function add_handler_item( $handler_type, $item_type, $values ) {
174 | $all_handlers = qw_all_handlers();
175 |
176 | if ( isset( $all_handlers[ $handler_type ]['all_items'][ $item_type ] ) ) {
177 | $handler = $all_handlers[ $handler_type ];
178 | $handler_item = $all_handlers[ $handler_type ]['all_items'][ $item_type ];
179 |
180 | // get existing items on the query
181 | $existing_items = array();
182 | if ( is_callable( $handler['data_callback'] ) ) {
183 | $existing_items = call_user_func( $handler['data_callback'],
184 | $this->data );
185 | }
186 |
187 | // determine the weight and name of the new item based on
188 | // items that already exist in the query->data
189 | $weight = 0;
190 | $instances = 0;
191 | foreach ( $existing_items as $name => $existing_item ) {
192 | $weight += 1;
193 |
194 | if ( $existing_item['type'] == $handler_item['type'] ) {
195 | $instances += 1;
196 | }
197 | }
198 |
199 | // create our new item
200 | $new_item = array(
201 | 'hook_key' => $handler_item['hook_key'],
202 | 'type' => $handler_item['type'],
203 | 'name' => ( $instances > 0 ) ? $handler_item['type'] . '_' . $instances : $handler_item['type'],
204 | 'weight' => $weight,
205 | );
206 |
207 | // merge in values
208 | $new_item = array_replace_recursive( $new_item, $values );
209 |
210 | $this->set_handler_item( $handler_type, $new_item['name'], $new_item );
211 | }
212 |
213 | return $this;
214 | }
215 |
216 | /**
217 | * Set the value of a specific handler item
218 | *
219 | * @param $handler_type
220 | * @param $key
221 | * @param $value
222 | *
223 | * @return $this
224 | */
225 | function set_handler_item( $handler_type, $key, $value ) {
226 | switch ( $handler_type ) {
227 | case 'filter':
228 | $this->data['args']['filters'][ $key ] = $value;
229 | break;
230 |
231 | case 'field':
232 | $this->data['display']['field_settings']['fields'][ $key ] = $value;
233 | break;
234 |
235 | case 'sort':
236 | $this->data['args']['sorts'][ $key ] = $value;
237 | break;
238 |
239 | case 'override':
240 | $this->data['override'][ $key ] = $value;
241 | break;
242 | }
243 |
244 | return $this;
245 | }
246 | }
247 |
--------------------------------------------------------------------------------
/includes/class-qw-settings.php:
--------------------------------------------------------------------------------
1 | QW_DEFAULT_THEME,
9 | 'widget_theme_compat' => 0,
10 | 'live_preview' => 0,
11 | 'show_silent_meta' => 0,
12 | 'meta_value_field_handler' => 0,
13 | 'shortcode_compat' => 0,
14 | 'meta_key_cache_life' => 0, // Forever.
15 | );
16 |
17 | public $values = array();
18 |
19 | /**
20 | * QW_Settings constructor.
21 | */
22 | private function __construct() {
23 | $saved = get_option( $this->option_name, false );
24 |
25 | if ( !$saved ){
26 | $saved = $this->unify_old_settings();
27 | }
28 |
29 | $this->values = array_replace( $this->default_settings, $saved );
30 | }
31 |
32 | /**
33 | * Singleton
34 | *
35 | * @return QW_Settings
36 | */
37 | static public function get_instance(){
38 | static $instance = null;
39 | if ( is_null( $instance ) ) {
40 | $instance = new self();
41 | }
42 |
43 | return $instance;
44 | }
45 |
46 | /**
47 | * Get a single setting
48 | *
49 | * @param $key
50 | * @param bool|FALSE $default
51 | *
52 | * @return mixed
53 | */
54 | function get( $key, $default = false ){
55 | if ( isset( $this->values[ $key ] ) ){
56 | return $this->values[ $key ];
57 | }
58 |
59 | return $default;
60 | }
61 |
62 | /**
63 | * Set a value
64 | *
65 | * @param $key
66 | * @param $value
67 | * @param string $sanitize_callback
68 | */
69 | function set( $key, $value, $sanitize_callback = 'sanitize_text_field' ){
70 | if ( is_callable( $sanitize_callback ) ){
71 | $value = call_user_func( $sanitize_callback, $value );
72 | }
73 |
74 | $this->values[ $key ] = $value;
75 | }
76 |
77 | /**
78 | * Save the current values
79 | */
80 | function save(){
81 | update_option( $this->option_name, $this->values );
82 | }
83 |
84 | /**
85 | * Update old multi-option settings to new single option array
86 | */
87 | private function unify_old_settings(){
88 | $settings = array(
89 | 'edit_theme' => get_option( 'qw_edit_theme', QW_DEFAULT_THEME ),
90 | 'live_preview' => get_option( 'qw_live_preview', 0 ),
91 | 'show_silent_meta' => get_option( 'qw_show_silent_meta', 0 ),
92 | 'meta_value_field_handler' => get_option( 'qw_meta_value_field_handler', 0 ),
93 | 'widget_theme_compat' => get_option( 'qw_widget_theme_compat', 0 ),
94 | );
95 |
96 | update_option( $this->option_name, $settings );
97 |
98 | delete_option( 'qw_edit_theme' );
99 | delete_option( 'qw_widget_theme_compat' );
100 | delete_option( 'qw_live_preview' );
101 | delete_option( 'qw_show_silent_meta' );
102 | delete_option( 'qw_meta_value_field_handler' );
103 |
104 | return $settings;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/includes/class-qw-shortcodes.php:
--------------------------------------------------------------------------------
1 | get('shortcode_compat') ){
14 | add_shortcode( 'qw_query', array( $self, 'query_shortcode' ) );
15 | }
16 | else {
17 | add_shortcode( 'query', array( $self, 'query_shortcode' ) );
18 | }
19 |
20 | add_filter( 'qw_shortcode_default_attributes', array( $self, 'arguments_default_attributes') );
21 | add_filter( 'qw_shortcode_options', array( $self, 'arguments_contextual_tokens' ), 10, 2 );
22 | add_filter( 'qw_pre_query', array( $self, 'arguments_pre_query' ), 10, 2 );
23 | }
24 |
25 | /**
26 | * Shortcode support for all queries
27 | *
28 | * @param $input_atts
29 | *
30 | * @return string
31 | */
32 | function query_shortcode( $input_atts ) {
33 | $options_override = array();
34 |
35 | // provide additional default shortcode attributes
36 | $default_atts = apply_filters( 'qw_shortcode_default_attributes', array( 'id' => '', 'slug' => '' ) );
37 |
38 | $atts = shortcode_atts( $default_atts, $input_atts );
39 |
40 | if ( ! $atts['id'] && $atts['slug'] ) {
41 | $atts['id'] = qw_get_query_by_slug( $atts['slug'] );
42 | }
43 |
44 | // alter the attributes
45 | $atts = apply_filters( 'qw_shortcode_attributes', $atts, $options_override );
46 |
47 | // alter the options provided to the query
48 | $options_override = apply_filters( 'qw_shortcode_options', $options_override, $atts );
49 |
50 | $themed = qw_execute_query( $atts['id'], $options_override );
51 |
52 | return $themed;
53 | }
54 |
55 | /**
56 | * Allow arguments to be passed into query shortcodes.
57 | * This way, users have control over individual shortcode instances.
58 | *
59 | * @param $default_atts
60 | *
61 | * @return array
62 | */
63 | function arguments_default_attributes( $default_atts ) {
64 | $default_atts['args'] = '';
65 |
66 | return $default_atts;
67 | }
68 |
69 | /**
70 | * Replace contextual tokens with their values
71 | *
72 | * @param $options
73 | * @param $attributes
74 | *
75 | * @return array
76 | */
77 | function arguments_contextual_tokens( $options, $attributes ) {
78 | if ( isset( $attributes['args'] ) && ! empty( $attributes['args'] ) ) {
79 |
80 | if ( stripos( $attributes['args'], '{{' ) !== FALSE ) {
81 | $attributes['args'] = qw_contextual_tokens_replace( $attributes['args'] );
82 | }
83 |
84 | $options['shortcode_args'] = html_entity_decode( $attributes['args'] );
85 | }
86 |
87 | return $options;
88 | }
89 |
90 | /**
91 | * Modify the query by parsing shortcode arguments and merge into query args
92 | *
93 | * @param $query_args
94 | * @param $options
95 | *
96 | * @return array
97 | */
98 | function arguments_pre_query( $query_args, $options ) {
99 |
100 | if ( isset( $options['shortcode_args'] ) ) {
101 | $shortcode_args = wp_parse_args( $options['shortcode_args'] );
102 | $query_args = array_replace_recursive( (array) $query_args,
103 | $shortcode_args );
104 | }
105 |
106 | return $query_args;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/includes/exposed.php:
--------------------------------------------------------------------------------
1 | '', 'filters' => '' );
9 | // loop through sorts and filters
10 | if ( isset( $exposed['sorts'] ) && is_array( $exposed['sorts'] ) ) {
11 | // loop through each exposed item
12 | foreach ( $exposed['sorts'] as $name => $item ) {
13 | // show the exposed form
14 | if ( function_exists( $item['exposed_form'] ) ) {
15 | $item['name'] = $name;
16 | $output['sorts'] .= qw_theme_single_exposed_handler( $item );
17 | }
18 | }
19 | }
20 |
21 | // loop through sorts and filters
22 | if ( isset( $exposed['filters'] ) && is_array( $exposed['filters'] ) ) {
23 | // loop through each exposed item
24 | foreach ( $exposed['filters'] as $name => $item ) {
25 | // show the exposed form
26 | if ( function_exists( $item['exposed_form'] ) ) {
27 | $item['name'] = $name;
28 | $output['filters'] .= qw_theme_single_exposed_handler( $item );
29 | }
30 | }
31 | }
32 |
33 | return $output;
34 | }
35 | }
36 |
37 | /*
38 | * Look for and prepare exposed handlers
39 | */
40 | function qw_process_exposed_handlers( $options ) {
41 | // look for exposed filters or sorts
42 | if ( isset( $options['args']['sorts'] ) && is_array( $options['args']['sorts'] ) ) {
43 | $all_sorts = qw_all_sort_options();
44 | $exposed_sorts = array();
45 | foreach ( $options['args']['sorts'] as $name => $sort ) {
46 | if ( isset( $sort['is_exposed'] ) ) {
47 | $exposed_sorts[ $name ] = $all_sorts[ $sort['hook_key'] ];
48 | // override exposed_key
49 | if ( ! empty( $sort['exposed_key'] ) ) {
50 | $exposed_sorts[ $name ]['exposed_key'] = $sort['exposed_key'];
51 | }
52 | $exposed_sorts[ $name ]['values'] = $sort;
53 | }
54 | }
55 | }
56 | if ( isset( $options['args']['filters'] ) && is_array( $options['args']['filters'] ) ) {
57 | $exposed_filters = array();
58 | $all_filters = qw_all_filters();
59 | foreach ( $options['args']['filters'] as $name => $filter ) {
60 | if ( isset( $filter['is_exposed'] ) ) {
61 | $exposed_filters[ $name ] = $all_filters[ $filter['hook_key'] ];
62 | // override exposed_key
63 | if ( ! empty( $filter['exposed_key'] ) ) {
64 | $exposed_filters[ $name ]['exposed_key'] = $filter['exposed_key'];
65 | }
66 | $exposed_filters[ $name ]['values'] = $filter;
67 | }
68 | }
69 | }
70 |
71 | $exposed = array();
72 | if ( isset( $exposed_filters ) && count( $exposed_filters ) > 0 ) {
73 | $exposed_filters = apply_filters( 'qw_process_exposed_filters',
74 | $exposed_filters );
75 | $exposed['filters'] = $exposed_filters;
76 | }
77 | /*
78 | if (isset($exposed_sorts) && count($exposed_sorts) > 0){
79 | do_action_ref_array('qw_process_exposed_sorts', array(&$exposed_sorts));
80 | $exposed['sorts'] = $exposed_sorts;
81 | }
82 | */
83 | if ( count( $exposed ) > 0 ) {
84 | return $exposed;
85 | }
86 |
87 | return FALSE;
88 | }
89 |
90 | /*
91 | * Make getting the subitted exposed data easy
92 | */
93 | function qw_exposed_submitted_data() {
94 | $data = array();
95 | if ( ! empty( $_GET ) ) {
96 | $data = $_GET;
97 | } else if ( ! empty( $_POST ) ) {
98 | $data = $_POST;
99 | }
100 | foreach ( $data as $k => $v ) {
101 | if ( is_null( $data[ $k ] ) ) {
102 | unset( $data[ $k ] );
103 | unset( $_GET[ $k ] );
104 | unset( $_POST[ $k ] );
105 | } else {
106 | if ( is_array( $v ) ) {
107 | array_walk_recursive( $v, 'sanitize_text_field' );
108 | $data[ $k ] = $v;
109 | } else {
110 | $data[ $k ] = sanitize_text_field( urldecode( $v ) );
111 | }
112 | }
113 | }
114 |
115 | if ( count( $data ) > 0 ) {
116 | return $data;
117 | }
118 |
119 | return FALSE;
120 | }
121 |
122 | /*
123 | * Single exposed handler wrapper html
124 | */
125 | function qw_theme_single_exposed_handler( $item ) {
126 | if ( empty( $item['exposed_key'] ) ) {
127 | $item['exposed_key'] = 'exposed_' . $item['name'];
128 | }
129 | // gather submitted values
130 | $submitted = qw_exposed_submitted_data();
131 | $values = '';
132 | if ( isset( $submitted[ $item['exposed_key'] ] ) ) {
133 | $values = $submitted[ $item['exposed_key'] ];
134 | }
135 | ob_start();
136 | ?>
137 |
138 |
139 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
150 |
151 |
152 |
153 |
154 | 'Select',
164 | 'checkboxes' => 'Checkboxes',
165 | );
166 | ?>
167 |
168 |
Exposed Values:
169 |
171 | $title ) {
173 | $selected = ( isset( $filter['values']['exposed_settings']['type'] ) && $value == $filter['values']['exposed_settings']['type'] ) ? 'selected="selected"' : '';
174 | ?>
175 | >
177 |
180 |
181 |
182 |
Provide an exposed filter that accepts the
183 | selected number of values.
184 |
185 | 'Callback',
12 | 'description' => 'Arbitrarily execute a function.',
13 | 'form_callback' => 'qw_callback_field_form',
14 | 'output_callback' => 'qw_execute_the_callback',
15 | 'output_arguments' => TRUE,
16 | );
17 |
18 | return $fields;
19 | }
20 |
21 | /*
22 | * Execute callback function
23 | */
24 | function qw_execute_the_callback( $post, $field, $tokens ) {
25 | $returned = FALSE;
26 | $echoed = FALSE;
27 |
28 | ob_start();
29 | if ( isset( $field['custom_output_callback'] ) && function_exists( $field['custom_output_callback'] ) ) {
30 | if ( isset( $field['include_output_arguments'] ) ) {
31 | $returned = $field['custom_output_callback']( $post,
32 | $field,
33 | $tokens );
34 | } else if ( isset( $field['include_text_arguments'] ) ) {
35 |
36 | // unset empty
37 | $callback_params = $field['parameters'];
38 | foreach ( $callback_params as $k => $v ) {
39 | if ( empty( $v ) ) {
40 | unset( $callback_params[ $k ] );
41 | }
42 | else {
43 | $callback_params[ $k ] = qw_contextual_tokens_replace( $v );
44 | }
45 | }
46 |
47 | $returned = call_user_func_array( $field['custom_output_callback'],
48 | $callback_params );
49 | } else {
50 | $returned = $field['custom_output_callback']();
51 | }
52 | }
53 | $echoed = ob_get_clean();
54 |
55 | // some functions both return and echo a value
56 | // so make sure to only show 1 instance of the callback
57 | if ( $returned ) {
58 | return $returned;
59 | }
60 |
61 | if ( $echoed ) {
62 | return $echoed;
63 | }
64 | }
65 |
66 | /*
67 | * Custom callback settings form
68 | */
69 | function qw_callback_field_form( $field ) {
70 | $custom_output_callback = ( isset( $field['values']['custom_output_callback'] ) && ! empty( $field['values']['custom_output_callback'] ) ) ? $field['values']['custom_output_callback'] : '';
71 | //$callback_exists = ($custom_output_callback && function_exists($custom_output_callback)) ? true : false;
72 | $include_output_args = ( isset( $field['values']['include_output_arguments'] ) ) ? 'checked="checked"' : '';
73 | $include_text_args = ( isset( $field['values']['include_text_arguments'] ) ) ? 'checked="checked"' : '';
74 | $defaults = array( '', '', '', '', '' );
75 |
76 | if ( ! isset( $field['values']['parameters'] ) ) {
77 | $field['values']['parameters'] = $defaults;
78 | }
79 | else {
80 | $field['values']['parameters'] = array_replace( $defaults, $field['values']['parameters'] );
81 | }
82 |
83 | ?>
84 |
85 |
86 | Callback:
87 |
90 |
91 |
92 |
93 | Provide an existing function name. This function will be executed
94 | during the loop of this query.
95 |
96 |
97 |
98 |
99 | [include_output_arguments]'
101 | /> - Include additional
102 | information
103 |
104 |
If checked, the callback will be executed with
105 | the parameters $post, $field, and $tokens. The $post parameter is a
106 | Wordpress $post object, and the $field paramater is the query
107 | wrangler field settings, and the $tokens parameter includes all the
108 | available token values.
109 |
110 |
156 | 'File Attachment',
14 |
15 | // description on the field form
16 | 'description' => 'Just a useful description of this field'
17 |
18 | // optional) callback for outputting a field, must return the results
19 | 'output_callback' => 'qw_theme_file',
20 |
21 | // (optional) where or not to pass $post and $field into the output_callback
22 | // useful for custom functions
23 | 'output_arguments' => true,
24 |
25 | // (optional) callback function for field forms
26 | 'form_callback' => 'qw_form_file_attachment',
27 | );
28 |
29 | */
30 | function qw_default_fields( $fields ) {
31 | $fields['ID'] = array(
32 | 'title' => 'Post ID',
33 | 'description' => 'The post ID.',
34 | );
35 | $fields['post_title'] = array(
36 | 'title' => 'Post Title',
37 | 'description' => 'The title of a post.',
38 | 'output_callback' => 'get_the_title',
39 | );
40 | $fields['post_content'] = array(
41 | 'title' => 'Post Content',
42 | 'description' => 'The full content body of a post.',
43 | 'output_callback' => 'get_the_content',
44 | 'content_options' => TRUE,
45 | );
46 | $fields['post_excerpt'] = array(
47 | 'title' => 'Post Excerpt',
48 | 'description' => 'The excerpt of a post.',
49 | 'output_callback' => 'get_the_excerpt',
50 | 'content_options' => TRUE,
51 | );
52 | $fields['post_date'] = array(
53 | 'title' => 'Post Date',
54 | 'description' => 'Published date of a post.',
55 | 'output_callback' => 'get_the_date',
56 | );
57 | $fields['post_status'] = array(
58 | 'title' => 'Post Status',
59 | 'description' => 'Status of a post.',
60 | );
61 | $fields['post_parent'] = array(
62 | 'title' => 'Post Parent',
63 | 'description' => 'Parent page ID for a page.',
64 | );
65 | $fields['post_modified'] = array(
66 | 'title' => 'Post Modified',
67 | 'description' => 'Last date a post was modified.',
68 | );
69 | $fields['guid'] = array(
70 | 'title' => 'GUID',
71 | 'description' => 'Global Unique ID for a post (url).',
72 | );
73 | $fields['post_type'] = array(
74 | 'title' => 'Post Type',
75 | 'description' => 'The type of a post.',
76 | );
77 | $fields['comment_count'] = array(
78 | 'title' => 'Comment Count',
79 | 'description' => 'Number of comments for a post.',
80 | );
81 | $fields['permalink'] = array(
82 | 'title' => 'Permalink',
83 | 'description' => 'Pretty URL for a post.',
84 | 'output_callback' => 'get_permalink',
85 | );
86 |
87 | return $fields;
88 | }
89 |
--------------------------------------------------------------------------------
/includes/fields/featured_image.php:
--------------------------------------------------------------------------------
1 | 'Featured Image',
12 | 'description' => 'The "post_thumbnail" of a given row.',
13 | 'output_callback' => 'qw_theme_featured_image',
14 | 'output_arguments' => TRUE,
15 | 'form_callback' => 'qw_field_featured_image_form',
16 | );
17 |
18 | return $fields;
19 | }
20 |
21 | /*
22 | * Image attachment settings Form
23 | */
24 | function qw_field_featured_image_form( $field ) {
25 | //$image_styles = _qw_get_image_styles();
26 | $image_styles = get_intermediate_image_sizes();
27 | ?>
28 |
29 | Image Display Style:
30 | [image_display_style]'>
32 | $style ) {
34 | $style_selected = ( $field['values']['image_display_style'] == $style ) ? 'selected="selected"' : '';
35 | ?>
36 | >
38 |
41 |
42 |
43 | ID ) ) {
55 | $image_id = get_post_thumbnail_id( $post->ID, $style );
56 |
57 | return wp_get_attachment_image( $image_id, $style );
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/includes/fields/file_attachment.php:
--------------------------------------------------------------------------------
1 | 'File Attachment',
15 | 'description' => 'Files that are attached to a post.',
16 | 'output_callback' => 'qw_theme_file',
17 | 'output_arguments' => TRUE,
18 | 'form_callback' => 'qw_field_file_attachment_form',
19 | );
20 |
21 | return $fields;
22 | }
23 |
24 | /*
25 | * File Styles
26 | *
27 | * @return array of file styles
28 | */
29 | function qw_default_file_styles( $file_styles ) {
30 | $file_styles['link'] = array(
31 | 'description' => 'Filename Link to File',
32 | //'callback' => 'qw_theme_file',
33 | );
34 | $file_styles['link_url'] = array(
35 | 'description' => 'URL Link to File',
36 | //'callback' => 'qw_theme_file',
37 | );
38 | $file_styles['url'] = array(
39 | 'description' => 'URL of File',
40 | //'callback' => 'qw_theme_file',
41 | );
42 |
43 | return $file_styles;
44 | }
45 |
46 | /*
47 | * File attachment settings Form
48 | */
49 | function qw_field_file_attachment_form( $field ) {
50 | $file_styles = qw_all_file_styles();
51 | ?>
52 |
53 | Number of items to show:
54 | [file_display_count]'
57 | value=""/>
58 |
59 |
60 | File Display Style:
61 | [file_display_style]'>
63 | $file_style_details ) {
65 | $style_selected = ( $field['values']['file_display_style'] == $key ) ? 'selected="selected"' : '';
66 | ?>
67 | >
69 |
72 |
73 |
74 | ID
81 | * $param int $count Number of files to get
82 | */
83 | function qw_theme_file( $post, $field ) {
84 | $style = ( $field['file_display_style'] ) ? $field['file_display_style'] : 'link';
85 | $count = ( $field['file_display_count'] ) ? $field['file_display_count'] : 0;
86 |
87 | $files = qw_get_post_files( $post->ID );
88 | if ( is_array( $files ) ) {
89 | $output = array();
90 | $i = 0;
91 | foreach ( $files as $file ) {
92 | if ( ( $count == 0 || ( $i < $count ) ) && substr( $file->post_mime_type,
93 | 0,
94 | 5 ) != "image"
95 | ) {
96 | switch ( $style ) {
97 | case 'url':
98 | $output[] = wp_get_attachment_url( $file->ID );
99 | break;
100 |
101 | case 'link':
102 | // complete file name
103 | $file_name = explode( "/", $file->guid );
104 | $file_name = $file_name[ count( $file_name ) - 1 ];
105 | $output[] = '' . $file_name . ' ';
106 | break;
107 |
108 | case 'link_url':
109 | $output[] = '' . $file->guid . ' ';
110 | break;
111 | }
112 | }
113 | $i ++;
114 | }
115 |
116 | return "".implode( " ", $output ) ." ";
117 | }
118 | }
119 |
120 | /*
121 | * Get files attached to a post
122 | *
123 | * @param int $post_id The WP post id
124 | * @return Array of file posts
125 | */
126 | function qw_get_post_files( $post_id ) {
127 | $child_args = array(
128 | "post_type" => "attachment",
129 | "post_parent" => $post_id,
130 | );
131 | // Get images for this post
132 | $files = get_posts( $child_args );
133 |
134 | if ( is_array( $files ) ) {
135 | return $files;
136 | }
137 |
138 | return FALSE;
139 | }
140 |
141 |
--------------------------------------------------------------------------------
/includes/fields/image_attachment.php:
--------------------------------------------------------------------------------
1 | 'Image Attachment',
12 | 'description' => 'Image files that are attached to a post.',
13 | 'output_callback' => 'qw_theme_image',
14 | 'output_arguments' => TRUE,
15 | 'form_callback' => 'qw_field_image_attachment_form',
16 | );
17 |
18 | return $fields;
19 | }
20 |
21 | /*
22 | * Image attachment settings Form
23 | */
24 | function qw_field_image_attachment_form( $field ) {
25 | //$image_styles = _qw_get_image_styles();
26 | $image_styles = get_intermediate_image_sizes();
27 | $featured_image = ( isset( $field['values']['featured_image'] ) ) ? 'checked="checked"' : "";
28 | ?>
29 |
30 | Number of items to show:
31 | [image_display_count]'
34 | value=""/>
35 |
36 |
37 | /> Featured Image Only
41 |
42 |
43 |
44 | Image Display Style:
45 | [image_display_style]'>
47 | $style ) {
49 | $style_selected = ( $field['values']['image_display_style'] == $style ) ? 'selected="selected"' : '';
50 | ?>
51 | >
53 |
56 |
57 |
58 | $size ) {
69 | $image_styles[ $size ] = array(
70 | 'description' => $size,
71 | 'callback' => 'qw_theme_image',
72 | );
73 | }
74 |
75 | return $image_styles;
76 | }
77 |
78 | /*
79 | * Turn a list of images into html
80 | *
81 | * @param $post_id
82 | * @param $image_type
83 | * @param $count;
84 | */
85 | function qw_theme_image( $post, $field ) {
86 | $style = $field['image_display_style'];
87 | $count = $field['image_display_count'];
88 | $featured_image_id = isset( $field['featured_image'] ) ? get_post_thumbnail_id( $post->ID ) : NULL;
89 | $images = qw_get_post_images( $post->ID );
90 |
91 | if ( is_array( $images ) ) {
92 | $output = '';
93 | $i = 0;
94 | foreach ( $images as $image ) {
95 | if ( $featured_image_id ) {
96 | if ( $image->ID == $featured_image_id ) {
97 | $output .= wp_get_attachment_image( $image->ID, $style );
98 | }
99 | } else {
100 | // ensure less than count
101 | if ( $count == 0 || ( $i < $count ) ) {
102 | $output .= wp_get_attachment_image( $image->ID, $style );
103 | }
104 | }
105 | $i ++;
106 | }
107 |
108 | return $output;
109 | }
110 | }
111 |
112 | /*
113 | * Get all images attached to a single post
114 | *
115 | * @param int $post_id The Wordpress ID for the post or page to get images from
116 | *
117 | * @return sorted array of images
118 | */
119 | function qw_get_post_images( $post_id ) {
120 | $child_args = array(
121 | "post_type" => "attachment",
122 | "post_mime_type" => "image",
123 | "post_parent" => $post_id
124 | );
125 | // Get images for this post
126 | $images = &get_children( $child_args );
127 |
128 | // If images exist for this page
129 | if ( is_array( $images ) ) {
130 | // sort this so menu order matters
131 | $sorted = array();
132 | $unsorted = array();
133 | foreach ( $images as $image ) {
134 | if ( $image->menu_order !== 0 ) {
135 | $sorted[ $image->menu_order ] = $image;
136 | } else {
137 | $unsorted[] = $image;
138 | }
139 | }
140 | // sort menu order
141 | ksort( $sorted );
142 | // reset array
143 | $sorted = array_values( $sorted );
144 | // add unsorted
145 | $sorted = array_merge( $sorted, $unsorted );
146 |
147 | return $sorted;
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/includes/fields/post_author.php:
--------------------------------------------------------------------------------
1 | 'Post Author',
12 | 'description' => 'Information relating to the author of a post.',
13 | 'form_callback' => 'qw_field_author_form',
14 | 'output_callback' => 'qw_get_the_author',
15 | 'output_arguments' => TRUE,
16 | );
17 |
18 | return $fields;
19 | }
20 |
21 | /*
22 | * Author output callback
23 | */
24 | function qw_get_the_author( $post, $field ) {
25 | switch ( $field['output_type'] ) {
26 | case 'ID':
27 | $author = $post->post_author;
28 | break;
29 |
30 | case 'name':
31 | default:
32 | $author = get_the_author();
33 | break;
34 | }
35 |
36 | if ( isset( $field['link_to_author'] ) ) {
37 | $author = '' . $author . ' ';
38 | }
39 |
40 | return $author;
41 | }
42 |
43 | /*
44 | * Author form callback
45 | */
46 | function qw_field_author_form( $field ) {
47 | $options = array(
48 | 'name' => 'Author Name',
49 | 'ID' => 'Author ID',
50 | );
51 | $link_selected = ( isset( $field['values']['link_to_author'] ) ) ? 'checked="checked"' : '';
52 | ?>
53 | Author Field Settings:
54 |
55 |
57 | $title ) { ?>
59 | >
61 |
62 |
63 |
66 |
67 |
68 |
69 |
70 | [link_to_author]'
72 | />
73 | Link to author page (list of author posts)
74 |
75 |
76 | 'Post Author Avatar',
12 | 'description' => 'Avatar for the author of a post.',
13 | 'form_callback' => 'qw_field_author_avatar_form',
14 | 'output_callback' => 'qw_get_avatar',
15 | 'output_arguments' => TRUE,
16 | );
17 |
18 | return $fields;
19 | }
20 |
21 | /*
22 | * Avatar output callback
23 | *
24 | * get_avatar( $id_or_email, $size, $default, $alt );
25 | */
26 | function qw_get_avatar( $post, $field ) {
27 | if ( isset( $field['link_to_author'] ) ) {
28 | $output = '' . get_avatar( $post->post_author,
29 | $field['size'] ) . ' ';
30 | } else {
31 | $output = get_avatar( $post->post_author, $field['size'] );
32 | }
33 |
34 | return $output;
35 | }
36 |
37 | /*
38 | * Avatar form callback
39 | */
40 | function qw_field_author_avatar_form( $field ) {
41 | $link_selected = ( isset( $field['values']['link_to_author'] ) ) ? 'checked="checked"' : '';
42 | $size = isset( $field['values']['size'] ) ? $field['values']['size'] : '';
43 | ?>
44 | Avatar Size:
45 |
49 | (pixel width)
50 |
51 |
52 | [link_to_author]'
54 | />
55 | Link to author page (list of author posts)
56 |
57 |
58 | 'Taxonomy Terms',
16 | 'description' => 'Information relating to the author of a post.',
17 | 'form_callback' => 'qw_field_taxonomy_terms_form',
18 | 'output_callback' => 'qw_field_taxonomy_terms_output',
19 | 'output_arguments' => TRUE,
20 | );
21 |
22 | return $fields;
23 | }
24 |
25 | /**
26 | * Output callback
27 | *
28 | * @param $post
29 | * @param $field
30 | *
31 | * @return null|string
32 | */
33 | function qw_field_taxonomy_terms_output( $post, $field ) {
34 | $output = array();
35 |
36 | $terms = get_the_terms( $post->ID, $field['taxonomy_name'] );
37 |
38 | if ( $terms ) {
39 | foreach( $terms as $term ){
40 | if ( isset( $field['link_to_term'] ) ) {
41 | $output[] = '' . $term->name . ' ';
42 | }
43 | else {
44 | $output[] = $term->name;
45 | }
46 | }
47 | }
48 |
49 | return "".
50 | implode( " ", $output ).
51 | " ";
52 | }
53 |
54 | /**
55 | * Form callback
56 | *
57 | * @param $field
58 | */
59 | function qw_field_taxonomy_terms_form( $field ) {
60 | $options = array();
61 | $taxes = get_taxonomies( array(
62 | 'public' => true,
63 | ), 'objects' );
64 |
65 | foreach( $taxes as $key => $tax ){
66 | $options[ $key ] = $tax->label;
67 | }
68 |
69 | $link_selected = ( isset( $field['values']['link_to_term'] ) ) ? 'checked="checked"' : '';
70 | ?>
71 | Taxonomy:
72 |
73 |
75 | $title ) { ?>
77 | >
79 |
80 |
81 |
84 |
85 |
86 |
87 |
88 | [link_to_term]'
90 | />
91 | Link to the term page
92 |
93 |
94 | 'Author',
10 | 'description' => 'Filter posts by author',
11 | 'form_callback' => 'qw_filter_author_form',
12 | 'query_args_callback' => 'qw_generate_query_args_author',
13 | 'query_display_types' => array( 'page', 'widget' ),
14 | );
15 |
16 | return $filters;
17 | }
18 |
19 | function qw_filter_author_form( $filter ) {
20 | $aut_ops = array(
21 | "author" => "Author ids",
22 | "author_name" => "Author nice name",
23 | "author__in" => "Authors in list of ids",
24 | "author__not_in" => "Authors Not in list of author ids",
25 | );
26 | if ( ! isset( $filter['values']['author_operator'] ) ) {
27 | $filter['values']['author_operator'] = '';
28 | }
29 | if ( ! isset( $filter['values']['author_values'] ) ) {
30 | $filter['values']['author_values'] = '';
31 | }
32 | ?>
33 | Author Options - show posts that are from:
34 |
35 |
36 | $title ) {
38 | $selected = ( $filter['values']['author_operator'] == $op ) ? 'selected="selected"' : '';
39 | ?>
40 | >
42 |
45 |
46 |
47 |
48 | Values
49 |
50 |
Provide the values appropriate for the author option. Ids should be comma separated.
51 |
52 | 'Callback',
15 | 'description' => 'Provide a callback that can alter the query arguments in any way.',
16 | 'form_callback' => 'qw_filter_callback_form',
17 | 'query_args_callback' => 'qw_filter_callback_execute',
18 | 'query_display_types' => array( 'page', 'widget', 'override' ),
19 | );
20 |
21 | return $filters;
22 | }
23 |
24 | /**
25 | * Form for callback filter
26 | *
27 | * @param $filter
28 | */
29 | function qw_filter_callback_form( $filter ) {
30 | if ( ! isset( $filter['values']['callback'] ) ) {
31 | $filter['values']['callback'] = '';
32 | }
33 | ?>
34 |
35 | '/>
40 |
41 |
42 | The callback function will be provided the $args and $filter variables,
43 | and should return the modified $args array.
44 | Eg, function my_filter_callback($args, $filter){ return
45 | $args; }
46 |
47 | 'Categories',
10 | 'description' => 'Select which categories to pull posts from, and how to treat those categories.',
11 | 'form_callback' => 'qw_filter_categories_form',
12 | 'query_args_callback' => 'qw_generate_query_args_categories',
13 | 'query_display_types' => array( 'page', 'widget' ),
14 | );
15 |
16 | return $filters;
17 | }
18 |
19 | /**
20 | * Options for "categories" filter
21 | *
22 | * @param $filter
23 | */
24 | function qw_filter_categories_form( $filter ) {
25 | $cat_ops = array(
26 | "cat" => "Any category plus children categories",
27 | "category__in" => "Any category without children categories",
28 | "category__and" => "All categories selected",
29 | "category__not_in" => "Not in the categories selected",
30 | );
31 | ?>
32 |
33 | 'id=>name', 'hide_empty' => 0 ) );
36 | // List all categories as checkboxes
37 | foreach ( $categories as $cat_id => $cat_name ) {
38 | $cat_checked = ( isset( $filter['values']['cats'][ $cat_id ] ) ) ? 'checked="checked"' : '';
39 | ?>
40 |
41 | />
46 |
47 |
48 |
51 |
52 | Categories Options - show posts that are:
53 |
54 |
56 | $title ) {
58 | $selected = ( $filter['values']['cat_operator'] == $op ) ? 'selected="selected"' : '';
59 | ?>
60 | >
62 |
65 |
66 |
67 | 'Meta Key',
9 | 'description' => 'Filter for a specific meta_key.',
10 | 'form_callback' => 'qw_filter_meta_key_form',
11 | 'query_args_callback' => 'qw_generate_query_args_meta_key',
12 | 'query_display_types' => array( 'page', 'widget', 'override' ),
13 | );
14 |
15 | return $filters;
16 | }
17 |
18 | function qw_filter_meta_key_form( $filter ) {
19 | if ( ! isset( $filter['values']['meta_key'] ) ) {
20 | $filter['values']['meta_key'] = '';
21 | }
22 | ?>
23 |
24 | '/>
28 |
29 | 'Meta Key/Value Compare',
10 | 'description' => 'Filter for a specific meta_key / meta_value pair.',
11 | 'form_callback' => 'qw_filter_meta_key_value_form',
12 | 'query_args_callback' => 'qw_generate_query_args_meta_key_value',
13 | 'query_display_types' => array( 'page', 'widget', 'override' ),
14 | );
15 |
16 | return $filters;
17 | }
18 |
19 | function qw_filter_meta_key_value_form( $filter ) {
20 | if ( ! isset( $filter['values']['meta_key'] ) ) {
21 | $filter['values']['meta_key'] = '';
22 | }
23 | if ( ! isset( $filter['values']['meta_compare'] ) ) {
24 | $filter['values']['meta_compare'] = '';
25 | }
26 | if ( ! isset( $filter['values']['meta_value'] ) ) {
27 | $filter['values']['meta_value'] = '';
28 | }
29 |
30 | $meta_compare = array(
31 | "=" => "Is equal to",
32 | "!=" => "Is not equal to",
33 | "<" => "Is less than",
34 | "<=" => "Is less than or equal to",
35 | ">" => "Is greater than",
36 | ">=" => "Is greater than or equal to",
37 | );
38 | ?>
39 |
40 | Meta Key:
41 | '/>
44 |
45 |
46 | Compare:
47 |
49 | $title ) {
51 | $selected = ( $filter['values']['meta_compare'] == $op ) ? 'selected="selected"' : '';
52 | ?>
53 | >
55 |
58 |
59 |
60 |
61 | Meta Value:
62 |
64 |
65 | 'Meta Query',
10 | 'description' => 'Filter for a single meta query',
11 | 'form_callback' => 'qw_filter_meta_query_form',
12 | 'query_args_callback' => 'qw_generate_query_args_meta_query',
13 | 'query_display_types' => array( 'page', 'widget', 'override' ),
14 | );
15 |
16 | return $filters;
17 | }
18 |
19 | function qw_filter_meta_query_form( $filter ) {
20 | if ( ! isset( $filter['values']['key'] ) ) {
21 | $filter['values']['key'] = '';
22 | }
23 | if ( ! isset( $filter['values']['type'] ) ) {
24 | $filter['values']['type'] = '';
25 | }
26 | if ( ! isset( $filter['values']['compare'] ) ) {
27 | $filter['values']['compare'] = '';
28 | }
29 | if ( ! isset( $filter['values']['value'] ) ) {
30 | $filter['values']['value'] = array( '', '' );
31 | }
32 | $compares = array(
33 | "=",
34 | "!=",
35 | "<",
36 | "<=",
37 | ">",
38 | ">=",
39 | "LIKE",
40 | "NOT LIKE",
41 | "IN",
42 | "NOT IN",
43 | "BETWEEN",
44 | "NOT BETWEEN",
45 | "EXISTS",
46 | "NOT EXISTS",
47 | );
48 | $types = array(
49 | "CHAR",
50 | "NUMERIC",
51 | "BINARY",
52 | "DATE",
53 | "DATETIME",
54 | "DECIMAL",
55 | "SIGNED",
56 | "TIME",
57 | "UNSIGNED"
58 | );
59 |
60 | ?>
61 |
62 | Meta Key:
63 | ' />
64 |
65 |
66 | Meta Value 1:
67 |
72 |
73 |
74 | Meta Value 2:
75 |
80 |
Only use Meta Value 2 when compare is 'IN', 'NOT IN', 'BETWEEN', or 'NOT BETWEEN'.
81 |
82 |
83 | Type:
84 |
85 |
87 | >
89 |
92 |
93 |
94 |
95 | Compare:
96 |
97 |
99 | >
101 |
104 |
105 |
106 | $filter['values']['key'],
118 | 'value' => $value,
119 | 'compare' => $filter['values']['compare'],
120 | 'type' => $filter['values']['type'],
121 | );
122 | }
--------------------------------------------------------------------------------
/includes/filters/meta_value.php:
--------------------------------------------------------------------------------
1 | 'Meta Value',
9 | 'description' => 'Filter for a specific meta_value.',
10 | 'form_callback' => 'qw_filter_meta_value_form',
11 | 'query_args_callback' => 'qw_generate_query_args_meta_value',
12 | 'query_display_types' => array( 'page', 'widget', 'override' ),
13 | );
14 |
15 | return $filters;
16 | }
17 |
18 | function qw_filter_meta_value_form( $filter ) {
19 | if ( ! isset( $filter['values']['meta_value'] ) ) {
20 | $filter['values']['meta_value'] = '';
21 | }
22 | ?>
23 |
25 |
26 | 'Post IDs',
9 | 'description' => 'Provide a list of post_ids to show or not show.',
10 | 'form_callback' => 'qw_filter_post_id_form',
11 | 'query_args_callback' => 'qw_generate_query_args_post_id',
12 | 'query_display_types' => array( 'page', 'widget', 'override' ),
13 | // exposed
14 | 'exposed_form' => 'qw_filter_post_id_exposed_form',
15 | 'exposed_process' => 'qw_filter_post_id_exposed_process',
16 | );
17 |
18 | return $filters;
19 | }
20 |
21 | function qw_filter_post_id_form( $filter ) {
22 | if ( ! isset( $filter['values']['post_ids'] ) ) {
23 | $filter['values']['post_ids'] = '';
24 | }
25 | if ( ! isset( $filter['values']['post_ids_callback'] ) ) {
26 | $filter['values']['post_ids_callback'] = '';
27 | }
28 | if ( ! isset( $filter['values']['compare'] ) ) {
29 | $filter['values']['compare'] = '';
30 | }
31 | ?>
32 |
33 | Provide post_ids as a comma separated list:
34 |
' />
35 |
36 |
37 | Or, provide a callback function name that returns an array of post_ids:
38 |
39 | Note: you cannot expose a filter if using a callback.
40 |
41 |
42 | How to treat these post IDs.
43 |
44 | >Only these posts
47 | >Not these posts
50 |
51 |
52 | $value ) {
87 | if ( ! in_array( $value, $allowed ) ) {
88 | unset( $values[ $k ] );
89 | }
90 | }
91 | }
92 | // set the values
93 | $args[ $filter['values']['compare'] ] = $values;
94 | }
95 |
96 | /*
97 | * Exposed form
98 | */
99 | function qw_filter_post_id_exposed_form( $filter, $values ) {
100 | // adjust for default values
101 | qw_filter_post_id_exposed_default_values( $filter, $values );
102 | ?>
103 |
106 | 'Post Parent',
10 | 'description' => 'Use only with post type "Page" to show results with the chosen parent ID.',
11 | 'form_callback' => 'qw_filter_post_parent_form',
12 | 'query_args_callback' => 'qw_generate_query_args_post_parent',
13 | 'query_display_types' => array( 'page', 'widget' ),
14 | // exposed
15 | 'exposed_form' => 'qw_filter_post_parent_exposed_form',
16 | 'exposed_process' => 'qw_filter_post_parent_exposed_process',
17 | //'exposed_settings_form' => 'qw_filter_post_parent_exposed_settings_form',
18 | );
19 |
20 | return $filters;
21 | }
22 |
23 | function qw_generate_query_args_post_parent( &$args, $filter ) {
24 | $args['post_parent'] = $filter['values']['post_parent'];
25 | }
26 |
27 | function qw_filter_post_parent_form( $filter ) {
28 | if ( ! isset( $filter['values']['post_parent'] ) ) {
29 | $filter['values']['post_parent'] = '';
30 | }
31 | ?>
32 |
33 |
37 |
38 |
65 |
68 | 'Search',
10 | 'description' => 'Searches for keywords',
11 | 'form_callback' => 'qw_filter_search_form',
12 | 'query_args_callback' => 'qw_generate_query_args_search',
13 | 'query_display_types' => array( 'page', 'widget' ),
14 | // exposed
15 | 'exposed_form' => 'qw_filter_search_exposed_form',
16 | 'exposed_process' => 'qw_filter_search_exposed_process',
17 | );
18 |
19 | return $filters;
20 | }
21 |
22 | function qw_generate_query_args_search( &$args, $filter ) {
23 | $args['s'] = $filter['values']['search'];
24 | }
25 |
26 | function qw_filter_search_form( $filter ) {
27 | if ( ! isset( $filter['values']['search'] ) ) {
28 | $filter['values']['search'] = '';
29 | }
30 | ?>
31 |
32 |
36 |
37 |
64 |
67 | 'Tags',
10 | 'description' => 'Select which tags to use.',
11 | 'form_callback' => 'qw_filter_tags_form',
12 | 'query_args_callback' => 'qw_generate_query_args_tags',
13 | 'query_display_types' => array( 'page', 'widget' ),
14 | );
15 |
16 | return $filters;
17 | }
18 |
19 | function qw_filter_tags_form( $filter ) {
20 | $tag_ops = array(
21 | "tag__in" => "Any of the selected tags",
22 | "tag__and" => "All of the selected tags",
23 | "tag__not_in" => "None of the selected tags",
24 | );
25 | ?>
26 |
27 | FALSE ) );
29 | foreach ( $tags as $tag ) {
30 | $tag_checked = ( isset( $filter['values']['tags'][ $tag->term_id ] ) ) ? 'checked="checked"' : '';
31 | ?>
32 |
33 | />
38 | name; ?>
39 |
40 |
43 |
44 | Tag Options - show posts that have:
45 |
46 |
48 | $title ) {
50 | $selected = ( $filter['values']['tag_operator'] == $op ) ? 'selected="selected"' : '';
51 | ?>
52 | >
54 |
57 |
58 |
59 | 'Taxonomy Relation',
11 | 'description' => 'Define how multiple taxonomy filters interact with each other.',
12 | 'form_callback' => 'qw_filter_taxonomy_relation_form',
13 | 'query_args_callback' => 'qw_filter_taxonomy_relation_args',
14 | 'query_display_types' => array( 'page', 'widget' ),
15 | // exposed
16 | //'exposed_form' => 'qw_filter_taxonomy_relation_exposed_form',
17 | //'exposed_process' => 'qw_filter_taxonomy_relation_exposed_process',
18 | //'exposed_settings_form_callback' => 'qw_filter_taxonomy_relation_exposed_settings_form',
19 | );
20 |
21 | return $filters;
22 | }
23 |
24 | /*
25 | * Convert values into query args
26 | */
27 | function qw_filter_taxonomy_relation_args( &$args, $filter ) {
28 | if ( isset( $filter['values']['taxonomy_relation'] ) ) {
29 | $args['tax_query']['relation'] = $filter['values']['taxonomy_relation'];
30 | }
31 | }
32 |
33 | /*
34 | * Filter form
35 | */
36 | function qw_filter_taxonomy_relation_form( $filter ) {
37 | $tax_rel_ops = array( "AND", "OR" );
38 | ?>
39 |
40 |
42 |
46 | >
48 |
51 |
52 |
53 | How do multiple taxonomy filters relate to each
54 | other?
55 | AND requires posts to contain at least one term from each taxonomy
56 | filter. OR allows posts to contain any terms from all of the taxonomy
57 | filters.
58 |
59 | 'Categories',
11 | 'description' => 'Override output based on categories',
12 | 'form_callback' => 'qw_override_categories_form',
13 | 'get_query_callback' => 'qw_override_categories_get_query',
14 | );
15 |
16 | return $overrides;
17 | }
18 |
19 | /**
20 | * Hook into qw_pre_save and add save additional data
21 | * Save term relationships to the query_override_terms table
22 | *
23 | * @param $options
24 | * @param $query_id
25 | *
26 | * @return mixed
27 | */
28 | function qw_override_categories_pre_save( $options, $query_id ) {
29 |
30 | // no matter what, we delete all previous relationships
31 | global $wpdb;
32 | $table = $wpdb->prefix . "query_override_terms";
33 |
34 | // get a list of term_ids from this taxonomy for pre-save deletion
35 | $terms = get_terms( 'category', array( 'hide_empty' => FALSE ) );
36 |
37 | // delete all existing relationships
38 | foreach ( $terms as $term ) {
39 | $wpdb->delete( $table,
40 | array(
41 | 'query_id' => $query_id,
42 | 'term_id' => $term->term_id,
43 | ) );
44 | }
45 |
46 | // merge tags
47 | if ( isset( $options['override']['cats']['values'] ) &&
48 | is_array( $options['override']['cats']['values'] )
49 | ) {
50 | // new relationships to save
51 | $insert_terms = array();
52 | foreach ( $options['override']['cats']['values'] as $term_id => $name ) {
53 | if ( term_exists( $term_id, 'category' ) ) {
54 | $insert_terms[] = $term_id;
55 | }
56 | }
57 |
58 | // loop through all terms and insert them
59 | foreach ( $insert_terms as $term_id ) {
60 | $wpdb->insert( $table,
61 | array(
62 | 'query_id' => $query_id,
63 | 'term_id' => $term_id,
64 | ) );
65 | }
66 | }
67 |
68 | return $options;
69 | }
70 |
71 | /**
72 | * Settings for this override
73 | *
74 | * @param $override
75 | */
76 | function qw_override_categories_form( $override ) {
77 | $category_ids = get_terms( 'category',
78 | array( 'fields' => 'ids', 'hide_empty' => 0 ) );
79 | ?>
80 | Select which categories to override.
81 |
82 |
87 |
88 | />
93 |
94 |
95 |
98 |
99 | is_category() && $wp_query->is_archive() ) {
110 | $term = $wp_query->get_queried_object();
111 | if ($term instanceof \WP_Term) {
112 | $query_id = qw_get_query_by_override_term($term->term_id);
113 |
114 | if ($query_id && $qw_query = qw_get_query($query_id)) {
115 |
116 | // add the appropriate filter to the query
117 | $qw_query->add_handler_item('filter',
118 | 'categories',
119 | array(
120 | 'cat_operator' => 'cat',
121 | 'cats' => array($term->term_id => $term->name),
122 | ))
123 | // override the post title
124 | ->override_options(array(
125 | 'display' => array(
126 | 'title' => single_term_title('', false),
127 | )
128 | ));
129 |
130 | return $qw_query;
131 | }
132 | }
133 | }
134 |
135 | return FALSE;
136 | }
--------------------------------------------------------------------------------
/includes/overrides/post_type_archive.php:
--------------------------------------------------------------------------------
1 | 'Post Types',
12 | 'description' => 'Override archive output based on post type',
13 | 'form_callback' => 'qw_override_post_type_archive_form',
14 | 'get_query_callback' => 'qw_override_post_type_archive_get_query',
15 | );
16 |
17 | return $overrides;
18 | }
19 |
20 | /**
21 | * Hook into qw_pre_save and add save additional data
22 | * Save term relationships to the query_override_terms table
23 | *
24 | * @param $options
25 | * @param $query_id
26 | *
27 | * @return mixed
28 | */
29 | function qw_override_post_type_archive_pre_save( $options, $query_id ) {
30 | if ( ! isset( $options['override'] ) ) {
31 | return $options;
32 | }
33 |
34 | if ( ! is_array( $options['override'] ) ){
35 | return $options;
36 | }
37 |
38 | $post_type_archives = get_option( '_qw_override_post_type_archives', array() );
39 |
40 | foreach ( $options['override'] as $name => $override ) {
41 | if ( $override['type'] == 'post_type_archive' && is_array( $override['values'] ) ) {
42 | foreach ( $override['values'] as $type ){
43 | $post_type_archives[ $type ] = $query_id;
44 | }
45 | }
46 | }
47 |
48 | update_option( '_qw_override_post_type_archives', $post_type_archives );
49 |
50 | return $options;
51 | }
52 |
53 | /**
54 | * Clean up after a deleted query
55 | *
56 | * @param $query_id
57 | */
58 | function qw_override_post_type_delete_query( $query_id ){
59 | $post_type_archives = get_option( '_qw_override_post_type_archives', array() );
60 |
61 | foreach ( $post_type_archives as $type => $_query_id ){
62 | if ( $query_id == $_query_id ){
63 | unset( $post_type_archives[ $type ] );
64 | }
65 | }
66 |
67 | update_option( '_qw_override_post_type_archives', $post_type_archives );
68 | }
69 |
70 | /**
71 | * Settings for this override
72 | *
73 | * @param $override
74 | */
75 | function qw_override_post_type_archive_form( $override ) {
76 | $post_types = qw_all_post_types();
77 | ?>
78 | Select which post types to override.
79 |
80 |
84 |
85 | />
90 |
91 |
92 |
95 |
96 | is_post_type_archive() ) {
109 | $post_types = get_query_var( 'post_type' );
110 | // Always deal with it as an array.
111 | $post_types = is_array( $post_types ) ? $post_types : [ $post_types ];
112 | $post_type_archives = get_option( '_qw_override_post_type_archives', array() );
113 |
114 | // Multiple post types can be overridden by a single query.
115 | $valid_post_types = [];
116 | $found_query = null;
117 | foreach ( $post_types as $post_type) {
118 | // Ensure the given post type is a QW override.
119 | if ( !isset( $post_type_archives[ $post_type ] ) ) {
120 | continue;
121 | }
122 |
123 | // If we haven't determined the query yet, set the first one.
124 | if ( !$found_query ) {
125 | $found_query = qw_get_query( (int) $post_type_archives[ $post_type ] );
126 | }
127 |
128 | // If we have a query, ensure that
129 | if ( $found_query && $found_query->id == $post_type_archives[ $post_type ] ) {
130 | $valid_post_types[] = $post_type;
131 | }
132 | }
133 |
134 | if ( $found_query ) {
135 | // add the appropriate filter to the query
136 | $found_query->add_handler_item( 'filter',
137 | 'post_type',
138 | $valid_post_types
139 | );
140 |
141 | return $found_query;
142 | }
143 | }
144 |
145 | return FALSE;
146 | }
147 |
--------------------------------------------------------------------------------
/includes/overrides/tags.php:
--------------------------------------------------------------------------------
1 | 'Tags',
11 | 'description' => 'Override output based on tags',
12 | 'form_callback' => 'qw_override_tags_form',
13 | 'get_query_callback' => 'qw_override_tags_get_query',
14 | );
15 |
16 | return $overrides;
17 | }
18 |
19 | /**
20 | * Hook into qw_pre_save and add save additional data*
21 | * Save term relationships to the query_override_terms table
22 | *
23 | * @param $options
24 | * @param $query_id
25 | *
26 | * @return mixed
27 | */
28 | function qw_override_tags_pre_save( $options, $query_id ) {
29 |
30 | // no matter what, we delete all previous relationships
31 | global $wpdb;
32 | $table = $wpdb->prefix . "query_override_terms";
33 |
34 | // get a list of term_ids from this taxonomy for pre-save deletion
35 | $terms = get_terms( 'post_tag', array( 'hide_empty' => FALSE ) );
36 |
37 | // delete all existing relationships
38 | foreach ( $terms as $term ) {
39 | $wpdb->delete( $table,
40 | array(
41 | 'query_id' => $query_id,
42 | 'term_id' => $term->term_id,
43 | ) );
44 | }
45 |
46 | // merge tags
47 | if ( isset( $options['override']['tags']['values'] ) &&
48 | is_array( $options['override']['tags']['values'] )
49 | ) {
50 | // new relationships to save
51 | $insert_terms = array();
52 | foreach ( $options['override']['tags']['values'] as $term_id => $name ) {
53 | if ( term_exists( $term_id, 'post_tag' ) ) {
54 | $insert_terms[] = $term_id;
55 | }
56 | }
57 |
58 | // loop through all terms and insert them
59 | foreach ( $insert_terms as $term_id ) {
60 | $wpdb->insert( $table,
61 | array(
62 | 'query_id' => $query_id,
63 | 'term_id' => $term_id,
64 | ) );
65 | }
66 | }
67 |
68 | return $options;
69 | }
70 |
71 | /**
72 | * Settings for this override
73 | *
74 | * @param $override
75 | */
76 | function qw_override_tags_form( $override ) {
77 | $tags = get_terms( 'post_tag', array( 'hide_empty' => FALSE ) );
78 | ?>
79 | Select which tags to override.
80 |
81 |
83 |
84 | term_id ] ) ); ?> />
89 | name; ?>
90 |
91 |
94 |
95 | is_tag() && $wp_query->is_archive() ) {
106 | $term = $wp_query->get_queried_object();
107 | $query_id = qw_get_query_by_override_term( $term->term_id );
108 |
109 | if ( $query_id && $qw_query = qw_get_query( $query_id ) ) {
110 |
111 | // add the appropriate filter to the query
112 | $qw_query->add_handler_item( 'filter',
113 | 'categories',
114 | array(
115 | 'tag_operator' => 'tag__in',
116 | 'tags' => array( $term->term_id => $term->name ),
117 | ) )
118 | // override the post title
119 | ->override_options( array(
120 | 'display' => array(
121 | 'title' => single_term_title( '', FALSE ),
122 | )
123 | ) );
124 |
125 | return $qw_query;
126 | }
127 | }
128 |
129 | return FALSE;
130 | }
131 |
--------------------------------------------------------------------------------
/includes/overrides/taxonomies.php:
--------------------------------------------------------------------------------
1 | 'Taxonomies',
12 | 'description' => 'Override term archive pages for an entire taxonomy.',
13 | 'form_callback' => 'qw_override_taxonomies_form',
14 | 'get_query_callback' => 'qw_override_taxonomies_get_query'
15 | );
16 |
17 | return $overrides;
18 | }
19 |
20 | /**
21 | * Hook into qw_pre_save and add save additional data
22 | *
23 | * @param $options
24 | * @param $query_id
25 | *
26 | * @return mixed
27 | */
28 | function qw_override_taxonomies_pre_save( $options, $query_id ) {
29 |
30 | if ( isset( $options['override']['taxonomies'] ) &&
31 | is_array( $options['override']['taxonomies'] )
32 | ) {
33 | $override = $options['override']['taxonomies'];
34 | $taxonomies = get_taxonomies( array( 'public' => TRUE, ),
35 | 'objects' );
36 | $_qw_override_taxonomies = get_option( '_qw_override_taxonomies',
37 | array() );
38 |
39 | /*
40 | * expecting
41 | * array(
42 | * '{$taxonomy->name}__{$query_id}' => array(
43 | * 'query_id' => $query_id,
44 | * 'taxonomy' => $taxonomy->name,
45 | * )
46 | * )
47 | */
48 | // loop through all taxonomies so we can know what was not submitted
49 | foreach ( $taxonomies as $taxonomy ) {
50 | $key = "{$taxonomy->name}__{$query_id}";
51 |
52 | // see if this taxonomy checkbox was submitted
53 | if ( isset( $override['values'][ $taxonomy->name ] ) ) {
54 | $_qw_override_taxonomies[ $key ] = array(
55 | 'query_id' => $query_id,
56 | 'taxonomy' => $taxonomy->name,
57 | );
58 | } // otherwise, remove any existing instances of this query
59 | else if ( isset( $_qw_override_taxonomies[ $key ] ) ) {
60 | unset( $_qw_override_taxonomies[ $key ] );
61 | }
62 | }
63 |
64 | // need to save overrides somewhere quickly accessible
65 | // eg, _qw_override_taxonomies__category = query_id
66 | update_option( '_qw_override_taxonomies', $_qw_override_taxonomies );
67 |
68 | // clean up soem redundant data from the form
69 | $options['override']['taxonomies'] = $options['override']['taxonomies']['values'];
70 | }
71 |
72 | return $options;
73 | }
74 |
75 | /**
76 | * QW hook 'qw_delete_query'
77 | *
78 | * @param $query_id
79 | */
80 | function qw_override_taxonomies_delete_query( $query_id ){
81 | $_qw_override_taxonomies = get_option( '_qw_override_taxonomies', array() );
82 | foreach ( $_qw_override_taxonomies as $key => $values ) {
83 | if ( $values['query_id'] == $query_id ) {
84 | unset( $_qw_override_taxonomies[ $key ] );
85 | }
86 | }
87 |
88 | update_option( '_qw_override_taxonomies', $_qw_override_taxonomies );
89 | }
90 |
91 | /**
92 | * Settings for this override
93 | *
94 | * @param $override
95 | */
96 | function qw_override_taxonomies_form( $override ) {
97 | $taxonomies = get_taxonomies( array( 'public' => TRUE, ), 'objects' );
98 | ?>
99 | Select which tags to override.
100 |
101 |
103 |
104 | name ] ) ); ?> />
109 | labels->name; ?>
110 |
111 |
114 |
115 | is_archive() && ( $wp_query->is_tag() || $wp_query->is_category() || $wp_query->is_tag() ) ) {
126 | $term = $wp_query->get_queried_object();
127 | $query_id = FALSE;
128 |
129 | // look for a taxonomies override on this term->taxonomy
130 | $_qw_override_taxonomies = get_option( '_qw_override_taxonomies',
131 | array() );
132 |
133 | foreach ( $_qw_override_taxonomies as $key => $values ) {
134 | if ( $values['taxonomy'] == $term->taxonomy ) {
135 | $query_id = $values['query_id'];
136 | break;
137 | }
138 | }
139 |
140 | if ( $query_id && $qw_query = qw_get_query( $query_id ) ) {
141 |
142 | // add the appropriate filter to the query
143 | $qw_query->add_handler_item( 'filter',
144 | 'taxonomy_' . $term->taxonomy,
145 | array(
146 | 'terms' => array( $term->term_id => $term->name ),
147 | 'operator' => 'IN',
148 | 'include_children' => TRUE,
149 | ) )
150 | // override the post title
151 | ->override_options( array(
152 | 'display' => array(
153 | 'title' => single_term_title( '', FALSE ),
154 | ),
155 | ) );
156 |
157 | return $qw_query;
158 | }
159 | }
160 |
161 | return FALSE;
162 | }
--------------------------------------------------------------------------------
/includes/pages.php:
--------------------------------------------------------------------------------
1 | query_vars['category_name'] ) ) {
10 | $op = 'category';
11 | } else if ( is_tag() || ! empty( $wp_query->query_vars['tag'] ) ) {
12 | $op = 'tag';
13 | } else if ( is_404() ) {
14 | $op = '404';
15 | } else if ( is_home() ) {
16 | $op = 'home';
17 | } else if ( is_single() ) {
18 | // single is not pages
19 | $op = 'single';
20 | } else if ( is_page() ) {
21 | $op = 'page';
22 | } else if ( is_author() ) {
23 | $op = 'author';
24 | } else if ( is_search() ) {
25 | $op = 'search';
26 | } else if ( is_paged() ) {
27 | $op = 'paged';
28 | } else {
29 | $op = 'default';
30 | }
31 |
32 | // fix incorrectly identifying query pages as categories or tags
33 | // depending on permalink structures
34 | if ( $op == 'category' ||
35 | $op == 'tag'
36 | ) {
37 | if ( $wp_query->found_posts == 0 ) {
38 | $op = '404';
39 | }
40 | }
41 |
42 | return $op;
43 | }
44 |
45 | /*
46 | * Handle the qw path for pages
47 | */
48 | function qw_get_path() {
49 | global $wpdb;
50 |
51 | $request_uri = $_SERVER['REQUEST_URI'];
52 | $request_uri = explode( "?", $request_uri );
53 | // Look at the requested uri w/o paginiation involved
54 | $dirty_path = explode( '/page/', $request_uri[0] );
55 |
56 | // Clean the result for DB
57 | $path = esc_sql( ltrim( $dirty_path[0], '/' ) );
58 |
59 | return $path;
60 | }
61 |
62 | //********* New page handling ********************/
63 |
64 | // http://stackoverflow.com/questions/12133200/how-do-i-create-a-route-in-wordpress
65 | add_action( 'parse_request', 'qw_route_requests' );
66 | function qw_route_requests( $wp ) {
67 | qw_execute_query_page();
68 | }
69 |
70 | function qw_execute_query_page() {
71 |
72 | global $wp_query, $wpdb;
73 | // page op is based on WP tags like is_category() && is_404()
74 | $op = qw_get_page_op();
75 |
76 | $qw_table = $wpdb->prefix . "query_wrangler";
77 | $qot_table = $wpdb->prefix . "query_override_terms";
78 |
79 | // We'll need to override query options
80 | $options_override = array();
81 |
82 | // get current page query-like path
83 | $path = qw_get_path();
84 |
85 | // make sure a path exists
86 | if ( empty( $path ) ) {
87 | return;
88 | }
89 |
90 | // fix the query paging
91 | if ( $paged = qw_get_page_number( $wp_query ) ) {
92 | $wp_query->query_vars['paged'] = $paged;
93 | $wp_query->query_vars['page'] = $paged;
94 | }
95 |
96 | /*
97 | * 404 -> Query type = Page
98 | */
99 | if ( $op == '404' ||
100 | $op == 'default'
101 | ) {
102 | // include Template Wrangler
103 | if ( ! function_exists( 'theme' ) ) {
104 | include_once QW_PLUGIN_DIR . '/template-wrangler.php';
105 | }
106 |
107 | // take into account trailing slash
108 | if ( substr( $path, strlen( $path ) - 1, 1 ) != '/' ) {
109 | $alt_path = $path . '/';
110 | } else {
111 | $alt_path = substr( $path, 0, strlen( $path ) - 1 );
112 | }
113 |
114 | // Look for the query path given
115 | $sql = "SELECT id,name,path,data FROM " . $qw_table . " WHERE type = 'page' AND (path = '" . $path . "' OR path = '" . $alt_path . "')";
116 | $rows = $wpdb->get_results( $sql );
117 | }
118 |
119 | // got results for a query
120 | if ( isset( $rows[0] ) && is_object( $rows[0] ) && $query = $rows[0] ) {
121 | //
122 | // pass the paged value into the query
123 | $options_override['args']['paged'] = $paged;
124 |
125 | // actual options
126 | $options = qw_unserialize( $query->data );
127 |
128 | // resulting query
129 | $themed_query = qw_execute_query( $query->id,
130 | $options_override,
131 | FALSE );
132 |
133 | // The title of the query
134 | $post_title = ( $options['display']['title'] ) ? $options['display']['title'] : $query->name;
135 |
136 | // Make the post object
137 | $post = new stdClass();
138 | $post->ID = - 42; // Arbitrary post id
139 | $post->post_title = $post_title;
140 | $post->post_content = $themed_query;
141 | $post->post_status = 'publish';
142 | $post->post_type = 'page';
143 | $post->post_category = array( 'uncategorized' );
144 | $post->post_excerpt = '';
145 | $post->ancestors = array();
146 |
147 | // set some query information
148 | $wp_query->queried_object = $post;
149 | $wp_query->post = $post;
150 | $wp_query->found_posts = TRUE;
151 | $wp_query->post_count = TRUE;
152 | //$wp_query->max_num_pages = true;
153 | $wp_query->is_single = TRUE;
154 | $wp_query->is_posts_page = TRUE;
155 | $wp_query->is_page = TRUE;
156 | $wp_query->posts = array( $post );
157 | $wp_query->is_404 = FALSE;
158 | $wp_query->is_post = FALSE;
159 | $wp_query->is_home = FALSE;
160 | $wp_query->is_archive = FALSE;
161 | $wp_query->is_category = FALSE;
162 |
163 | // According to http://codex.wordpress.org/Plugin_API/Action_Reference
164 | // we can safely exit here. The template will take care of the rest.
165 | // chosen template path
166 | $template_path = locate_template( array( $options['display']['page']['template-file'] ) );
167 | if ( ! file_exists( $template_path ) ) {
168 | $template_path = locate_template( array( qw_default_template_file() ) );
169 | }
170 |
171 | include( $template_path );
172 |
173 | exit();
174 | // */
175 | }
176 | }
--------------------------------------------------------------------------------
/includes/php-polyfill.php:
--------------------------------------------------------------------------------
1 | $v) {
20 | $target[$i] = $v;
21 | }
22 | }
23 | return $target;
24 | }
25 | }
26 |
27 | /**
28 | * Descends into sub-arrays when replacing values by key in $target array.
29 | *
30 | */
31 | if (!function_exists("array_replace_recursive")) {
32 | function array_replace_recursive($target/*, $from1, $from2, ...*/) {
33 | $merge = func_get_args();
34 | array_shift($merge);
35 | // loop through all merge arrays
36 | foreach ($merge as $from) {
37 | foreach ($from as $i=>$v) {
38 | // just add (wether array or scalar) if key does not exist yet
39 | if (!isset($target[$i])) {
40 | $target[$i] = $v;
41 | }
42 | // dive in
43 | elseif (is_array($v) && is_array($target[$i])) {
44 | $target[$i] = array_replace_recursive($target[$i], $v);
45 | }
46 | // replace
47 | else {
48 | $target[$i] = $v;
49 | }
50 | }
51 | }
52 | return $target;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/includes/sorts/default_sorts.php:
--------------------------------------------------------------------------------
1 | 'The Select Option Label',
14 |
15 | // some help text for the user about how this key works
16 | 'description' => 'A description of how this sort works',
17 |
18 | // (optional) the WP_Query argument's value (essentially 'orderby_value')
19 | // defaults to: the hook_key
20 | // $args[$sort['orderby_key']] = $sort['type'];
21 | 'type' => 'wp_query_argument_key'
22 |
23 | // (optional) a custom callback function for placing form values into a WP_Query as arguments
24 | // defaults to:
25 | // $args[$sort['orderby_key']] = $sort['type'];
26 | // $args[$sort['order_key']] = $sort['order_value'];
27 | 'query_args_callback' => 'my_sort_option_args_callback',
28 |
29 | // (optional) a custom callback for sort options forms
30 | // if callback and template both aren't set,
31 | // defaults to: 'qw_form_default_sort_order_options'
32 | 'form_callback' => 'my_sort_option_form_callback',
33 |
34 | // (optional) a template wrangler form template
35 | 'form_template' => 'my_tw_form_template',
36 |
37 | // (optional) the WP_Query argument key equivalent to WP_Query's 'orderby'
38 | // defaults to: 'orderby'
39 | 'orderby_key' => 'my_orderby_key',
40 |
41 | // (optional) the WP_Query argument key equivalent to WP_Query's 'order'
42 | // defaults to: 'order'
43 | 'order_key' => 'my_order_key',
44 |
45 | // (optional) order options provided in a select menu
46 | // defaults to: below values
47 | 'order_options' => array(
48 | 'ASC' => 'Ascending',
49 | 'DESC' => 'Descending',
50 | ),
51 | );
52 |
53 | */
54 | function qw_default_sort_options( $sort_options ) {
55 |
56 | $sort_options['author_id'] = array(
57 | 'title' => 'Author',
58 | 'description' => 'The content author ID.',
59 | 'type' => 'author',
60 | );
61 | $sort_options['comment_count'] = array(
62 | 'title' => 'Comment Count',
63 | 'description' => 'Total number of comments on a piece of content.',
64 | );
65 | $sort_options['menu_order'] = array(
66 | 'title' => 'Menu Order (for Page post_types)',
67 | 'description' => 'Menu Order of a Page.',
68 | );
69 | $sort_options['meta_value'] = array(
70 | 'title' => 'Meta value',
71 | 'description' => "Note that a 'meta_key=keyname' filter must also be present in the query. Good for sorting words, but not numbers.",
72 | );
73 | $sort_options['meta_value_num'] = array(
74 | 'title' => 'Meta value number',
75 | 'description' => "Order by numeric meta value. Also note that a 'meta_key' filter must be present in the query. This value allows for numerical sorting as noted above in 'meta_value'.",
76 | );
77 | $sort_options['none'] = array(
78 | 'title' => 'None',
79 | 'description' => 'No sort order.',
80 | 'order_options' => array(
81 | 'none' => 'None',
82 | )
83 | );
84 | $sort_options['post__in'] = array(
85 | 'title' => 'Post__in order',
86 | 'description' => 'Preserve post ID order given in the post__in array.',
87 | 'order_options' => FALSE,
88 | );
89 | $sort_options['post_date'] = array(
90 | 'title' => 'Date',
91 | 'description' => 'The posted date of content.',
92 | 'type' => 'date',
93 | );
94 | $sort_options['post_ID'] = array(
95 | 'title' => 'Post ID',
96 | 'description' => 'The ID of the content.',
97 | 'type' => 'ID',
98 | );
99 | $sort_options['post_modified'] = array(
100 | 'title' => 'Date Modified',
101 | 'description' => 'Date content was last modified.',
102 | 'type' => 'modified',
103 | );
104 | $sort_options['post_parent'] = array(
105 | 'title' => 'Parent',
106 | 'description' => 'The parent post for content.',
107 | 'type' => 'parent',
108 | );
109 | $sort_options['post_title'] = array(
110 | 'title' => 'Title',
111 | 'description' => 'The title of the content.',
112 | 'type' => 'title',
113 | );
114 | $sort_options['rand'] = array(
115 | 'title' => 'Random',
116 | 'description' => 'Random order.',
117 | );
118 |
119 | return $sort_options;
120 | }
121 |
122 | /*
123 | * Default sort options 'order' options form
124 | */
125 | function qw_form_default_sort_order_options( $sort ) {
126 | if ( ! empty( $sort['order_options'] ) ) { ?>
127 |
128 |
129 | Order by
130 | :
131 |
133 | $label ) {
135 | $selected = ( $sort['values']['order_value'] == $value ) ? 'selected="selected"' : '';
136 | ?>
137 | >
139 |
140 |
141 |
144 |
145 |
146 | Select how to order the results.
147 |
12 |
13 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/templates/query-excerpt.php:
--------------------------------------------------------------------------------
1 |
12 |
13 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/templates/query-ordered_list.php:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/templates/query-table.php:
--------------------------------------------------------------------------------
1 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/templates/query-unformatted.php:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/templates/query-unordered_list.php:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/templates/query-wrapper.php:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 |
45 |
46 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/widget.query.php:
--------------------------------------------------------------------------------
1 | 'query-wrangler-widget',
33 | 'description' => __( 'A Query Wrangler Widget',
34 | 'qw-widget' )
35 | );
36 |
37 | // Widget control settings.
38 | $control_ops = array( 'id_base' => 'query-wrangler-widget' );
39 |
40 | // Create the widget.
41 | parent::__construct( 'query-wrangler-widget',
42 | __( 'Query Wrangler Widget', 'querywranglerwidget' ),
43 | $widget_ops,
44 | $control_ops );
45 | }
46 |
47 | /**
48 | * How to display the widget on the screen.
49 | */
50 | function widget( $args, $instance ) {
51 | $output = '';
52 | $options_override = array();
53 | $settings = QW_Settings::get_instance();
54 |
55 | if ( isset( $instance['qw-widget'] ) && ! empty( $instance['qw-widget'] ) ) {
56 |
57 | // shortcode args
58 | if ( isset( $instance['qw-shortcode-args'] ) && ! empty( $instance['qw-shortcode-args'] ) ) {
59 | if ( stripos( $instance['qw-shortcode-args'], '{{' ) !== FALSE ) {
60 | $instance['qw-shortcode-args'] = qw_contextual_tokens_replace( $instance['qw-shortcode-args'] );
61 | }
62 | $options_override['shortcode_args'] = html_entity_decode( $instance['qw-shortcode-args'] );
63 | }
64 |
65 | $options = qw_generate_query_options( $instance['qw-widget'] );
66 | $widget_content = qw_execute_query( $instance['qw-widget'], $options_override );
67 |
68 | $show_title = ( isset( $instance['qw-show-widget-title'] ) && ! empty( $instance['qw-show-widget-title'] ) );
69 | $title = ( $show_title && $options['display']['title'] ) ? $args['before_title'] . $options['display']['title'] . $args['after_title'] : '';
70 |
71 |
72 | if ( $settings->get( 'widget_theme_compat' ) ) {
73 | $output = $args['before_widget'] .
74 | $title .
75 | $widget_content .
76 | $args['after_widget'];
77 |
78 | }
79 | else {
80 | $output = $title . $widget_content;
81 | }
82 | }
83 | print $output;
84 | }
85 |
86 | /**
87 | * Update the widget settings.
88 | */
89 | function update( $new_instance, $old_instance ) {
90 | $instance = array_replace( array(
91 | 'title' => '',
92 | 'qw-widget' => '',
93 | 'qw-shortcode-args' => '',
94 | 'qw-show-widget-title' => '',
95 | ), $old_instance, $new_instance );
96 |
97 | return $instance;
98 | }
99 |
100 | /**
101 | * Displays the widget settings controls on the widget panel.
102 | * Make use of the get_field_id() and get_field_name() function
103 | * when creating your form elements. This handles the confusing stuff.
104 | */
105 | function form( $instance ) {
106 | // Set up some default widget settings.
107 | $defaults = array(
108 | 'title' => __( 'QW Widget',
109 | 'querywranglerwidget' ),
110 | 'qw-widget' => '',
111 | 'qw-shortcode-args' => '',
112 | 'qw-show-widget-title' => ''
113 | );
114 | $instance = wp_parse_args( (array) $instance, $defaults );
115 | $widgets = qw_get_all_widgets();
116 | $this_widget_value = isset( $widgets[ $instance['qw-widget'] ] ) ? $widgets[ $instance['qw-widget'] ] : '';
117 | ?>
118 |
120 |
123 |
124 | /> Show query's Display Title as Widget
128 | Title
129 |
130 |
131 |
133 |
134 |
135 |
136 |
137 |
140 | - Select -
141 | $name ) {
144 | if ( $instance['qw-widget'] == $query_id ) {
145 | $query_selected = 'selected="selected"';
146 | $selected_query_id = $query_id;
147 | } else {
148 | $query_selected = '';
149 | }
150 | ?>
151 |
152 | value="">
153 |
156 |
157 |
158 |
159 | Edit
160 | this Query
161 |
162 |
163 |
165 |
166 |
167 |
173 |
174 |