├── .babelrc
├── .editorconfig
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── composer.json
├── dist
├── css
│ ├── style.css.map
│ ├── style.min.css
│ └── style.min.css.map
├── images
│ ├── logotype.png
│ └── plus-minus.png
└── js
│ ├── main.min.js
│ └── main.min.js.map
├── docker-compose.yml
├── languages
├── papi-fr_FR.mo
├── papi-fr_FR.po
├── papi-sv_SE.mo
├── papi-sv_SE.po
└── papi.pot
├── package-lock.json
├── papi-loader.php
└── src
├── admin
├── class-papi-admin-ajax.php
├── class-papi-admin-assets.php
├── class-papi-admin-columns.php
├── class-papi-admin-entry-post.php
├── class-papi-admin-entry-taxonomy.php
├── class-papi-admin-entry.php
├── class-papi-admin-menu.php
├── class-papi-admin-meta-box-tabs.php
├── class-papi-admin-meta-box.php
├── class-papi-admin-meta-handler.php
├── class-papi-admin-option-handler.php
├── class-papi-admin-page-type-switcher.php
├── class-papi-admin-view.php
├── class-papi-admin.php
└── views
│ ├── add-new-page.php
│ └── partials
│ └── add-new-item.php
├── cli
├── class-papi-cli-command.php
├── class-papi-cli-post-command.php
├── class-papi-cli-term-command.php
├── class-papi-cli-type-command.php
└── class-papi-cli.php
├── core
├── class-papi-core-autoload.php
├── class-papi-core-box.php
├── class-papi-core-conditional-rule.php
├── class-papi-core-conditional-rules.php
├── class-papi-core-conditional.php
├── class-papi-core-container.php
├── class-papi-core-data-handler.php
├── class-papi-core-data.php
├── class-papi-core-meta-store.php
├── class-papi-core-property.php
├── class-papi-core-tab.php
└── class-papi-core-type.php
├── lib
├── core
│ ├── cache.php
│ ├── conditional.php
│ ├── data.php
│ ├── deprecated.php
│ ├── io.php
│ ├── meta.php
│ ├── post.php
│ ├── property.php
│ ├── slug.php
│ ├── tabs.php
│ ├── taxonomy.php
│ ├── template.php
│ ├── url.php
│ └── utilities.php
├── fields
│ ├── option.php
│ ├── page.php
│ └── taxonomy.php
├── hooks
│ ├── actions.php
│ ├── filters-page-type.php
│ ├── filters-taxonomy-type.php
│ └── filters.php
└── types
│ ├── entry.php
│ ├── page.php
│ └── taxonomy.php
├── papi-loader.php
├── properties
├── class-papi-property-bool.php
├── class-papi-property-checkbox.php
├── class-papi-property-color.php
├── class-papi-property-datetime.php
├── class-papi-property-divider.php
├── class-papi-property-dropdown.php
├── class-papi-property-editor.php
├── class-papi-property-email.php
├── class-papi-property-file.php
├── class-papi-property-flexible.php
├── class-papi-property-gallery.php
├── class-papi-property-group.php
├── class-papi-property-hidden.php
├── class-papi-property-html.php
├── class-papi-property-image.php
├── class-papi-property-link.php
├── class-papi-property-module.php
├── class-papi-property-number.php
├── class-papi-property-post.php
├── class-papi-property-radio.php
├── class-papi-property-reference.php
├── class-papi-property-relationship.php
├── class-papi-property-repeater.php
├── class-papi-property-sidebar.php
├── class-papi-property-string.php
├── class-papi-property-table.php
├── class-papi-property-term.php
├── class-papi-property-text.php
├── class-papi-property-url.php
├── class-papi-property-user.php
└── class-papi-property.php
├── query
└── class-papi-query.php
├── rest-api
├── class-papi-rest-api-post.php
├── class-papi-rest-api-settings.php
└── class-papi-rest-api.php
├── stores
├── class-papi-option-store.php
├── class-papi-post-store.php
└── class-papi-term-store.php
└── types
├── class-papi-attachment-type.php
├── class-papi-entry-type.php
├── class-papi-front-page-type.php
├── class-papi-module-type.php
├── class-papi-option-type.php
├── class-papi-page-type.php
└── class-papi-taxonomy-type.php
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@jitesoft/main"]
3 | }
4 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.php]
12 | indent_style = tab
13 | indent_size = 4
14 |
15 | [*.md]
16 | trim_trailing_whitespace = false
17 |
18 | [Makefile]
19 | indent_style = tab
20 | indent_size = 8
21 |
22 | [*.{js,jsx,ts,tsx,vue}]
23 | quote_type = single
24 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at [http://contributor-covenant.org/version/1/4][version]
72 |
73 | [homepage]: http://contributor-covenant.org
74 | [version]: http://contributor-covenant.org/version/1/4/
75 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013-2019 Fredrik Forsmo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Papi
2 |
3 | 
4 |
5 | [](https://github.com/wp-papi/papi/releases)
6 | [](https://packagist.org/packages/wp-papi/papi)
7 | [](https://gitter.im/wp-papi/papi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
8 | [](http://unmaintained.tech/)
9 |
10 | > `master` is unsafe. `3.x` is the stable branch.
11 |
12 | Papi has a different approach on how to work with fields and page types in WordPress. The idea is coming from how Page Type Builder in EPiServer works and has been loved by the developers.
13 |
14 | So we though why don’t use the same approach in WordPress? Papi is today running in production and has been easy to work with when it came to add new fields. Papi don’t have any admin user interface where you should add all fields, we use classes in PHP, where one class represents one page type and in your class you add all fields you need. It’s that easy!
15 |
16 | [Visit Papi’s project page](https://wp-papi.github.io/)
17 |
18 | ## A message from the author
19 |
20 | v3.2.0 will likely be the last release I plan to work on as the core maintainer of Papi since my focus has shifted from WordPress to doing more JavaScript and Go projects. I hope you understand my decision to step back from the project, if you have any questions or would be interested in take over some of the maintenance of the project please let me know. I will still be around answering questions and helping any new maintainers. Some bug fixes and/or pull request may be added (but no new versions) since me and my colleagues use Papi internally and will be continuing doing it.
21 |
22 | ## Installation
23 |
24 | If you're using Composer to manage WordPress, add Papi to your project's dependencies. Run:
25 |
26 | ```sh
27 | composer require wp-papi/papi
28 | ```
29 |
30 | Or manually add it to your `composer.json`:
31 |
32 | ```json
33 | "require": {
34 | "php": "^^7.4",
35 | "wordpress": "^4.6",
36 | "wp-papi/papi": "^3.2"
37 | }
38 | ```
39 |
40 | ## Build CSS and JavaScript
41 |
42 | Install dependencies:
43 |
44 | ```
45 | make deps
46 | ```
47 |
48 | Build CSS:
49 |
50 | ```
51 | make css
52 | ```
53 |
54 | Build JavaScript:
55 |
56 | ```
57 | make js
58 | ```
59 |
60 | ## Testing
61 |
62 | Visit the [readme](tests/README.md) file for testing.
63 |
64 | ## Coding style
65 |
66 | You can check if your contribution passes the styleguide by installing [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) and running the following in your Papi directory:
67 |
68 | ```
69 | make lint:php
70 | ```
71 |
72 | ## Contributing
73 |
74 | Visit the [contributing](CONTRIBUTING.md) file.
75 |
76 | ## Security
77 |
78 | If you discover a security vulnerability within this package, please send an e-mail to Fredrik Forsmo at security@frozzare.com. All security vulnerabilities will be promptly addressed.
79 |
80 | ## License
81 |
82 | MIT © [Fredrik Forsmo](https://github.com/frozzare)
83 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wp-papi/papi",
3 | "type": "wordpress-plugin",
4 | "license": "MIT",
5 | "description": "WordPress Page Type API with custom fields",
6 | "homepage": "https://wp-papi.github.io",
7 | "authors": [{
8 | "name": "Fredrik Forsmo",
9 | "email": "fredrik.forsmo@gmail.com",
10 | "homepage": "https://github.com/frozzare"
11 | }],
12 | "keywords": [
13 | "wordpress",
14 | "custom fields",
15 | "page type",
16 | "page",
17 | "taxonomy",
18 | "options"
19 | ],
20 | "require": {
21 | "php": "^7.4"
22 | },
23 | "require-dev": {
24 | "frozzare/wp-test-suite": "^1.0",
25 | "wp-coding-standards/wpcs": "^0.13"
26 | },
27 | "scripts": {
28 | "post-install-cmd": "if [ -f vendor/bin/phpcs ]; then \"vendor/bin/phpcs\" --config-set installed_paths vendor/wp-coding-standards/wpcs; fi",
29 | "post-update-cmd": "if [ -f vendor/bin/phpcs ]; then \"vendor/bin/phpcs\" --config-set installed_paths vendor/wp-coding-standards/wpcs; fi"
30 | },
31 | "minimum-stability": "dev",
32 | "prefer-stable": true,
33 | "extra": {
34 | "branch-alias": {
35 | "dev-master": "3.3.x-dev"
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/dist/images/logotype.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wp-papi/papi/c6621f5acbf20aa687dc98776cf3f78a4f1d87dd/dist/images/logotype.png
--------------------------------------------------------------------------------
/dist/images/plus-minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wp-papi/papi/c6621f5acbf20aa687dc98776cf3f78a4f1d87dd/dist/images/plus-minus.png
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | mysql:
5 | image: mariadb
6 | environment:
7 | - MYSQL_ROOT_PASSWORD=root
8 | phpunit:
9 | build:
10 | context: ./tests
11 | volumes:
12 | - .:/var/www/html
13 | depends_on:
14 | - mysql
15 | entrypoint: bash -c "composer install && vendor/frozzare/wp-test-suite/bin/install-wp-tests.sh wordpress_test root root mysql latest && vendor/bin/phpunit"
16 |
--------------------------------------------------------------------------------
/languages/papi-fr_FR.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wp-papi/papi/c6621f5acbf20aa687dc98776cf3f78a4f1d87dd/languages/papi-fr_FR.mo
--------------------------------------------------------------------------------
/languages/papi-sv_SE.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wp-papi/papi/c6621f5acbf20aa687dc98776cf3f78a4f1d87dd/languages/papi-sv_SE.mo
--------------------------------------------------------------------------------
/papi-loader.php:
--------------------------------------------------------------------------------
1 | __( 'Close', 'default' ),
52 | 'edit' => __( 'Edit', 'default' ),
53 | 'new' => __( 'New', 'default' ),
54 | 'remove' => __( 'Remove', 'default' ),
55 | 'requiredError' => __( 'This fields are required:', 'papi' ),
56 | ] );
57 | }
58 | }
59 |
60 | if ( papi_is_admin() ) {
61 | new Papi_Admin_Assets;
62 | }
63 |
--------------------------------------------------------------------------------
/src/admin/class-papi-admin-entry-post.php:
--------------------------------------------------------------------------------
1 | post_type = papi_get_post_type();
17 |
18 | $this->setup_actions();
19 | $this->setup_filters();
20 | }
21 |
22 | /**
23 | * Filters the fields displayed in the post revision diff UI.
24 | *
25 | * @param array $return
26 | * @param WP_Post $compare_from
27 | * @param WP_Post $compare_to
28 | *
29 | * @return array
30 | */
31 | public function get_revision_ui_diff( $return, $compare_from, $compare_to ) {
32 | $meta = get_post_meta( $compare_from->ID );
33 | $meta = is_array( $meta ) ? $meta : [];
34 |
35 | foreach ( $meta as $key => $value ) {
36 | if ( $key[0] === '_' && $key !== papi_get_page_type_key() ) {
37 | continue;
38 | }
39 |
40 | $content_from = papi_data_get( $compare_from->ID, $key );
41 | $content_to = papi_data_get( $compare_to->ID, $key );
42 |
43 | $diff = wp_text_diff( $content_from, $content_to, [
44 | 'show_split_view' => true
45 | ] );
46 |
47 | if ( $diff ) {
48 | $return[] = [
49 | 'id' => $key,
50 | 'name' => $key,
51 | 'diff' => $diff,
52 | ];
53 | }
54 | }
55 |
56 | return $return;
57 | }
58 |
59 | /**
60 | * Output hidden meta boxes.
61 | */
62 | public function hidden_meta_boxes() {
63 | global $_wp_post_type_features;
64 |
65 | if ( isset( $_wp_post_type_features[$this->post_type]['editor'] ) ) {
66 | return;
67 | }
68 |
69 | add_meta_box( 'papi-hidden-editor', 'Papi hidden editor', [$this, 'hidden_meta_box_editor'], $this->post_type );
70 | }
71 |
72 | /**
73 | * Output hidden WordPress editor.
74 | */
75 | public function hidden_meta_box_editor() {
76 | wp_editor( '', 'papiHiddenEditor' );
77 | }
78 |
79 | /**
80 | * Load post new action
81 | * Redirect to right url if no page type is set.
82 | */
83 | public function load_post_new() {
84 | $request_uri = $_SERVER['REQUEST_URI'];
85 | $post_types = papi_get_post_types();
86 |
87 | if ( in_array( $this->post_type, $post_types, true ) && strpos( $request_uri, 'page_type=' ) === false ) {
88 | $parsed_url = parse_url( $request_uri );
89 |
90 | $only_page_type = papi_filter_settings_only_page_type( $this->post_type );
91 | $page_types = papi_get_all_page_types( $this->post_type );
92 | $show_standard = false;
93 |
94 | if ( count( $page_types ) === 1 && empty( $only_page_type ) ) {
95 | $show_standard = $page_types[0]->standard_type;
96 | $show_standard = $show_standard ? papi_filter_settings_show_standard_page_type( $this->post_type ) : $show_standard;
97 | $only_page_type = $show_standard ? '' : $page_types[0]->get_id();
98 | }
99 |
100 | // Check if we should show one post type or not and
101 | // create the right url for that.
102 | if ( ! empty( $only_page_type ) && ! $show_standard ) {
103 | $url = papi_get_page_new_url( $only_page_type, false );
104 | } else {
105 | $page = 'page=papi-add-new-page,' . $this->post_type;
106 |
107 | if ( $this->post_type !== 'post' ) {
108 | $page = '&' . $page;
109 | }
110 |
111 | $url = 'edit.php?' . $parsed_url['query'] . $page;
112 | }
113 |
114 | wp_safe_redirect( $url );
115 | papi_is_admin() && exit;
116 | }
117 | }
118 |
119 | /**
120 | * Redirect post location when post is in iframe mode.
121 | *
122 | * @param string $location
123 | *
124 | * @return string
125 | */
126 | public function redirect_post_location( $location ) {
127 | if ( ! isset( $_SERVER['HTTP_REFERER'] ) ) {
128 | return $location;
129 | }
130 |
131 | $referer = $_SERVER['HTTP_REFERER'];
132 | $referer = strtolower( $referer );
133 |
134 | if ( strpos( $referer, 'papi-iframe-mode' ) === false ) {
135 | return $location;
136 | }
137 |
138 | return sprintf( '%s&papi_css[]=papi-iframe-mode', $location );
139 | }
140 |
141 | /**
142 | * Setup admin entry.
143 | */
144 | public function setup() {
145 | // Preload all page types.
146 | foreach ( papi_get_post_types() as $post_type ) {
147 | papi_get_all_entry_types( [
148 | 'args' => $post_type
149 | ] );
150 | }
151 |
152 | return ! in_array( $this->post_type, ['revision', 'nav_menu_item'], true );
153 | }
154 |
155 | /**
156 | * Setup actions.
157 | */
158 | protected function setup_actions() {
159 | add_action( 'load-post-new.php', [$this, 'load_post_new'] );
160 | add_action( 'add_meta_boxes', [$this, 'hidden_meta_boxes'], 10 );
161 | add_action( 'redirect_post_location', [$this, 'redirect_post_location'] );
162 | }
163 |
164 | /**
165 | * Setup filters.
166 | */
167 | protected function setup_filters() {
168 | add_filter( 'wp_get_revision_ui_diff', [$this, 'get_revision_ui_diff'], 10, 3 );
169 | }
170 | }
171 |
172 | if ( papi_is_admin() ) {
173 | Papi_Admin_Entry_Post::instance();
174 | }
175 |
--------------------------------------------------------------------------------
/src/admin/class-papi-admin-entry-taxonomy.php:
--------------------------------------------------------------------------------
1 | setup_actions();
20 | }
21 |
22 | /**
23 | * Add form fields to edit tags page.
24 | */
25 | public function add_form_fields() {
26 | $html_name = esc_attr( papi_get_page_type_key() );
27 | $taxonomy = papi_get_qs( 'taxonomy' );
28 | $taxonomy_object = get_taxonomy( $taxonomy );
29 |
30 | // Get only the taxonomy types that has the taxonomy.
31 | $taxonomy_types = array_filter( $this->taxonomy_types, function ( $taxonomy_type ) use ( $taxonomy ) {
32 | return in_array( $taxonomy, $taxonomy_type->taxonomy, true ) && $taxonomy_type->display( $taxonomy );
33 | } );
34 | $taxonomy_types = array_values( $taxonomy_types );
35 |
36 | // Do not display empty select if no taxonomy types.
37 | if ( empty( $taxonomy_types ) ) {
38 | return;
39 | }
40 |
41 | // Prepare taxonomy types with standard taxonomy type.
42 | $taxonomy_types = $this->prepare_taxonomy_types( $taxonomy_types );
43 |
44 | // Render a dropdown if more than one taxonomy types
45 | // exists on the taxonomy.
46 | if ( count( $taxonomy_types ) > 1 ):
47 | ?>
48 |
49 |
52 |
63 |
64 | $taxonomy_types[0]->redirect_after_create,
68 | 'data-papi-page-type-key' => true,
69 | 'name' => esc_attr( $html_name ),
70 | 'type' => 'hidden',
71 | 'value' => esc_attr( $taxonomy_types[0]->get_id() )
72 | ] );
73 | endif;
74 | }
75 |
76 | /**
77 | * Prepare taxonomy types, add standard taxonomy if it should be added.
78 | *
79 | * @param array $taxonomy_types
80 | *
81 | * @return array
82 | */
83 | protected function prepare_taxonomy_types( array $taxonomy_types ) {
84 | $taxonomy = papi_get_qs( 'taxonomy' );
85 |
86 | if ( papi_filter_settings_show_standard_taxonomy_type( $taxonomy ) ) {
87 | $id = sprintf( 'papi-standard-%s-type', $taxonomy );
88 | $taxonomy_type = new Papi_Taxonomy_Type( $id );
89 | $taxonomy_type->id = $id;
90 | $taxonomy_type->name = papi_filter_settings_standard_taxonomy_type_name( $taxonomy );
91 | $taxonomy_type->taxonomy = [$taxonomy];
92 | $taxonomy_types[] = $taxonomy_type;
93 | }
94 |
95 | usort( $taxonomy_types, function ( $a, $b ) {
96 | return strcmp( $a->name, $b->name );
97 | } );
98 |
99 | return papi_sort_order( array_reverse( $taxonomy_types ) );
100 | }
101 |
102 | /**
103 | * Setup actions.
104 | */
105 | protected function setup_actions() {
106 | add_action( 'admin_init', [$this, 'setup_taxonomies_hooks'] );
107 | }
108 |
109 | /**
110 | * Setup hooks for all taxonomies.
111 | */
112 | public function setup_taxonomies_hooks() {
113 | $this->taxonomy_types = papi_get_all_entry_types( [
114 | 'types' => 'taxonomy'
115 | ] );
116 |
117 | $taxonomies = array_reduce( $this->taxonomy_types, function ( $taxonomies, $taxonomy_type ) {
118 | return array_merge( $taxonomies, $taxonomy_type->taxonomy );
119 | }, [] );
120 | $taxonomies = array_unique( $taxonomies );
121 |
122 | foreach ( $taxonomies as $taxonomy ) {
123 | if ( is_string( $taxonomy ) && taxonomy_exists( $taxonomy ) ) {
124 | add_action( $taxonomy . '_add_form_fields', [$this, 'add_form_fields'] );
125 | }
126 | }
127 | }
128 | }
129 |
130 | if ( papi_is_admin() ) {
131 | Papi_Admin_Entry_Taxonomy::instance();
132 | }
133 |
--------------------------------------------------------------------------------
/src/admin/class-papi-admin-entry.php:
--------------------------------------------------------------------------------
1 | setup_actions();
13 | }
14 |
15 | /**
16 | * Fill labels on admin bar.
17 | */
18 | public function admin_bar_menu() {
19 | if ( $entry_type = $this->get_entry_type() ) {
20 | $this->override_labels( $entry_type );
21 | }
22 | }
23 |
24 | /**
25 | * Get current type class.
26 | *
27 | * @return Papi_Entry_Type
28 | */
29 | protected function get_entry_type() {
30 | if ( $entry_type = papi_get_entry_type_by_id( papi_get_entry_type_id() ) ) {
31 | return $entry_type;
32 | }
33 | }
34 |
35 | /**
36 | * Override labels with labels from the entry type.
37 | *
38 | * @param Papi_Entry_Type $entry_type
39 | */
40 | protected function override_labels( Papi_Entry_Type $entry_type ) {
41 | global $wp_post_types, $wp_taxonomies;
42 |
43 | if ( $entry_type->get_type() === 'taxonomy' ) {
44 | $meta_type_value = papi_get_taxonomy();
45 | } else {
46 | $meta_type_value = papi_get_post_type();
47 | }
48 |
49 | if ( empty( $meta_type_value ) || ( ! isset( $wp_post_types[$meta_type_value] ) && ! isset( $wp_taxonomies[$meta_type_value] ) ) ) {
50 | return;
51 | }
52 |
53 | foreach ( $entry_type->get_labels() as $key => $value ) {
54 | if ( empty( $value ) ) {
55 | continue;
56 | }
57 |
58 | if ( $entry_type->get_type() === 'taxonomy' && isset( $wp_taxonomies[$meta_type_value]->labels->$key ) ) {
59 | $wp_taxonomies[$meta_type_value]->labels->$key = $value;
60 | } else if ( isset( $wp_post_types[$meta_type_value]->labels->$key ) ) {
61 | $wp_post_types[$meta_type_value]->labels->$key = $value;
62 | }
63 | }
64 | }
65 |
66 | /**
67 | * Page items menu.
68 | *
69 | * This function will register all entry types
70 | * that has a fake post type. Like option types.
71 | */
72 | public function page_items_menu() {
73 | $entry_types = papi_get_all_entry_types( [
74 | 'mode' => 'exclude',
75 | 'types' => 'page'
76 | ] );
77 |
78 | foreach ( $entry_types as $entry_type ) {
79 | if ( empty( $entry_type->get_menu() ) || empty( $entry_type->name ) ) {
80 | continue;
81 | }
82 |
83 | $slug = sprintf(
84 | 'papi/%s/%s',
85 | $entry_type->get_type(),
86 | $entry_type->get_id()
87 | );
88 |
89 | add_submenu_page(
90 | $entry_type->get_menu(),
91 | $entry_type->name,
92 | $entry_type->name,
93 | $entry_type->capability,
94 | $slug,
95 | [$entry_type, 'render']
96 | );
97 | }
98 | }
99 |
100 | /**
101 | * Setup menu items for real post types.
102 | */
103 | public function post_types_menu() {
104 | global $submenu;
105 |
106 | $post_types = papi_get_post_types();
107 |
108 | foreach ( $post_types as $post_type ) {
109 | if ( ! post_type_exists( $post_type ) ) {
110 | continue;
111 | }
112 |
113 | if ( $post_type === 'post' ) {
114 | $edit_url = 'edit.php';
115 | } else {
116 | $edit_url = 'edit.php?post_type=' . $post_type;
117 | }
118 |
119 | if ( ! isset( $submenu[$edit_url], $submenu[$edit_url][10], $submenu[$edit_url][10][2] ) ) {
120 | $post_type_object = get_post_type_object( $post_type );
121 |
122 | if ( $post_type_object->show_in_menu !== true ) {
123 | $submenu[$edit_url] = [
124 | 10 => [
125 | __( 'Add New', 'papi' ),
126 | 'edit_posts',
127 | 'post-new.php'
128 | ]
129 | ];
130 | } else {
131 | continue;
132 | }
133 | }
134 |
135 | $only_page_type = papi_filter_settings_only_page_type( $post_type );
136 | $page_types = papi_get_all_page_types( $post_type );
137 | $show_standard = false;
138 |
139 | // Don't change menu item when no page types is found.
140 | if ( empty( $page_types ) ) {
141 | continue;
142 | }
143 |
144 | if ( count( $page_types ) === 1 && empty( $only_page_type ) ) {
145 | $show_standard = papi_filter_settings_show_standard_page_type( $post_type );
146 | $only_page_type = $show_standard ? '' : $page_types[0]->get_id();
147 | }
148 |
149 | if ( ! empty( $only_page_type ) && ! $show_standard ) {
150 | $submenu[$edit_url][10][2] = papi_get_page_new_url(
151 | $only_page_type,
152 | false,
153 | $post_type,
154 | [
155 | 'post_parent',
156 | 'lang'
157 | ]
158 | );
159 | } else {
160 | $page = 'papi-add-new-page,' . $post_type;
161 | $start = strpos( $edit_url, 'post_type' ) === false ? '?' : '&';
162 |
163 | $submenu[$edit_url][10][2] = sprintf(
164 | '%s%spage=%s',
165 | $edit_url,
166 | $start,
167 | $page
168 | );
169 |
170 | // Add menu item.
171 | add_menu_page(
172 | __( 'Add New', 'papi' ),
173 | __( 'Add New', 'papi' ),
174 | 'read',
175 | $page,
176 | [$this, 'render_view']
177 | );
178 |
179 | // Remove the menu item so it's hidden.
180 | remove_menu_page( $page );
181 | }
182 | }
183 | }
184 |
185 | /**
186 | * Menu callback that loads right view depending on what the `page` query string says.
187 | */
188 | public function render_view() {
189 | if ( strpos( papi_get_qs( 'page' ), 'papi' ) !== false ) {
190 | $page = str_replace( 'papi-', '', papi_get_qs( 'page' ) );
191 | $res = preg_replace( '/\,.*/', '', $page );
192 |
193 | if ( is_string( $res ) ) {
194 | $page_view = $res;
195 | }
196 | }
197 |
198 | if ( ! isset( $page_view ) ) {
199 | $page_view = null;
200 | }
201 |
202 | if ( ! is_null( $page_view ) ) {
203 | $view = new Papi_Admin_View;
204 | $view->render( $page_view );
205 | } else {
206 | echo 'Papi - 404
';
207 | }
208 | }
209 |
210 | /**
211 | * Setup actions.
212 | */
213 | protected function setup_actions() {
214 | if ( papi_is_admin() ) {
215 | add_action( 'admin_init', [$this, 'admin_bar_menu'] );
216 | add_action( 'admin_menu', [$this, 'page_items_menu'] );
217 | add_action( 'admin_menu', [$this, 'post_types_menu'] );
218 | } else {
219 | add_action( 'admin_bar_menu', [$this, 'admin_bar_menu'] );
220 | }
221 | }
222 | }
223 |
224 | new Papi_Admin_Menu;
225 |
--------------------------------------------------------------------------------
/src/admin/class-papi-admin-meta-box-tabs.php:
--------------------------------------------------------------------------------
1 | tabs = papi_tabs_setup( $tabs );
28 |
29 | if ( $render ) {
30 | $this->html();
31 | }
32 | }
33 |
34 | /**
35 | * Get the tabs that are registered.
36 | *
37 | * @return array
38 | */
39 | public function get_tabs() {
40 | return $this->tabs;
41 | }
42 |
43 | /**
44 | * Generate html for tabs and properties.
45 | */
46 | protected function html() {
47 | ?>
48 |
49 |
50 |
51 |
52 | tabs as $tab ):
54 | $css_classes = $this->tabs[0] === $tab ? 'active ' : '';
55 |
56 | if ( empty( $tab->background ) ) {
57 | // Find out if the first property has a sidebar or not. If the first property
58 | // don't have a sidebar the tab background should be white since it looks better.
59 | $no_sidebar = empty( $tab->properties ) ? false : $tab->properties[0]->sidebar;
60 | $css_classes .= ! empty( $tab->properties ) && $no_sidebar ? '' : 'white-tab';
61 | } else {
62 | $css_classes .= $tab->background === 'white' ? 'white-tab' : '';
63 | }
64 | ?>
65 | -
66 |
67 | icon ) ): ?>
68 |
69 | title ); ?>
71 |
72 |
73 |
74 |
75 |
76 | tabs as $tab ):
78 | ?>
79 |
80 | properties ); ?>
81 |
82 |
85 |
86 |
87 |
88 | capabilities ) ) {
23 | return;
24 | }
25 |
26 | if ( $box->display ) {
27 | $this->box = $box;
28 | $this->setup_actions();
29 | }
30 | }
31 |
32 | /**
33 | * Add custom css for hiding boxes with no frame in screen options.
34 | *
35 | * @return string
36 | */
37 | public function admin_head() {
38 | if ( ! $this->box->frame ) {
39 | echo sprintf(
40 | '',
41 | esc_attr( $this->box->id ),
42 | esc_attr( $this->box->id ),
43 | esc_attr( $this->box->id )
44 | );
45 | }
46 | }
47 |
48 | /**
49 | * Add css classes to meta box.
50 | *
51 | * @param array $classes
52 | *
53 | * @return string[]
54 | */
55 | public function meta_box_css_classes( array $classes ) {
56 | return array_merge( $classes, [
57 | 'papi-box'
58 | ] );
59 | }
60 |
61 | /**
62 | * Move meta boxes after title.
63 | */
64 | public function move_meta_box_after_title() {
65 | global $post, $wp_meta_boxes;
66 | do_meta_boxes( get_current_screen(), $this->box->context, $post );
67 | unset( $wp_meta_boxes[get_post_type( $post )][$this->box->context] );
68 | }
69 |
70 | /**
71 | * Get meta post type.
72 | *
73 | * @return string
74 | */
75 | protected function get_post_type() {
76 | if ( papi_get_meta_type() === 'post' ) {
77 | if ( $post_id = papi_get_post_id() ) {
78 | return get_post_type( $post_id );
79 | }
80 |
81 | if ( $post_type = papi_get_post_type() ) {
82 | return $post_type;
83 | }
84 | }
85 |
86 | return $this->box->id;
87 | }
88 |
89 | /**
90 | * Get meta box title.
91 | *
92 | * @return string
93 | */
94 | protected function get_title() {
95 | $title = $this->box->title;
96 |
97 | if ( $this->box->get_option( 'required' ) ) {
98 | $title .= papi_property_required_html(
99 | $this->box->properties[0],
100 | true
101 | );
102 | }
103 |
104 | return $title;
105 | }
106 |
107 | /**
108 | * Render the meta box
109 | *
110 | * @param array $post
111 | * @param array $args
112 | */
113 | public function render_meta_box( $post, array $args ) {
114 | if ( ! isset( $args['args'] ) ) {
115 | return;
116 | }
117 |
118 | // Do a last check before all properties is rendered.
119 | $args['args'] = array_filter( $args['args'], 'papi_is_property' );
120 |
121 | // Inherit options from the box.
122 | foreach ( $args['args'] as $index => $property ) {
123 | if ( $property->layout === 'horizontal' ) {
124 | $args['args'][$index]->layout = $this->box->layout;
125 | }
126 | }
127 |
128 | // Render the properties.
129 | papi_render_properties( papi_sort_order( array_reverse( $args['args'] ) ) );
130 | }
131 |
132 | /**
133 | * Setup action hooks.
134 | */
135 | protected function setup_actions() {
136 | if ( post_type_exists( $this->get_post_type() ) && papi_get_meta_type() === 'post' ) {
137 | add_action( 'add_meta_boxes', [$this, 'setup_meta_box'] );
138 |
139 | if ( $this->box->context === 'after_title' ) {
140 | add_action( 'edit_form_after_title', [$this, 'move_meta_box_after_title'] );
141 | }
142 | } else {
143 | $this->setup_meta_box();
144 | }
145 |
146 | // Will be called on when you call do_meta_boxes
147 | // even without a real post type.
148 | add_action(
149 | sprintf(
150 | 'postbox_classes_%s_%s',
151 | strtolower( $this->get_post_type() ),
152 | $this->box->id
153 | ),
154 | [$this, 'meta_box_css_classes']
155 | );
156 |
157 | add_action( 'admin_head', [$this, 'admin_head'] );
158 | }
159 |
160 | /**
161 | * Setup meta box.
162 | */
163 | public function setup_meta_box() {
164 | $properties = $this->box->properties;
165 |
166 | // Check all properties and remove them that can't be rendered.
167 | foreach ( $properties as $index => $property ) {
168 | if ( $property instanceof Papi_Property && ! $property->can_render() ) {
169 | unset( $properties[$index] );
170 | }
171 | }
172 |
173 | // Bail if properties array is empty,
174 | // no need to render a empty meta box.
175 | if ( empty( $properties ) ) {
176 | return;
177 | }
178 |
179 | add_meta_box(
180 | $this->box->id,
181 | $this->get_title(),
182 | [$this, 'render_meta_box'],
183 | $this->get_post_type(),
184 | $this->box->context,
185 | $this->box->priority,
186 | $properties
187 | );
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/src/admin/class-papi-admin-option-handler.php:
--------------------------------------------------------------------------------
1 | get_post_data();
23 |
24 | // Prepare properties data.
25 | $data = $this->prepare_properties_data( $data, 0 );
26 |
27 | foreach ( $data as $key => $value ) {
28 | papi_data_update( 0, $key, $value, 'option' );
29 | }
30 |
31 | /**
32 | * Fire `save_properties` action when all is done.
33 | *
34 | * @param int $id
35 | * @param string $meta_type
36 | */
37 | do_action( 'papi/save_properties', 0, 'option' );
38 | }
39 |
40 | /**
41 | * Setup actions.
42 | */
43 | protected function setup_actions() {
44 | add_action( 'admin_init', [$this, 'save_properties'] );
45 | }
46 | }
47 |
48 | if ( papi_is_admin() ) {
49 | new Papi_Admin_Option_Handler;
50 | }
51 |
--------------------------------------------------------------------------------
/src/admin/class-papi-admin-page-type-switcher.php:
--------------------------------------------------------------------------------
1 | name, $b->name );
41 | } );
42 |
43 | $page_types = papi_sort_order( array_reverse( $page_types ) );
44 |
45 | // Don't do anything without any page types.
46 | if ( empty( $page_type ) || empty( $page_types ) ) {
47 | return;
48 | } ?>
49 |
50 |
51 |
52 |
name ); ?>
53 |
54 | capabilities ) && $page_type->switcher ): ?>
55 |
56 |
57 |
73 |
74 |
75 |
76 |
77 |
78 | post_type ) === $page_type_id ) {
116 | $page_type = papi_get_standard_page_type( $post->post_type );
117 | } else {
118 | $page_type = papi_get_entry_type_by_id( $page_type_id );
119 | }
120 |
121 | // Fetch right page type switch if standard page type id.
122 | if ( papi_get_standard_page_type_id( $post->post_type ) === $page_type_switch_id ) {
123 | $page_type_switch = papi_get_standard_page_type( $post->post_type );
124 | $page_type_switch_id = '';
125 | } else {
126 | $page_type_switch = papi_get_entry_type_by_id( $page_type_switch_id );
127 | }
128 |
129 | $post_type_object = get_post_type_object( $post->post_type );
130 |
131 | // Check if page type and post type is not empty.
132 | if ( empty( $page_type_switch ) || empty( $post_type_object ) ) {
133 | return false;
134 | }
135 |
136 | // Check if autosave.
137 | if ( wp_is_post_autosave( $post_id ) ) {
138 | return false;
139 | }
140 |
141 | // Check if revision.
142 | if ( wp_is_post_revision( $post_id ) ) {
143 | return false;
144 | }
145 |
146 | // Check if revision post type.
147 | if ( in_array( $post->post_type, ['revision', 'nav_menu_item'], true ) ) {
148 | return false;
149 | }
150 |
151 | // Check so page type has the post type.
152 | if ( ! $page_type->has_post_type( $post->post_type ) || ! $page_type_switch->has_post_type( $post->post_type ) ) {
153 | return false;
154 | }
155 |
156 | // Check page type capabilities.
157 | if ( ! papi_current_user_is_allowed( $page_type_switch->capabilities ) ) {
158 | return false;
159 | }
160 |
161 | // Check so user can edit posts and that the user can publish posts on the post type.
162 | if ( ! current_user_can( 'edit_post', $post_id ) || ! current_user_can( $post_type_object->cap->publish_posts ) ) {
163 | return false;
164 | }
165 |
166 | // Get properties.
167 | $properties = $page_type->get_properties();
168 | $properties_switch = $page_type_switch->get_properties();
169 |
170 | // Delete only properties that don't have the same type and slug.
171 | foreach ( $properties as $property ) {
172 | $delete = true;
173 |
174 | // Check if the properties are the same or not.
175 | foreach ( $properties_switch as $property_switch ) {
176 | if ( $property_switch->type === $property->type && $property_switch->match_slug( $property->get_slug() ) ) {
177 | $delete = false;
178 | break;
179 | }
180 | }
181 |
182 | if ( ! $delete ) {
183 | continue;
184 | }
185 |
186 | // Delete property values.
187 | $property->delete_value( $property->get_slug( true ), $post_id, papi_get_meta_type() );
188 | }
189 |
190 | // Delete page type switch id.
191 | if ( empty( $page_type_switch_id ) ) {
192 | return delete_post_meta( $post_id, papi_get_page_type_key() );
193 | }
194 |
195 | // Update page type id.
196 | return papi_set_page_type_id( $post_id, $page_type_switch_id );
197 | }
198 | }
199 |
200 | if ( papi_is_admin() ) {
201 | new Papi_Admin_Page_Type_Switcher;
202 | }
203 |
--------------------------------------------------------------------------------
/src/admin/class-papi-admin-view.php:
--------------------------------------------------------------------------------
1 | path = empty( $path ) ? PAPI_PLUGIN_DIR . '/admin/views/' : $path;
22 | }
23 |
24 | /**
25 | * Check if file exists.
26 | *
27 | * @param string $file
28 | *
29 | * @return bool
30 | */
31 | public function exists( $file ) {
32 | return file_exists( $this->file( $file ) );
33 | }
34 |
35 | /**
36 | * Render file.
37 | *
38 | * @param string $file
39 | *
40 | * @return string
41 | */
42 | public function render( $file ) {
43 | if ( ! empty( $file ) && $this->exists( $file ) ) {
44 | require $this->file( $file );
45 | }
46 | }
47 |
48 | /**
49 | * Get full path to file with php exstention.
50 | *
51 | * @param string $file
52 | *
53 | * @return string
54 | */
55 | protected function file( $file ) {
56 | return $this->path . $file . '.php';
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/admin/views/add-new-page.php:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | labels->singular_name ) ); ?>
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 | get_child_types();
25 | $page_types = empty( $child_types ) ? $page_types : $child_types;
26 |
27 | if ( ! $show_standard ) {
28 | $show_standard = $parent_page_type->standard_type;
29 | }
30 | }
31 |
32 | if ( $show_standard ) {
33 | $page_types[] = papi_get_standard_page_type( $post_type_name );
34 | }
35 |
36 | usort( $page_types, function ( $a, $b ) {
37 | return strcmp( $a->name, $b->name );
38 | } );
39 |
40 | $page_types = papi_sort_order( array_reverse( $page_types ) );
41 | $use_thumbnail = false;
42 |
43 | foreach ( $page_types as $key => $page_type ) {
44 | if ( ! empty( $page_type->get_thumbnail() ) ) {
45 | $use_thumbnail = true;
46 | }
47 | }
48 |
49 | foreach ( $page_types as $key => $page_type ) {
50 | if ( ! papi_display_page_type( $page_type ) ) {
51 | continue;
52 | }
53 |
54 | papi_include_template( 'admin/views/partials/add-new-item.php', [
55 | 'title' => $page_type->name,
56 | 'description' => $page_type->description,
57 | 'thumbnail' => $page_type->get_thumbnail(),
58 | 'url' => papi_get_page_new_url( $page_type->get_id(), true, null ),
59 | 'use_thumbnail' => $use_thumbnail
60 | ] );
61 | }
62 | ?>
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/admin/views/partials/add-new-item.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/cli/class-papi-cli-command.php:
--------------------------------------------------------------------------------
1 | get_format_args( $assoc_args );
17 |
18 | return new \WP_CLI\Formatter( $args );
19 | }
20 |
21 | /**
22 | * Get default fields for formatter.
23 | *
24 | * Class that extends Papi_CLI_Command should override this method.
25 | *
26 | * @return null|string|array
27 | */
28 | protected function get_default_format_fields() {
29 | return null;
30 | }
31 |
32 | /**
33 | * Get format args that will be passed into CLI Formatter.
34 | *
35 | * @param array $assoc_args Associative args from CLI
36 | *
37 | * @return array Formatter args
38 | */
39 | protected function get_format_args( $assoc_args ) {
40 | $format_args = [
41 | 'fields' => $this->get_default_format_fields(),
42 | 'field' => null,
43 | 'format' => 'table',
44 | ];
45 |
46 | if ( isset( $assoc_args['fields'] ) ) {
47 | $format_args['fields'] = $assoc_args['fields'];
48 | }
49 |
50 | if ( isset( $assoc_args['field'] ) ) {
51 | $format_args['field'] = $assoc_args['field'];
52 | }
53 |
54 | if ( ! empty( $assoc_args['format'] ) && in_array( $assoc_args['format'], ['count', 'ids', 'table', 'csv', 'json'], true ) ) {
55 | $format_args['format'] = $assoc_args['format'];
56 | }
57 |
58 | return $format_args;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/cli/class-papi-cli-post-command.php:
--------------------------------------------------------------------------------
1 |
23 | * : Post ID
24 | *
25 | * [--field=]
26 | * : Instead of returning the whole post fields, returns the value of a single fields.
27 | *
28 | * [--fields=]
29 | * : Get a specific subset of the post's fields.
30 | *
31 | * [--format=]
32 | * : Accepted values: table, json, csv. Default: table.
33 | *
34 | * ## AVAILABLE FIELDS
35 | *
36 | * These fields are available for get command:
37 | *
38 | * * slug
39 | * * type
40 | * * exists
41 | *
42 | * ## EXAMPLES
43 | *
44 | * wp papi post get 123 --format=json
45 | *
46 | * wp papi post get 123 --field=slug
47 | *
48 | * @param array $args
49 | * @param array $assoc_args
50 | */
51 | public function get( $args, $assoc_args ) {
52 | try {
53 | // Set query string that we need.
54 | $_GET['post'] = $args[0];
55 |
56 | // Get the page type that the post has.
57 | $entry_type = papi_get_entry_type_by_meta_id( $args[0] );
58 |
59 | if ( empty( $entry_type ) || $entry_type instanceof Papi_Page_Type === false ) {
60 | WP_CLI::error( 'No page type exists on the post' );
61 | }
62 |
63 | $properties = [];
64 |
65 | foreach ( $entry_type->get_boxes() as $box ) {
66 | foreach ( $box->properties as $property ) {
67 | $properties[] = [
68 | 'slug' => $property->get_slug( true ),
69 | 'type' => $property->type,
70 | 'has value' => $property->get_value() !== null ? 'true' : 'false',
71 | 'box' => $box->title
72 | ];
73 | }
74 | }
75 |
76 | // Render types as a table.
77 | $formatter = $this->get_formatter( $assoc_args );
78 | $formatter->display_items( $properties );
79 | } catch ( WC_CLI_Exception $e ) {
80 | WP_CLI::error( $e->getMessage() );
81 | }
82 | }
83 |
84 | /**
85 | * Rename meta key for page type.
86 | *
87 | * ## OPTIONS
88 | *
89 | *
90 | * : Page type id
91 | *
92 | *
93 | * : Old meta key
94 | *
95 | *
96 | * : New meta key
97 | *
98 | * ## EXAMPLES
99 | *
100 | * wp papi post rename about-page-type name title
101 | *
102 | * @param array $args
103 | * @param array $assoc_args
104 | */
105 | public function rename( $args, $assoc_args ) {
106 | $type = $args[0];
107 | $old_key = $args[1];
108 | $new_key = $args[2];
109 |
110 | $posts = ( new Papi_Query( [
111 | 'entry_type' => $type,
112 | 'fields' => 'ids'
113 | ] ) )->get_result();
114 |
115 | if ( empty( $posts ) ) {
116 | WP_CLI::error( 'No posts found' );
117 | }
118 |
119 | foreach ( $posts as $post ) {
120 | $meta = get_post_meta( $post, $old_key, true );
121 |
122 | if ( papi_is_empty( $meta ) ) {
123 | continue;
124 | }
125 |
126 | if ( delete_post_meta( $post, $old_key ) === false ) {
127 | WP_CLI::error( 'Could not delete post meta with key: ' . $old_key );
128 |
129 | }
130 |
131 | if ( update_post_meta( $post, $new_key, $meta ) === false ) {
132 | WP_CLI::error( 'Could not update post meta with key: ' . $new_key );
133 | }
134 | }
135 |
136 | WP_CLI::success( 'Done' );
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/cli/class-papi-cli-term-command.php:
--------------------------------------------------------------------------------
1 |
23 | * : Term ID
24 | *
25 | * [--field=]
26 | * : Instead of returning the whole term fields, returns the value of a single fields.
27 | *
28 | * [--fields=]
29 | * : Get a specific subset of the term's fields.
30 | *
31 | * [--format=]
32 | * : Accepted values: table, json, csv. Default: table.
33 | *
34 | * ## AVAILABLE FIELDS
35 | *
36 | * These fields are available for get command:
37 | *
38 | * * slug
39 | * * type
40 | * * exists
41 | *
42 | * ## EXAMPLES
43 | *
44 | * wp papi term get 123 --format=json
45 | *
46 | * wp papi term get 123 --field=slug
47 | *
48 | * @param array $args
49 | * @param array $assoc_args
50 | */
51 | public function get( $args, $assoc_args ) {
52 | try {
53 | // Set query string that we need.
54 | $_GET['meta_type'] = 'term';
55 |
56 | // Get the taxonomy type that the term has.
57 | $entry_type = papi_get_entry_type_by_meta_id( $args[0] );
58 |
59 | if ( empty( $entry_type ) || $entry_type instanceof Papi_Taxonomy_Type === false ) {
60 | WP_CLI::error( 'No taxonomy type exists on the term' );
61 | }
62 |
63 | $properties = [];
64 |
65 | foreach ( $entry_type->get_boxes() as $box ) {
66 | foreach ( $box->properties as $property ) {
67 | $properties[] = [
68 | 'slug' => $property->get_slug( true ),
69 | 'type' => $property->type,
70 | 'has value' => $property->get_value() !== null ? 'true' : 'false',
71 | 'box' => $box->title
72 | ];
73 | }
74 | }
75 |
76 | // Render types as a table.
77 | $formatter = $this->get_formatter( $assoc_args );
78 | $formatter->display_items( $properties );
79 | } catch ( WC_CLI_Exception $e ) {
80 | WP_CLI::error( $e->getMessage() );
81 | }
82 | }
83 |
84 | /**
85 | * Rename meta key for taxonomy type.
86 | *
87 | * ## OPTIONS
88 | *
89 | *
90 | * : Taxonomy type id
91 | *
92 | *
93 | * : Old meta key
94 | *
95 | *
96 | * : New meta key
97 | *
98 | * ## EXAMPLES
99 | *
100 | * wp papi term rename about-page-type name title
101 | *
102 | * @param array $args
103 | * @param array $assoc_args
104 | */
105 | public function rename( $args, $assoc_args ) {
106 | $type = $args[0];
107 | $old_key = $args[1];
108 | $new_key = $args[2];
109 |
110 | $terms = ( new Papi_Query( [
111 | 'entry_type' => $type,
112 | 'fields' => 'ids'
113 | ] ) )->get_result();
114 |
115 | if ( empty( $terms ) ) {
116 | WP_CLI::error( 'No terms found' );
117 | }
118 |
119 | foreach ( $terms as $term ) {
120 | $meta = get_term_meta( $term, $old_key, true );
121 |
122 | if ( papi_is_empty( $meta ) ) {
123 | continue;
124 | }
125 |
126 | if ( delete_term_meta( $term, $old_key ) === false ) {
127 | WP_CLI::error( 'Could not delete term meta with key: ' . $old_key );
128 |
129 | }
130 |
131 | if ( update_term_meta( $term, $new_key, $meta ) === false ) {
132 | WP_CLI::error( 'Could not update term meta with key: ' . $new_key );
133 | }
134 | }
135 |
136 | WP_CLI::success( 'Done' );
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/cli/class-papi-cli-type-command.php:
--------------------------------------------------------------------------------
1 | get_type(), ['attachment'], true ) ) {
26 | return $entry_type->get_type();
27 | }
28 |
29 | switch ( papi_get_meta_type( $entry_type->get_type() ) ) {
30 | case 'post':
31 | return implode( ', ', $entry_type->post_type );
32 | case 'term':
33 | return implode( ', ', $entry_type->taxonomy );
34 | default:
35 | return 'n/a';
36 | }
37 | }
38 |
39 | /**
40 | * List Papi types.
41 | *
42 | * ## Options
43 | *
44 | * [--=]
45 | * : Filter types based on type property.
46 | *
47 | * [--field=]
48 | * : Prints the value of a single field for each type.
49 | *
50 | * [--fields=]
51 | * : Limit the output to specific type fields.
52 | *
53 | * [--format=]
54 | * : Acceptec values: table, csv, json, count, ids. Default: table.
55 | *
56 | * ## AVAILABLE FIELDS
57 | *
58 | * These fields will be displayed by default for each type:
59 | *
60 | * * name
61 | * * id
62 | * * post_type
63 | * * template
64 | * * number_of_pages
65 | * * type
66 | *
67 | * Not all fields exists on a Papi type so some fields will have `n/a`
68 | * as value when no value can be displayed.
69 | *
70 | * ## EXAMPLES
71 | *
72 | * wp papi type list
73 | *
74 | * @subcommand list
75 | */
76 | public function list_( $args, $assoc_args ) {
77 | // Get all entry types.
78 | $entry_types = papi_get_all_entry_types();
79 |
80 | if ( empty( $entry_types ) ) {
81 | WP_CLI::error( 'No Papi types exists.' );
82 | }
83 |
84 | // Create type item with the fields that
85 | // will be displayed.
86 | $entry_types = array_map( function( $entry_type ) {
87 | return [
88 | 'id' => $entry_type->get_id(),
89 | 'name' => $entry_type->name,
90 | 'meta type value' => $this->get_meta_type_value( $entry_type ),
91 | 'template' => empty( $entry_type->template ) ? 'n/a' : $entry_type->template,
92 | 'type' => $entry_type->get_type(),
93 | 'db count' => $entry_type->get_type() === 'option' ? 'n/a' : papi_get_entry_type_count( $entry_type )
94 | ];
95 | }, $entry_types );
96 |
97 | // Render types as a table.
98 | $formatter = $this->get_formatter( $assoc_args );
99 | $formatter->display_items( $entry_types );
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/cli/class-papi-cli.php:
--------------------------------------------------------------------------------
1 | setup_args( $args );
101 | $this->setup_properties( $properties );
102 | }
103 |
104 | /**
105 | * Get box option.
106 | *
107 | * @param string $key
108 | *
109 | * @return mixed
110 | */
111 | public function get_option( $key ) {
112 | return isset( $this->options[$key] ) ? $this->options[$key] : null;
113 | }
114 |
115 | /**
116 | * Set box option.
117 | *
118 | * @param string $key
119 | * @param mixed $value
120 | */
121 | public function set_option( $key, $value ) {
122 | $this->options[$key] = $value;
123 | }
124 |
125 | /**
126 | * Setup arguments.
127 | *
128 | * @param array $args
129 | */
130 | protected function setup_args( array $args ) {
131 | $excluded_keys = ['options', 'properties'];
132 |
133 | foreach ( $args as $key => $value ) {
134 | if ( isset( $this->$key ) && ! in_array( $key, $excluded_keys, true ) ) {
135 | $this->$key = papi_esc_html( $value );
136 | }
137 | }
138 |
139 | if ( empty( $this->id ) ) {
140 | $this->id = papi_slugify( strtolower( papi_f( papi_underscorify( papify( $this->title ) ) ) ) );
141 | $this->id = sanitize_text_field( $this->id );
142 | }
143 | }
144 |
145 | /**
146 | * Setup properties.
147 | *
148 | * @param array $properties
149 | */
150 | protected function setup_properties( array $properties ) {
151 | $this->properties = papi_populate_properties( $properties );
152 | }
153 |
154 | /**
155 | * Get a string representation of the object.
156 | *
157 | * @return string
158 | */
159 | public function __toString() {
160 | return $this->id;
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/core/class-papi-core-conditional-rule.php:
--------------------------------------------------------------------------------
1 | setup( $rule );
43 | }
44 |
45 | /**
46 | * Get field slug.
47 | *
48 | * @return string
49 | */
50 | public function get_field_slug() {
51 | if ( preg_match( '/\[|\]/', $this->slug ) ) {
52 | $slug = preg_replace( '/\[|\]/', '.', $this->slug );
53 | $slug = str_replace( '..', '.', $slug );
54 | return substr( $slug, 0, -1 );
55 | }
56 |
57 | return $this->slug;
58 | }
59 |
60 | /**
61 | * Get the source value.
62 | *
63 | * @return mixed
64 | */
65 | public function get_source() {
66 | if ( is_callable( $this->source ) ) {
67 | return call_user_func_array( $this->source, [$this->slug] );
68 | }
69 |
70 | if ( is_string( $this->source ) && strpos( $this->source, '#' ) !== false ) {
71 | $source = explode( '#', $this->source );
72 |
73 | if ( empty( $source[0] ) || empty( $source[1] ) ) {
74 | return $this->source;
75 | }
76 |
77 | $source[0] = new $source[0]();
78 |
79 | if ( method_exists( $source[0], $source[1] ) ) {
80 | return call_user_func_array( $source, [$this->slug] );
81 | }
82 |
83 | return;
84 | }
85 |
86 | return $this->source;
87 | }
88 |
89 | /**
90 | * Setup source callable.
91 | *
92 | * @param string $value
93 | *
94 | * @return string
95 | */
96 | public function setup_source( $value ) {
97 | if ( is_array( $value ) && count( $value ) === 2 && is_object( $value[0] ) && is_string( $value[1] ) ) {
98 | return sprintf( '%s#%s', get_class( $value[0] ), $value[1] );
99 | }
100 |
101 | if ( is_string( $value ) && is_callable( $value ) ) {
102 | return $value;
103 | }
104 |
105 | // No support for closure.
106 | if ( is_object( $value ) && $value instanceof Closure ) {
107 | return '';
108 | }
109 |
110 | return $value;
111 | }
112 |
113 | /**
114 | * Setup the rule and assign properties with values.
115 | *
116 | * @param array $rule
117 | */
118 | protected function setup( array $rule ) {
119 | foreach ( $rule as $key => $value ) {
120 | if ( $key === 'operator' ) {
121 | $value = strtoupper( $value );
122 | $value = html_entity_decode( $value );
123 | } else if ( $key === 'slug' ) {
124 | $value = papify( $value );
125 | } else if ( $key === 'source' ) {
126 | $value = $this->setup_source( $value );
127 | }
128 |
129 | $this->$key = $value;
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/core/class-papi-core-conditional.php:
--------------------------------------------------------------------------------
1 | prepare_rules( $rules, $property );
33 |
34 | if ( in_array( $rules['relation'], $this->relations, true ) ) {
35 | return $this->display_by_relation( $rules );
36 | }
37 |
38 | return true;
39 | }
40 |
41 | /**
42 | * Get the display by relation.
43 | *
44 | * @param array $rules
45 | *
46 | * @return bool
47 | */
48 | protected function display_by_relation( array $rules ) {
49 | if ( $rules['relation'] === 'AND' ) {
50 | $display = true;
51 |
52 | foreach ( $rules as $rule ) {
53 | if ( ! $display ) {
54 | break;
55 | }
56 |
57 | if ( papi_is_rule( $rule ) ) {
58 | /**
59 | * Modify rule allowed.
60 | *
61 | * @param bool $result
62 | * @param Papi_Core_Conditional_Rule $rule
63 | *
64 | * @return bool
65 | */
66 | $display = apply_filters( 'papi/conditional/rule_allowed', papi_filter_conditional_rule_allowed( $rule ), $rule );
67 | }
68 | }
69 |
70 | return $display;
71 | }
72 |
73 | $empty = array_filter( $rules, function ( $rule ) {
74 | return papi_is_rule( $rule ) ? true : null;
75 | } );
76 |
77 | if ( empty( $empty ) ) {
78 | return true;
79 | }
80 |
81 | $result = [];
82 |
83 | foreach ( $rules as $rule ) {
84 | if ( papi_is_rule( $rule ) ) {
85 | /**
86 | * Modify rule allowed.
87 | *
88 | * @param bool $result
89 | * @param Papi_Core_Conditional_Rule $rule
90 | *
91 | * @return bool
92 | */
93 | $result[] = apply_filters( 'papi/conditional/rule_allowed', papi_filter_conditional_rule_allowed( $rule ), $rule );
94 | }
95 | }
96 |
97 | $result = array_filter( $result, function ( $res ) {
98 | return $res === true ? true : null;
99 | } );
100 |
101 | return ! empty( $result );
102 | }
103 |
104 | /**
105 | * Get rule slug.
106 | *
107 | * @param Papi_Core_Conditional_Rule $rule
108 | * @param Papi_Core_Property $property
109 | *
110 | * @return string
111 | */
112 | protected function get_rule_slug( $rule, $property ) {
113 | $arr_reg = '/\[\d+\](\[\w+\])$/';
114 | $slug = $property->get_slug();
115 |
116 | $page_type = papi_get_entry_type_by_meta_id();
117 |
118 | if ( $page_type instanceof Papi_Page_Type === false ) {
119 | return $rule->slug;
120 | }
121 |
122 | if ( preg_match( $arr_reg, $slug, $out ) ) {
123 | $slug = str_replace( $out[1], '[' . unpapify( $rule->slug ) . ']', $slug );
124 | $property = $page_type->get_property( $slug );
125 |
126 | if ( papi_is_property( $property ) ) {
127 | return $slug;
128 | }
129 | }
130 |
131 | return $rule->slug;
132 | }
133 |
134 | /**
135 | * Prepare rules.
136 | *
137 | * @param array $rules
138 | * @param Papi_Core_Property $property
139 | *
140 | * @return array
141 | */
142 | public function prepare_rules( array $rules, $property = null ) {
143 | if ( ! isset( $rules['relation'] ) ) {
144 | $rules['relation'] = 'OR';
145 | } else {
146 | $rules['relation'] = strtoupper( $rules['relation'] );
147 | }
148 |
149 | foreach ( $rules as $index => $value ) {
150 | if ( is_string( $index ) ) {
151 | continue;
152 | }
153 |
154 | if ( is_array( $value ) ) {
155 | $rules[$index] = new Papi_Core_Conditional_Rule( $value );
156 |
157 | if ( strpos( $rules[$index]->slug, '.' ) === false && papi_is_property( $property ) ) {
158 | $rules[$index]->slug = $this->get_rule_slug(
159 | $rules[$index],
160 | $property
161 | );
162 | }
163 | }
164 | }
165 |
166 | return $rules;
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/src/core/class-papi-core-data-handler.php:
--------------------------------------------------------------------------------
1 | setup_actions();
20 | }
21 |
22 | /**
23 | * Decode property.
24 | *
25 | * @param string $key
26 | * @param string $value
27 | *
28 | * @return mixed
29 | */
30 | protected function decode_property( $key, $value ) {
31 | if ( papi_is_property_type_key( $key ) && is_string( $value ) ) {
32 | $value = base64_decode( $value );
33 | $value = papi_maybe_json_decode( $value );
34 | }
35 |
36 | return $value;
37 | }
38 |
39 | /**
40 | * Get post data.
41 | *
42 | * @param string $pattern
43 | *
44 | * @return array
45 | */
46 | protected function get_post_data( $pattern = '/^papi\_.*/' ) {
47 | $data = [];
48 | $keys = preg_grep( $pattern, array_keys( $_POST ) );
49 |
50 | foreach ( $keys as $key ) {
51 | // Remove page type keys with suffix. This should not be saved.
52 | if (
53 | strpos( $key, papi_get_page_type_key() ) === 0
54 | &&
55 | strlen( papi_get_page_type_key() ) !== strlen( $key )
56 | ) {
57 | continue;
58 | }
59 |
60 | // Fix for input fields that should be true on `on` value.
61 | if ( $_POST[$key] === 'on' ) {
62 | $data[$key] = true;
63 | } else {
64 | $value = $this->decode_property( $key, $_POST[$key] );
65 | $data[$key] = $this->prepare_post_data( $value );
66 | $data[$key] = $this->santize_data( $data[$key] );
67 | }
68 | }
69 |
70 | // Don't wont to save meta nonce field.
71 | if ( isset( $data['papi_meta_nonce'] ) ) {
72 | unset( $data['papi_meta_nonce'] );
73 | }
74 |
75 | return $data;
76 | }
77 |
78 | /**
79 | * Get pre data that should be saved before all properties data.
80 | */
81 | protected function get_pre_data() {
82 | return $this->get_post_data( '/^\_papi\_.*/' );
83 | }
84 |
85 | /**
86 | * Pre get deep keys and value.
87 | *
88 | * Used for saving pre data when properties are in a flexible or repeater.
89 | *
90 | * @param array $arr
91 | *
92 | * @return array
93 | */
94 | protected function get_pre_deep_keys_value( array $arr ) {
95 | $keys = [];
96 | $value = null;
97 |
98 | foreach ( $arr as $key => $v ) {
99 | if ( is_array( $v ) ) {
100 | $keys[] = $key;
101 | list( $ks, $val ) = $this->get_pre_deep_keys_value( $v );
102 | $keys = array_merge( $keys, $ks );
103 | $value = $val;
104 | } else {
105 | $keys[] = $key;
106 | $value = $v;
107 | }
108 | }
109 |
110 | return [$keys, $value];
111 | }
112 |
113 | /**
114 | * Prepare post data.
115 | * Will decode property options recursive.
116 | *
117 | * @param mixed $data
118 | *
119 | * @return mixed
120 | */
121 | protected function prepare_post_data( $data ) {
122 | if ( ! is_array( $data ) ) {
123 | return $data;
124 | }
125 |
126 | foreach ( $data as $key => $value ) {
127 | if ( is_array( $value ) ) {
128 | $data[$key] = $this->prepare_post_data( $value );
129 | } else {
130 | $data[$key] = $this->decode_property( $key, $value );
131 | }
132 | }
133 |
134 | return $data;
135 | }
136 |
137 | /**
138 | * Prepare properties data for saving.
139 | *
140 | * @param array $data
141 | * @param int $post_id
142 | *
143 | * @return array
144 | */
145 | protected function prepare_properties_data( array $data = [], $post_id = 0 ) {
146 | // Since we are storing witch property it is in the `$data` array
147 | // we need to remove that and set the property type to the property
148 | // and make a array of the property type and the value.
149 | foreach ( $data as $key => $value ) {
150 | if ( papi_is_property_type_key( $key ) ) {
151 | continue;
152 | }
153 |
154 | $property_type_key = papify( papi_get_property_type_key( $key ) );
155 |
156 | // Check if value exists.
157 | if ( ! isset( $data[$key] ) || ! isset( $data[$property_type_key] ) ) {
158 | continue;
159 | }
160 |
161 | // Pair property value with property type object.
162 | $data[$key] = [
163 | 'type' => $data[$property_type_key],
164 | 'value' => $value
165 | ];
166 |
167 | // Remove property type object since it's not needed anymore.
168 | unset( $data[$property_type_key] );
169 | }
170 |
171 | foreach ( $data as $key => $item ) {
172 | if ( papi_is_property_type_key( $key ) ) {
173 | if ( isset( $data[$key] ) ) {
174 | unset( $data[$key] );
175 | }
176 | continue;
177 | }
178 |
179 | if ( empty( $item['type'] ) ) {
180 | continue;
181 | }
182 |
183 | $property = papi_get_property_type( $item['type'] );
184 |
185 | unset( $data[ $key ] );
186 |
187 | if ( papi_is_property( $property ) ) {
188 | // Run `update_value` method on the property class.
189 | $data[$key] = $property->update_value(
190 | $item['value'],
191 | unpapify( $key ),
192 | $post_id
193 | );
194 |
195 | // Apply `update_value` filter so this can be changed from
196 | // the theme for specified property type.
197 | $data[$key] = papi_filter_update_value(
198 | $item['type']->type,
199 | $data[$key],
200 | unpapify( $key ),
201 | $post_id,
202 | papi_get_meta_type()
203 | );
204 |
205 | if ( $item['type']->overwrite ) {
206 | $slug = unpapify( $key );
207 | $this->overwrite[$slug] = $data[$key];
208 | unset( $data[$key] );
209 | }
210 | }
211 | }
212 |
213 | return $data;
214 | }
215 |
216 | /**
217 | * Sanitize data before saving it.
218 | *
219 | * @param mixed $value
220 | *
221 | * @return mixed
222 | */
223 | protected function santize_data( $value ) {
224 | if ( is_array( $value ) ) {
225 | foreach ( $value as $k => $v ) {
226 | if ( is_string( $v ) ) {
227 | $value[$k] = $this->santize_data( $v );
228 | }
229 | }
230 | } else if ( is_string( $value ) ) {
231 | $value = wp_unslash( $value );
232 | }
233 |
234 | return $value;
235 | }
236 |
237 | /**
238 | * Setup actions.
239 | *
240 | * @codeCoverageIgnore
241 | */
242 | protected function setup_actions() {
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/src/core/class-papi-core-data.php:
--------------------------------------------------------------------------------
1 | type = is_string( $type ) ? papi_get_meta_type( $type ) : 'post';
26 | $this->id = in_array( $this->type, ['post', 'term'], true );
27 | }
28 |
29 | /**
30 | * Delete property value.
31 | *
32 | * @param int $id
33 | * @param string $slug
34 | *
35 | * @return bool
36 | */
37 | public function delete( $id, $slug ) {
38 | $fn = $this->get_function( 'delete' );
39 |
40 | // Check so the function is callable before using it.
41 | if ( ! is_callable( $fn ) ) {
42 | return false;
43 | }
44 |
45 | // Delete cached value.
46 | papi_cache_delete( $slug, $id, $this->type );
47 |
48 | if ( $this->id ) {
49 | return call_user_func_array( $fn, [$this->type, $id, unpapify( $slug )] );
50 | }
51 |
52 | return call_user_func_array( $fn, [unpapify( $slug )] );
53 | }
54 |
55 | /**
56 | * Get right meta function for right type and context.
57 | *
58 | * @param string $context
59 | *
60 | * @return string
61 | */
62 | public function get_function( $context = 'get' ) {
63 | switch ( $this->type ) {
64 | case 'option':
65 | return sprintf( '%s_option', $context );
66 | case 'site':
67 | case 'network':
68 | return sprintf( '%s_site_option', $context );
69 | case 'post':
70 | case 'term':
71 | return sprintf( '%s_metadata', $context );
72 | default:
73 | break;
74 | }
75 | }
76 |
77 | /**
78 | * Geta property value for right meta type.
79 | *
80 | * @param int $id
81 | * @param string $slug
82 | *
83 | * @return mixed
84 | */
85 | public function get( $id, $slug ) {
86 | $fn = $this->get_function( 'get' );
87 |
88 | if ( ! is_callable( $fn ) ) {
89 | return;
90 | }
91 |
92 | if ( $this->id ) {
93 | $value = call_user_func_array( $fn, [$this->type, $id, unpapify( $slug ), true] );
94 | } else {
95 | $value = call_user_func_array( $fn, [unpapify( $slug ), null] );
96 | }
97 |
98 | if ( papi_is_empty( $value ) ) {
99 | return;
100 | }
101 |
102 | return $value;
103 | }
104 |
105 | /**
106 | * Update property meta.
107 | *
108 | * @param int $id
109 | * @param string $slug
110 | * @param mixed $value
111 | *
112 | * @return bool
113 | */
114 | public function update( $id, $slug, $value ) {
115 | $save_value = true;
116 |
117 | // Get right update function to use.
118 | $fn = $this->get_function( 'update' );
119 |
120 | if ( ! is_callable( $fn ) ) {
121 | return false;
122 | }
123 |
124 | // Check for string keys in the array if any.
125 | foreach ( array_keys( papi_to_array( $value ) ) as $key ) {
126 | if ( is_string( $key ) ) {
127 | $save_value = false;
128 | break;
129 | }
130 | }
131 |
132 | // If main value shouldn't be saved it should be array.
133 | if ( ! $save_value && is_array( $value ) ) {
134 | $value = [$value];
135 | }
136 |
137 | // Delete saved value if empty.
138 | if ( papi_is_empty( $value ) ) {
139 | return $this->delete( $id, $slug );
140 | }
141 |
142 | $result = true;
143 |
144 | foreach ( papi_to_array( $value ) as $key => $val ) {
145 | // Delete saved value if value is empty.
146 | if ( papi_is_empty( $val ) || $val === '[]' || $val === '{}' ) {
147 | return $this->delete( $id, $slug );
148 | }
149 |
150 | // Delete main value cache.
151 | papi_cache_delete( $slug, $id, $this->type );
152 |
153 | // If not a array we can save the value.
154 | if ( ! is_array( $val ) ) {
155 | if ( $save_value ) {
156 | $val = $value;
157 | }
158 |
159 | if ( $this->id ) {
160 | $out = call_user_func_array( $fn, [$this->type, $id, unpapify( $slug ), $val] );
161 | $result = $out ? $result : $out;
162 | } else {
163 | $out = call_user_func_array( $fn, [unpapify( $slug ), $val] );
164 | $result = $out ? $result : $out;
165 | }
166 |
167 | continue;
168 | }
169 |
170 | // Clear cache for all child values.
171 | $this->update_clear_cache( $id, $value );
172 |
173 | // Update metadata or option value for all child values.
174 | foreach ( $val as $child_key => $child_value ) {
175 | if ( papi_is_empty( $child_value ) ) {
176 | $this->delete( $id, $child_key );
177 | } else {
178 | if ( $this->id ) {
179 | call_user_func_array( $fn, [$this->type, $id, unpapify( $child_key ), $child_value] );
180 | } else {
181 | call_user_func_array( $fn, [unpapify( $child_key ), $child_value] );
182 | }
183 | }
184 | }
185 | }
186 |
187 | return $result;
188 | }
189 |
190 | /**
191 | * Clear cache values on update property meta.
192 | *
193 | * @param int $id
194 | * @param mixed $value
195 | */
196 | public function update_clear_cache( $id, $value ) {
197 | $value = is_array( $value ) ? $value : [];
198 |
199 | foreach ( $value as $child_key => $child_value ) {
200 | papi_cache_delete( $child_key, $id, $this->type );
201 |
202 | if ( is_array( $child_value ) ) {
203 | $this->update_clear_cache( $id, $child_value );
204 | }
205 | }
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/src/core/class-papi-core-tab.php:
--------------------------------------------------------------------------------
1 | setup_args( $args );
77 | $this->setup_properties( $properties );
78 | }
79 |
80 | /**
81 | * Setup arguments.
82 | *
83 | * @param array $args
84 | */
85 | protected function setup_args( array $args ) {
86 | foreach ( $args as $key => $value ) {
87 | if ( isset( $this->$key ) ) {
88 | $this->$key = papi_esc_html( $value );
89 | }
90 | }
91 |
92 | if ( empty( $this->id ) ) {
93 | $this->id = strtolower( papi_f( papi_underscorify( papify( $this->title ) ) ) );
94 | }
95 | }
96 |
97 | /**
98 | * Setup properties.
99 | *
100 | * @param array $properties
101 | */
102 | protected function setup_properties( array $properties ) {
103 | $this->properties = array_merge( $this->properties, papi_populate_properties( $properties ) );
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/core/class-papi-core-type.php:
--------------------------------------------------------------------------------
1 | setup_file( $file_path );
60 | $this->setup_meta_data();
61 | }
62 | }
63 |
64 | /**
65 | * Determine if the entry type is allowed.
66 | *
67 | * @return bool
68 | */
69 | public function allowed() {
70 | return true;
71 | }
72 |
73 | /**
74 | * Boot page type.
75 | *
76 | * @codeCoverageIgnore
77 | */
78 | public function boot() {
79 | $this->setup_actions();
80 | $this->setup_filters();
81 | }
82 |
83 | /**
84 | * Get the page type class name with namespace if exists.
85 | *
86 | * @return string
87 | */
88 | public function get_class_name() {
89 | return $this->_class_name;
90 | }
91 |
92 | /**
93 | * Get the page type file pat.h
94 | *
95 | * @return string
96 | */
97 | public function get_file_path() {
98 | return $this->_file_path;
99 | }
100 |
101 | /**
102 | * Get the page type identifier.
103 | *
104 | * @return string
105 | */
106 | public function get_id() {
107 | if ( ! empty( $this->_id ) ) {
108 | return $this->_id;
109 | }
110 |
111 | return papi_get_core_type_base_path( $this->_file_path );
112 | }
113 |
114 | /**
115 | * Get meta data from type class and merge
116 | * with the parent meta data.
117 | *
118 | * @return array
119 | */
120 | protected function get_meta() {
121 | $method = 'meta';
122 |
123 | if ( ! method_exists( $this, $method ) ) {
124 | return [];
125 | }
126 |
127 | $child_meta = call_user_func( [$this, $method] );
128 | $child_meta = is_array( $child_meta ) ? $child_meta : [];
129 |
130 | $parent_class = get_parent_class( $this );
131 | $parent_exists = method_exists( $parent_class, $method );
132 | $parent_meta = [];
133 |
134 | while ( $parent_exists ) {
135 | $rc = new ReflectionClass( $parent_class );
136 |
137 | // Bail if not instantiable.
138 | if ( ! $rc->isInstantiable() ) {
139 | break;
140 | }
141 |
142 | $parent = $rc->newInstance();
143 | $output = call_user_func( [$parent, $method] );
144 | $output = is_array( $output ) ? $output : [];
145 | $parent_meta = array_merge( $parent_meta, $output );
146 | $parent_class = get_parent_class( $parent_class );
147 | $parent_exists = method_exists( $parent_class, $method );
148 | }
149 |
150 | return array_merge( $parent_meta, $child_meta );
151 | }
152 |
153 | /**
154 | * Get type name.
155 | *
156 | * @return string
157 | */
158 | public function get_type() {
159 | return strtolower( $this->type );
160 | }
161 |
162 | /**
163 | * Check so we have a name on the page type.
164 | *
165 | * @return bool
166 | */
167 | public function has_name() {
168 | return ! empty( $this->name );
169 | }
170 |
171 | /**
172 | * Check if the the given identifier match the page type identifier.
173 | *
174 | * @param string $id
175 | *
176 | * @return bool
177 | */
178 | public function match_id( $id ) {
179 | return $this->get_id() === $id;
180 | }
181 |
182 | /**
183 | * Create a new instance of the page type file.
184 | *
185 | * @return null|object
186 | */
187 | public function new_class() {
188 | if ( empty( $this->_file_path ) ) {
189 | return;
190 | }
191 |
192 | return new $this->_class_name;
193 | }
194 |
195 | /**
196 | * Set custom id.
197 | *
198 | * @param string $id
199 | */
200 | public function set_id( $id ) {
201 | $this->_id = $id;
202 | }
203 |
204 | /**
205 | * Setup actions.
206 | *
207 | * @codeCoverageIgnore
208 | */
209 | protected function setup_actions() {
210 | }
211 |
212 | /**
213 | * Load the file and setup file path, file name and class name properties.
214 | *
215 | * @param string $file_path
216 | */
217 | protected function setup_file( $file_path ) {
218 | $this->_file_path = $file_path;
219 | $this->_class_name = papi_get_class_name( $this->_file_path );
220 | }
221 |
222 | /**
223 | * Setup filters.
224 | *
225 | * @codeCoverageIgnore
226 | */
227 | protected function setup_filters() {
228 | }
229 |
230 | /**
231 | * Setup meta data.
232 | */
233 | protected function setup_meta_data() {
234 | foreach ( $this->get_meta() as $key => $value ) {
235 | if ( substr( $key, 0, 1 ) === '_' ) {
236 | continue;
237 | }
238 |
239 | $this->$key = papi_esc_html( $value );
240 | }
241 |
242 | if ( $this->sort_order === 1000 ) {
243 | $this->sort_order = papi_filter_settings_sort_order();
244 | }
245 | }
246 | }
247 |
--------------------------------------------------------------------------------
/src/lib/core/cache.php:
--------------------------------------------------------------------------------
1 | data( $type )->delete( $id, $slug, $type );
14 | }
15 |
16 | /**
17 | * Get data from database.
18 | *
19 | * @param int $id
20 | * @param string $slug
21 | * @param string $type
22 | */
23 | function papi_data_get( $id, $slug, $type = 'post' ) {
24 | return papi()->data( $type )->get( $id, $slug );
25 | }
26 |
27 | /**
28 | * Updata data in database.
29 | *
30 | * @param int $id
31 | * @param string $slug
32 | * @param mixed $value
33 | * @param string $type
34 | *
35 | * @return bool
36 | */
37 | function papi_data_update( $id, $slug, $value, $type = 'post' ) {
38 | return papi()->data( $type )->update( $id, $slug, $value );
39 | }
40 |
--------------------------------------------------------------------------------
/src/lib/core/deprecated.php:
--------------------------------------------------------------------------------
1 | $dir ) {
31 | if ( ! file_exists( $dir ) || ! is_dir( $dir ) ) {
32 | unset( $directory[$index] );
33 | }
34 | }
35 |
36 | return array_merge( $directories, $directory );
37 | } );
38 | }
39 |
40 | /**
41 | * Get all files in directory.
42 | *
43 | * @param string $directory
44 | *
45 | * @return string
46 | */
47 | function papi_get_all_files_in_directory( $directory = '' ) {
48 | $result = [];
49 |
50 | if ( empty( $directory ) || ! is_string( $directory ) ) {
51 | return $result;
52 | }
53 |
54 | if ( file_exists( $directory ) && $handle = opendir( $directory ) ) {
55 | while ( false !== ( $file = readdir( $handle ) ) ) {
56 | if ( ! in_array( $file, ['..', '.'], true ) && $file[0] !== '.' ) {
57 | if ( is_dir( $directory . '/' . $file ) ) {
58 | $result = array_merge( $result, papi_get_all_files_in_directory( $directory . '/' . $file ) );
59 | } else {
60 | $file = $directory . '/' . $file;
61 | $result[] = preg_replace( '/\/\//si', '/', $file );
62 | }
63 | }
64 | }
65 |
66 | closedir( $handle );
67 | }
68 |
69 | return $result;
70 | }
71 |
72 | /**
73 | * Get core type file path, this allows classes to be overridden.
74 | *
75 | * @param string $file_path
76 | *
77 | * @return string
78 | */
79 | function papi_get_core_type_file_path( $file_path ) {
80 | if ( empty( $file_path ) ) {
81 | return [];
82 | }
83 |
84 | $directories = papi_filter_settings_directories();
85 | $result = [];
86 |
87 | foreach ( $directories as $directory ) {
88 | $directory = rtrim( $directory, '/' ) . '/';
89 | $file_path = str_replace( $directory, '', $file_path );
90 | $path = $directory . $file_path;
91 |
92 | if ( file_exists( $path ) ) {
93 | $result[] = $path;
94 | }
95 | }
96 |
97 | return array_pop( $result );
98 | }
99 |
100 | /**
101 | * Get all core type files from the register directories.
102 | *
103 | * @return array
104 | */
105 | function papi_get_all_core_type_files() {
106 | return papi()->once( __FUNCTION__, function() {
107 | $directories = papi_filter_settings_directories();
108 | $result = [];
109 |
110 | foreach ( $directories as $directory ) {
111 | $result = array_merge( $result, papi_get_all_files_in_directory( $directory ) );
112 | }
113 |
114 | // Get the last file path from directories.
115 | $result = array_map( 'papi_get_core_type_file_path', $result );
116 |
117 | // Only unique path, no duplicated path is allowed.
118 | return array_unique( $result );
119 | } );
120 | }
121 |
122 | /**
123 | * Get core type file path from file name.
124 | *
125 | * @param string $file
126 | *
127 | * @return null|string
128 | */
129 | function papi_get_file_path( $file ) {
130 | if ( empty( $file ) || ! is_string( $file ) ) {
131 | return;
132 | }
133 |
134 | $directories = papi_filter_settings_directories();
135 | $file = '/' . str_replace( ' ', '-', str_replace( '_', '-', $file ) );
136 |
137 | foreach ( $directories as $directory ) {
138 | if ( file_exists( $directory . $file ) ) {
139 | return $directory . $file;
140 | }
141 |
142 | if ( file_exists( $directory . $file . '.php' ) ) {
143 | return $directory . $file . '.php';
144 | }
145 | }
146 | }
147 |
148 | /**
149 | * Get core type base path.
150 | *
151 | * @param string $file
152 | *
153 | * @return string
154 | */
155 | function papi_get_core_type_base_path( $file ) {
156 | if ( empty( $file ) || ! is_string( $file ) ) {
157 | return '';
158 | }
159 |
160 | $directories = papi_filter_settings_directories();
161 |
162 | foreach ( $directories as $directory ) {
163 | if ( strpos( $file, $directory ) !== false ) {
164 | $file = str_replace( $directory . '/', '', $file );
165 | }
166 | }
167 |
168 | $file = explode( '.', $file );
169 |
170 | return $file[0];
171 | }
172 |
--------------------------------------------------------------------------------
/src/lib/core/meta.php:
--------------------------------------------------------------------------------
1 | term_id ) ) {
106 | return 'term';
107 | }
108 |
109 | if ( $obj instanceof WP_Post || isset( $obj->post_id ) ) {
110 | return 'post';
111 | }
112 | }
113 |
114 | // Default was has to be set here since we trying to figure out
115 | // which url conform which meta type.
116 | if ( is_null( $type ) ) {
117 | $type = 'post';
118 | }
119 |
120 | // If meta type exists as a filter we can return it.
121 | if ( function_exists( "get_{$type}_meta" ) ) {
122 | return $type;
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/lib/core/post.php:
--------------------------------------------------------------------------------
1 | ID ) ) {
12 | return $post_id->ID;
13 | }
14 |
15 | if ( is_numeric( $post_id ) && is_string( $post_id ) && $post_id !== '0' ) {
16 | return intval( $post_id );
17 | }
18 |
19 | if ( is_null( $post_id ) || intval( $post_id ) === 0 ) {
20 | if ( isset( $_POST['action'] ) ) {
21 | if ( $_POST['action'] === 'query-attachments' && isset( $_POST['query']['item'] ) ) {
22 | return intval( $_POST['query']['item'] );
23 | }
24 | }
25 |
26 | if ( get_post() ) {
27 | return get_the_ID();
28 | }
29 |
30 | if ( $value = papi_get_qs( 'post' ) ) {
31 | return is_array( $value ) ? 0 : intval( $value );
32 | }
33 |
34 | if ( $value = papi_get_qs( 'page_id' ) ) {
35 | return intval( $value );
36 | }
37 |
38 | return intval( $post_id );
39 | }
40 |
41 | return intval( $post_id );
42 | }
43 |
44 | /**
45 | * Get post parent id.
46 | *
47 | * @return int
48 | */
49 | function papi_get_parent_post_id() {
50 | return intval( papi_get_qs( 'post_parent' ) );
51 | }
52 |
53 | /**
54 | * Get WordPress post type in various ways.
55 | *
56 | * @param int $post_id
57 | *
58 | * @return string
59 | */
60 | function papi_get_post_type( $post_id = null ) {
61 | if ( $post_type = papi_get_or_post( 'post_type' ) ) {
62 | return $post_type;
63 | }
64 |
65 | $post_id = papi_get_post_id( $post_id );
66 |
67 | if ( $post_id !== 0 ) {
68 | return strtolower( get_post_type( $post_id ) );
69 | }
70 |
71 | $page = papi_get_qs( 'page' );
72 |
73 | if ( is_string( $page ) && strpos( strtolower( $page ), 'papi-add-new-page,' ) !== false ) {
74 | $exploded = explode( ',', $page );
75 |
76 | if ( empty( $exploded[1] ) ) {
77 | return '';
78 | }
79 |
80 | return $exploded[1];
81 | }
82 |
83 | // If only `post-new.php` without any querystrings
84 | // it would be the post post type.
85 | $req_uri = $_SERVER['REQUEST_URI'];
86 | $exploded = explode( '/', $req_uri );
87 | $last = end( $exploded );
88 |
89 | if ( $last === 'post-new.php' ) {
90 | return 'post';
91 | }
92 |
93 | return '';
94 | }
95 |
96 | /**
97 | * Get post type label.
98 | *
99 | * @param string $post_type
100 | * @param string $label
101 | * @param string $default
102 | *
103 | * @return string
104 | */
105 | function papi_get_post_type_label( $post_type, $label, $default = '' ) {
106 | if ( ! post_type_exists( $post_type ) ) {
107 | return $default;
108 | }
109 |
110 | return get_post_type_object( $post_type )->labels->$label;
111 | }
112 |
--------------------------------------------------------------------------------
/src/lib/core/slug.php:
--------------------------------------------------------------------------------
1 | capabilities ) ) {
19 | $_tabs[] = $tab;
20 | }
21 | }
22 |
23 | $tabs = papi_sort_order( $_tabs );
24 |
25 | // Generate unique names for all tabs.
26 | $len = count( $tabs );
27 | for ( $i = 0; $i < $len; $i ++ ) {
28 | $tabs[$i]->id = papi_html_name( $tabs[$i]->title ) . '_' . $i;
29 | }
30 |
31 | return $tabs;
32 | }
33 |
34 | /**
35 | * Create a new tab array or rendering a template tab file.
36 | *
37 | * @param string|array $file_or_options
38 | * @param array $properties
39 | *
40 | * @return Papi_Core_Tab
41 | */
42 | function papi_tab( $file_or_options, $properties = [] ) {
43 | list( $options, $properties ) = papi_get_options_and_properties( $file_or_options, $properties, false );
44 |
45 | return new Papi_Core_Tab( $options, $properties );
46 | }
47 |
--------------------------------------------------------------------------------
/src/lib/core/taxonomy.php:
--------------------------------------------------------------------------------
1 | term_id ) ) {
12 | return $term_id->term_id;
13 | }
14 |
15 | if ( is_numeric( $term_id ) && is_string( $term_id ) && $term_id !== '0' ) {
16 | return intval( $term_id );
17 | }
18 |
19 | if ( is_null( $term_id ) || intval( $term_id ) === 0 ) {
20 | if ( ! papi_is_admin() && ( is_category() || is_tag() || is_tax() ) ) {
21 | return get_queried_object_id();
22 | } else if ( $term_id = papi_get_or_post( 'term_id' ) ) {
23 | return intval( $term_id );
24 | } else if ( $tag_id = papi_get_or_post( 'tag_ID' ) ) {
25 | return intval( $tag_id );
26 | }
27 | }
28 |
29 | return intval( $term_id );
30 | }
31 |
32 | /**
33 | * Get WordPress taxonomy in various ways.
34 | *
35 | * @param int $term_id
36 | *
37 | * @return string
38 | */
39 | function papi_get_taxonomy( $term_id = null ) {
40 | if ( $taxonomy = papi_get_or_post( 'taxonomy' ) ) {
41 | return $taxonomy;
42 | }
43 |
44 | $term_id = papi_get_term_id( $term_id );
45 |
46 | if ( ! empty( $term_id ) ) {
47 | $term = get_term( $term_id, '' );
48 |
49 | if ( is_object( $term ) && ! is_wp_error( $term ) ) {
50 | return strtolower( $term->taxonomy );
51 | }
52 | }
53 |
54 | return '';
55 | }
56 |
57 | /**
58 | * Get taxonomy label.
59 | *
60 | * @param string $taxonomy
61 | * @param string $label
62 | * @param string $default
63 | *
64 | * @return string
65 | */
66 | function papi_get_taxonomy_label( $taxonomy, $label, $default = '' ) {
67 | if ( ! taxonomy_exists( $taxonomy ) ) {
68 | return $default;
69 | }
70 |
71 | return get_taxonomy( $taxonomy )->labels->$label;
72 | }
73 |
--------------------------------------------------------------------------------
/src/lib/core/template.php:
--------------------------------------------------------------------------------
1 | $value ) {
93 | $template->set_option( $key, $value );
94 | }
95 |
96 | $result = $template;
97 | } else {
98 | $result = array_merge( (array) $template, $values );
99 | }
100 |
101 | if ( $convert_to_object ) {
102 | return (object) $result;
103 | }
104 |
105 | return $result;
106 | }
107 |
108 | /**
109 | * Include template files from Papis custom page template meta field.
110 | *
111 | * @param string $original_template
112 | *
113 | * @return string
114 | */
115 | function papi_template_include( $original_template ) {
116 | global $post;
117 |
118 | // Check so we only change template on single and page posts.
119 | if ( ! is_single() && ! is_page() && ! is_tag() ) {
120 | return $original_template;
121 | }
122 |
123 | /**
124 | * Modify which template is included before Papi looks for the right template.
125 | *
126 | * @param string $original_template
127 | *
128 | * @return string
129 | */
130 | $template = apply_filters( 'papi/pre_template_include', $original_template );
131 |
132 | if ( ! empty( $template ) && $original_template !== $template ) {
133 | return $template;
134 | }
135 |
136 | // Determine which id to use.
137 | $id = is_tag() ? get_queried_object()->term_id : $post->ID;
138 |
139 | // Only load a template if it exists.
140 | if ( $page_template = papi_get_entry_type_template( $id ) ) {
141 | if ( $template = locate_template( $page_template ) ) {
142 | /**
143 | * Change which template that is used by Papi.
144 | *
145 | * @param string $template
146 | *
147 | * @return string
148 | */
149 | return apply_filters( 'papi/template_include', $template );
150 | }
151 | }
152 |
153 | return $original_template;
154 | }
155 | add_filter( 'template_include', 'papi_template_include' );
156 |
--------------------------------------------------------------------------------
/src/lib/core/url.php:
--------------------------------------------------------------------------------
1 | get_id();
31 | }
32 |
33 | $value = apply_filters( 'papi/settings/show_page_type_' . $post_type, $page_type );
34 |
35 | if ( $value === $page_type ) {
36 | return true;
37 | }
38 |
39 | if ( ! is_bool( $value ) ) {
40 | return false;
41 | }
42 |
43 | return $value;
44 | }
45 |
46 | /**
47 | * Get standard page description for the given post type.
48 | *
49 | * @param string $post_type
50 | *
51 | * @return string
52 | */
53 | function papi_filter_settings_standard_page_type_description( $post_type ) {
54 | $name = papi_get_post_type_label( $post_type, 'singular_name', 'Page' );
55 |
56 | // New filter, with `type` in the filter tag.
57 | $tag = 'papi/settings/standard_page_type_description_' . $post_type;
58 | $out = apply_filters( $tag, sprintf( __( '%s with WordPress standard fields', 'papi' ), $name ) );
59 |
60 | // Old filter, that didn't have `type` in the filter tag.
61 | // Should work until Papi 4.0.0.
62 | $tag = 'papi/settings/standard_page_description_' . $post_type;
63 | $out = apply_filters( $tag, $out );
64 |
65 | return $out;
66 | }
67 |
68 | /**
69 | * Get standard page name for the given post type.
70 | *
71 | * @param string $post_type
72 | *
73 | * @return string
74 | */
75 | function papi_filter_settings_standard_page_type_name( $post_type ) {
76 | $name = papi_get_post_type_label( $post_type, 'singular_name', 'Page' );
77 |
78 | // New filter, with `type` in the filter tag.
79 | $tag = 'papi/settings/standard_page_type_name_' . $post_type;
80 | $out = apply_filters( $tag, sprintf( __( 'Standard %s', 'papi' ), $name ) );
81 |
82 | // Old filter, that didn't have `type` in the filter tag.
83 | // Should work until Papi 4.0.0.
84 | $tag = 'papi/settings/standard_page_name_' . $post_type;
85 | $out = apply_filters( $tag, $out );
86 |
87 | return $out;
88 | }
89 |
90 | /**
91 | * Show standard page type on the given post type.
92 | *
93 | * @param string $post_type
94 | *
95 | * @return bool
96 | */
97 | function papi_filter_settings_show_standard_page_type( $post_type ) {
98 | return ! apply_filters( 'papi/settings/show_standard_page_type_' . $post_type, false ) === false;
99 | }
100 |
101 | /**
102 | * Show standard page type in filter dropdown on the given post type.
103 | *
104 | * @param string $post_type
105 | *
106 | * @return bool
107 | */
108 | function papi_filter_settings_show_standard_page_type_in_filter( $post_type ) {
109 | $tag = 'papi/settings/show_standard_page_type_in_filter_' . $post_type;
110 |
111 | return ! apply_filters( $tag, papi_filter_settings_show_standard_page_type( $post_type ) ) === false;
112 | }
113 |
114 | /**
115 | * Get standard page thumbnail for the given post type.
116 | *
117 | * @param string $post_type
118 | *
119 | * @return string
120 | */
121 | function papi_filter_settings_standard_page_type_thumbnail( $post_type ) {
122 | // New filter, with `type` in the filter tag.
123 | $tag = 'papi/settings/standard_page_type_thumbnail_' . $post_type;
124 | $out = apply_filters( $tag, '' );
125 |
126 | // Old filter, that didn't have `type` in the filter tag.
127 | // Should work until Papi 4.0.0.
128 | $tag = 'papi/settings/standard_page_thumbnail_' . $post_type;
129 | $out = apply_filters( $tag, $out );
130 |
131 | return $out;
132 | }
133 |
--------------------------------------------------------------------------------
/src/lib/hooks/filters-taxonomy-type.php:
--------------------------------------------------------------------------------
1 | operator, $rule );
18 |
19 | if ( $result === true || $result === false ) {
20 | return $result;
21 | }
22 |
23 | return false;
24 | }
25 |
26 | /**
27 | * Format the value of the property before it's returned to WordPress admin or the site.
28 | *
29 | * @since 3.1.0 `$meta_type` argument was added.
30 | *
31 | * @param string $type
32 | * @param mixed $value
33 | * @param string $slug
34 | * @param int $id
35 | * @param string $meta_type
36 | *
37 | * @return mixed
38 | */
39 | function papi_filter_format_value( $type, $value, $slug, $id, $meta_type = 'post' ) {
40 | return apply_filters( 'papi/format_value/' . $type, $value, $slug, $id, $meta_type );
41 | }
42 |
43 | /**
44 | * This filter is applied after the value is loaded in the database.
45 | *
46 | * @since 3.1.0 `$meta_type` argument was added.
47 | *
48 | * @param string $type
49 | * @param mixed $value
50 | * @param string $slug
51 | * @param int $id
52 | * @param string $meta_type
53 | *
54 | * @return mixed
55 | */
56 | function papi_filter_load_value( $type, $value, $slug, $id, $meta_type = 'post' ) {
57 | return apply_filters( 'papi/load_value/' . $type, $value, $slug, $id, $meta_type );
58 | }
59 |
60 | /**
61 | * Get all registered page type directories.
62 | *
63 | * @return array
64 | */
65 | function papi_filter_settings_directories() {
66 | $directories = apply_filters( 'papi/settings/directories', [] );
67 |
68 | if ( empty( $directories ) ) {
69 | $directories = get_template_directory() . '/page-types';
70 | }
71 |
72 | if ( is_string( $directories ) ) {
73 | return [$directories];
74 | }
75 |
76 | if ( ! is_array( $directories ) ) {
77 | return [];
78 | }
79 |
80 | return array_filter( $directories, function ( $directory ) {
81 | return is_string( $directory );
82 | } );
83 | }
84 |
85 | /**
86 | * Get the default sort order that is 1000.
87 | *
88 | * @return int
89 | */
90 | function papi_filter_settings_sort_order() {
91 | return intval( apply_filters( 'papi/settings/sort_order', 1000 ) );
92 | }
93 |
94 | /**
95 | * This filter is applied before the value is saved in the database.
96 | *
97 | * @since 3.1.0 `$meta_type` argument was added.
98 | *
99 | * @param string $type
100 | * @param mixed $value
101 | * @param string $slug
102 | * @param int $id
103 | * @param string $meta_type
104 | *
105 | * @return mixed
106 | */
107 | function papi_filter_update_value( $type, $value, $slug, $id, $meta_type = 'post' ) {
108 | return apply_filters( 'papi/update_value/' . $type, $value, $slug, $id, $meta_type );
109 | }
110 |
--------------------------------------------------------------------------------
/src/lib/types/taxonomy.php:
--------------------------------------------------------------------------------
1 | name;
41 | }
42 |
43 | /**
44 | * Load the entry type id on a taxonomy.
45 | *
46 | * @param string $entry_type_id
47 | * @param string $type
48 | *
49 | * @return string
50 | */
51 | function papi_load_taxonomy_type_id( $entry_type_id = '', $type = 'term' ) {
52 | if ( $type !== 'term' ) {
53 | return $entry_type_id;
54 | }
55 |
56 | $key = papi_get_page_type_key();
57 | $term_id = papi_get_term_id();
58 | $taxonomy = papi_get_taxonomy( $term_id );
59 |
60 | // Try to load the entry type id from only taxonomy type filter.
61 | if ( empty( $entry_type_id ) ) {
62 | $entry_type_id = papi_filter_settings_only_taxonomy_type( $taxonomy );
63 | }
64 |
65 | // If we have a term id we can load the entry type id from the term.
66 | if ( empty( $entry_type_id ) && $term_id > 0 ) {
67 | $meta_value = get_term_meta( $term_id, $key, true );
68 | $entry_type_id = empty( $meta_value ) ? '' : $meta_value;
69 | }
70 |
71 | // Try to load the entry type from all taxonomy types and check
72 | // if only one exists of that post type.
73 | //
74 | // The same as only taxonomy type filter but without the filter.
75 | if ( empty( $entry_type_id ) ) {
76 | $key = sprintf( 'entry_type_id.taxonomy.%s', $taxonomy );
77 |
78 | if ( papi()->exists( $key ) ) {
79 | return papi()->make( $key );
80 | }
81 |
82 | $entries = papi_get_all_entry_types( [
83 | 'args' => $taxonomy,
84 | 'mode' => 'include',
85 | 'types' => ['taxonomy']
86 | ] );
87 |
88 | if ( is_array( $entries ) ) {
89 | usort( $entries, function ( $a, $b ) {
90 | return strcmp( $a->name, $b->name );
91 | } );
92 | }
93 |
94 | $entries = papi_sort_order( array_reverse( $entries ) );
95 |
96 | if ( count( $entries ) === 1 ) {
97 | $entry_type_id = $entries[0]->get_id();
98 |
99 | papi()->bind( $key, $entry_type_id );
100 | }
101 | }
102 |
103 | return $entry_type_id;
104 | }
105 |
106 | add_filter( 'papi/entry_type_id', 'papi_load_taxonomy_type_id', 10, 2 );
107 |
108 | /**
109 | * Get all taxonomies Papi should work with.
110 | *
111 | * @return array
112 | */
113 | function papi_get_taxonomies() {
114 | $taxonomies = [];
115 | $entry_types = papi_get_all_entry_types( [
116 | 'types' => 'taxonomy'
117 | ] );
118 |
119 | foreach ( $entry_types as $entry_type ) {
120 | $taxonomies = array_merge( $taxonomies, papi_to_array( $entry_type->taxonomy ) );
121 | }
122 |
123 | return array_filter( array_unique( $taxonomies ) );
124 | }
125 |
126 | /**
127 | * Set taxonomy type to a term.
128 | *
129 | * @param mixed $term_id
130 | * @param string $taxonomy_type
131 | *
132 | * @return bool
133 | */
134 | function papi_set_taxonomy_type_id( $term_id, $taxonomy_type ) {
135 | if ( papi_entry_type_exists( $taxonomy_type ) ) {
136 | return update_term_meta( papi_get_term_id( $term_id ), papi_get_page_type_key(), $taxonomy_type );
137 | }
138 |
139 | return false;
140 | }
141 |
142 | /**
143 | * Echo the taxonomy type name.
144 | *
145 | * @param int $term_id
146 | *
147 | * @return string
148 | */
149 | function the_papi_taxonomy_type_name( $term_id = 0 ) {
150 | echo esc_html( papi_get_taxonomy_type_name( $term_id ) );
151 | }
152 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-bool.php:
--------------------------------------------------------------------------------
1 | get_value();
47 |
48 | papi_render_html_tag( 'input', [
49 | 'type' => 'hidden',
50 | 'name' => esc_attr( $this->html_name() ),
51 | 'value' => false
52 | ] );
53 |
54 | papi_render_html_tag( 'input', [
55 | 'checked' => ! empty( $value ),
56 | 'id' => esc_attr( $this->html_id() ),
57 | 'name' => esc_attr( $this->html_name() ),
58 | 'type' => 'checkbox'
59 | ] );
60 | }
61 |
62 | /**
63 | * Change value after it's loaded from the database.
64 | *
65 | * @param mixed $value
66 | * @param string $slug
67 | * @param int $post_id
68 | *
69 | * @return mixed
70 | */
71 | public function load_value( $value, $slug, $post_id ) {
72 | return is_string( $value ) && $value === '1' || $value;
73 | }
74 |
75 | /**
76 | * Prepare property value.
77 | *
78 | * @param mixed $value
79 | *
80 | * @return mixed
81 | */
82 | protected function prepare_value( $value ) {
83 | if ( is_string( $value ) && ( $value === 'true' || $value === 'on' ) || $value === true ) {
84 | return true;
85 | }
86 |
87 | return null;
88 | }
89 |
90 | /**
91 | * Fix the database value on update.
92 | *
93 | * @param mixed $value
94 | * @param string $slug
95 | * @param int $post_id
96 | *
97 | * @return array
98 | */
99 | public function update_value( $value, $slug, $post_id ) {
100 | return $this->prepare_value( $value );
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-checkbox.php:
--------------------------------------------------------------------------------
1 | default_value;
40 | }
41 |
42 | return array_map( 'papi_cast_string_value', $value );
43 | }
44 |
45 | /**
46 | * Get default settings.
47 | *
48 | * @return array
49 | */
50 | public function get_default_settings() {
51 | return [
52 | 'items' => [],
53 | 'selected' => []
54 | ];
55 | }
56 |
57 | /**
58 | * Render property html.
59 | */
60 | public function html() {
61 | $settings = $this->get_settings();
62 | $value = papi_cast_string_value( $this->get_value() );
63 |
64 | // Override selected setting with
65 | // database value if not empty.
66 | if ( ! papi_is_empty( $value ) ) {
67 | $settings->selected = $value;
68 | }
69 |
70 | $settings->selected = papi_to_array( $settings->selected );
71 |
72 | echo '';
73 |
74 | foreach ( $settings->items as $key => $value ) {
75 | $key = is_numeric( $key ) ? $value : $key;
76 |
77 | papi_render_html_tag( 'p', [
78 | papi_html_tag( 'label', [
79 | 'class' => 'light',
80 | 'for' => esc_attr( $this->html_id( $key ) ),
81 |
82 | papi_html_tag( 'input', [
83 | 'id' => esc_attr( $this->html_id( $key ) ),
84 | 'name' => esc_attr( $this->html_name() ) . '[]',
85 | 'type' => 'hidden'
86 | ] ),
87 |
88 | papi_html_tag( 'input', [
89 | 'checked' => in_array( $value, $settings->selected, true ),
90 | 'id' => esc_attr( $this->html_id( $key ) ),
91 | 'name' => esc_attr( $this->html_name() ) . '[]',
92 | 'type' => 'checkbox',
93 | 'value' => esc_attr( $value )
94 | ] ),
95 |
96 | esc_html( papi_convert_to_string( $key ) )
97 | ] )
98 | ] );
99 | }
100 |
101 | echo '
';
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-color.php:
--------------------------------------------------------------------------------
1 | false,
17 | 'clear' => false,
18 | 'default_color' => false,
19 | 'hide' => false,
20 | 'mode' => 'hsv',
21 | 'palettes' => true,
22 | 'slider' => 'horizontal',
23 | 'show_input' => false,
24 | 'type' => 'full',
25 | 'width' => 255
26 | ];
27 | }
28 |
29 | /**
30 | * Render property html.
31 | */
32 | public function html() {
33 | $settings = $this->get_settings();
34 | $value = $this->get_value();
35 |
36 | papi_render_html_tag( 'div', [
37 | 'class' => 'papi-property-color-picker',
38 |
39 | papi_html_tag( 'input', [
40 | 'data-settings' => $settings,
41 | 'id' => $this->html_id(),
42 | 'name' => $this->html_name(),
43 | 'type' => $settings->show_input === true ? 'text' : 'hidden',
44 | 'value' => $value,
45 | ] )
46 |
47 | ] );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-datetime.php:
--------------------------------------------------------------------------------
1 | 'YYYY-MM-DD hh:mm:ss',
16 | 'first_day' => 0,
17 | 'show_seconds' => false,
18 | 'show_time' => true,
19 | 'show_time_first' => false,
20 | 'show_week_number' => false,
21 | 'use_24_hours' => get_locale() === 'sv_SE'
22 | ];
23 | }
24 |
25 | /**
26 | * Render property html.
27 | */
28 | public function html() {
29 | $settings = $this->get_settings();
30 | $value = $this->get_value();
31 |
32 | $settings_json = [
33 | 'i18n' => [
34 | 'previousMonth' => __( 'Previous Month', 'papi' ),
35 | 'nextMonth' => __( 'Next Month', 'papi' ),
36 | 'midnight' => __( 'Midnight', 'papi' ),
37 | 'months' => [
38 | __( 'January', 'papi' ),
39 | __( 'February', 'papi' ),
40 | __( 'March', 'papi' ),
41 | __( 'April', 'papi' ),
42 | __( 'May', 'papi' ),
43 | __( 'June', 'papi' ),
44 | __( 'July', 'papi' ),
45 | __( 'August', 'papi' ),
46 | __( 'September', 'papi' ),
47 | __( 'October', 'papi' ),
48 | __( 'November', 'papi' ),
49 | __( 'December', 'papi' )
50 | ],
51 | 'noon' => __( 'Noon', 'papi' ),
52 | 'weekdays' => [
53 | __( 'Sunday', 'papi' ),
54 | __( 'Monday', 'papi' ),
55 | __( 'Tuesday', 'papi' ),
56 | __( 'Wednesday', 'papi' ),
57 | __( 'Thursday', 'papi' ),
58 | __( 'Friday', 'papi' ),
59 | __( 'Saturday', 'papi' )
60 | ],
61 | 'weekdaysShort' => [
62 | __( 'Sun', 'papi' ),
63 | __( 'Mon', 'papi' ),
64 | __( 'Tue', 'papi' ),
65 | __( 'Wed', 'papi' ),
66 | __( 'Thu', 'papi' ),
67 | __( 'Fri', 'papi' ),
68 | __( 'Sat', 'papi' )
69 | ]
70 | ]
71 | ];
72 |
73 | // Remove i18n setting if it exists.
74 | if ( isset( $settings->i18n ) ) {
75 | unset( $settings->i18n );
76 | }
77 |
78 | // Remove default time format if show time is false.
79 | if ( isset( $settings->show_time ) && ! $settings->show_time && isset( $settings->format ) ) {
80 | $settings->format = trim( str_replace( 'hh:mm:ss', '', $settings->format ) );
81 | }
82 |
83 | // Convert all sneak case key to camel case.
84 | foreach ( (array) $settings as $key => $val ) {
85 | if ( ! is_string( $key ) ) {
86 | continue;
87 | }
88 |
89 | if ( $key = papi_camel_case( $key ) ) {
90 | $settings_json[$key] = $val;
91 | }
92 | }
93 |
94 | // Papi has `use24Hours` as key and Pikaday has `use24hour`.
95 | // This code will fix it.
96 | if ( isset( $settings_json['use24Hours'] ) ) {
97 | $settings_json['use24hour'] = $settings_json['use24Hours'];
98 | unset( $settings_json['use24Hours'] );
99 | }
100 |
101 | papi_render_html_tag( 'input', [
102 | 'class' => 'papi-property-datetime',
103 | 'data-settings' => (object) $settings_json,
104 | 'id' => $this->html_id(),
105 | 'name' => $this->html_name(),
106 | 'type' => 'text',
107 | 'value' => $value
108 | ] );
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-divider.php:
--------------------------------------------------------------------------------
1 | get_options();
20 | $title = '';
21 | $text = '';
22 |
23 | if ( ! papi_is_empty( $options->title ) ) {
24 | $title = sprintf( '%s
', esc_html( $options->title ) );
25 | }
26 |
27 | if ( ! papi_is_empty( $options->description ) ) {
28 | $text = sprintf( '%s
', $options->description );
29 | }
30 |
31 | papi_render_html_tag( 'div', [
32 | 'class' => 'papi-property-divider',
33 | 'data-papi-rule' => esc_attr( $this->html_name() ),
34 | sprintf( '%s%s', $title, $text )
35 | ] );
36 | }
37 |
38 | /**
39 | * Render the final html that is displayed in the table.
40 | */
41 | protected function render_row_html() {
42 | if ( $this->get_option( 'raw' ) ) {
43 | parent::render_row_html();
44 | } else {
45 | ?>
46 |
47 |
48 | render_property_html(); ?>
49 | |
50 |
51 | get_setting( 'multiple' ) ) {
27 | return $this->is_string_items() ? $value : papi_cast_string_value( $value );
28 | }
29 |
30 | $value = is_array( $value ) ? $value : [];
31 |
32 | if ( ! $this->is_string_items() ) {
33 | $value = array_map( 'papi_cast_string_value', $value );
34 | }
35 |
36 | return $value;
37 | }
38 |
39 | /**
40 | * Determine if items are strings or not.
41 | *
42 | * @return bool
43 | */
44 | public function is_string_items() {
45 | $items = $this->get_items();
46 |
47 | if ( empty( $items ) ) {
48 | return false;
49 | }
50 |
51 | $items = array_values( $items );
52 |
53 | return is_string( $items[0] );
54 | }
55 |
56 | /**
57 | * Get default settings.
58 | *
59 | * @return array
60 | */
61 | public function get_default_settings() {
62 | return [
63 | 'allow_clear' => true,
64 | 'placeholder' => null,
65 | 'items' => [],
66 | 'multiple' => false,
67 | 'selected' => [],
68 | 'select2' => true
69 | ];
70 | }
71 |
72 | /**
73 | * Get dropdown items.
74 | *
75 | * @return array
76 | */
77 | protected function get_items() {
78 | return papi_to_array( $this->get_setting( 'items', [] ) );
79 | }
80 |
81 | /**
82 | * Render property html.
83 | */
84 | public function html() {
85 | // Setup variables needed.
86 | $settings = $this->get_settings();
87 | $value = $this->get_value();
88 | $options_html = [];
89 |
90 | // Properties that extends dropdown property
91 | // maybe don't have this setting.
92 | if ( ! isset( $settings->selected ) ) {
93 | $settings->selected = [];
94 | }
95 |
96 | // Properties that extends dropdown property
97 | // maybe don't have this setting.
98 | if ( ! isset( $settings->multiple ) ) {
99 | $settings->multiple = false;
100 | }
101 |
102 | // Override selected setting with
103 | // database value if not empty.
104 | if ( ! papi_is_empty( $value ) ) {
105 | $settings->selected = $value;
106 | }
107 |
108 | $placeholder = ! is_null( $settings->placeholder ) ? $settings->placeholder : '';
109 | $placeholder = papi_is_empty( $placeholder ) ? ' ' : $placeholder;
110 |
111 | // Add placeholder if any.
112 | if ( ! is_null( $settings->placeholder ) ) {
113 | $options_html[] = sprintf( '', esc_attr( $this->get_option( 'default', '' ) ), esc_html( $placeholder ) );
114 | }
115 |
116 | $classes = 'papi-fullwidth';
117 |
118 | if ( $settings->select2 ) {
119 | $classes .= ' papi-component-select2';
120 | }
121 |
122 | // Create option html tags for all items.
123 | foreach ( $this->get_items() as $key => $value ) {
124 | $key = is_numeric( $key ) ? $value : $key;
125 |
126 | if ( papi_is_empty( $key ) ) {
127 | continue;
128 | }
129 |
130 | // When a multiple we need to check with
131 | // `in_array` since the value is a array.
132 | if ( $settings->multiple ) {
133 | $selected = in_array( $value, $settings->selected, true );
134 | } else {
135 | $selected = papi_convert_to_string( $value ) === papi_convert_to_string( $settings->selected );
136 | }
137 |
138 | $options_html[] = papi_html_tag( 'option', [
139 | 'data-edit-url' => false,
140 | 'data-new-url' => false,
141 | 'selected' => $selected ? 'selected' : null,
142 | 'value' => $value,
143 | esc_html( papi_convert_to_string( $key ) )
144 | ] );
145 | }
146 |
147 | // When selectize is empty this will be used.
148 | papi_render_html_tag( 'input', [
149 | 'name' => $this->html_name() . ( $settings->multiple ? '[]' : '' ),
150 | 'type' => 'hidden'
151 | ] );
152 |
153 | papi_render_html_tag( 'select', [
154 | 'class' => $classes,
155 | 'data-allow-clear' => $settings->allow_clear,
156 | 'data-placeholder' => $placeholder,
157 | 'data-width' => '100%',
158 | 'id' => $this->html_id() . ( $settings->multiple ? '[]' : '' ),
159 | 'multiple' => $settings->multiple ? 'multiple' : null,
160 | 'name' => $this->html_name() . ( $settings->multiple ? '[]' : '' ),
161 | $options_html
162 | ] );
163 | }
164 |
165 | /**
166 | * Change value after it's loaded from the database.
167 | *
168 | * @param mixed $value
169 | * @param string $slug
170 | * @param int $post_id
171 | *
172 | * @return mixed
173 | */
174 | public function load_value( $value, $slug, $post_id ) {
175 | $value = maybe_unserialize( $value );
176 |
177 | return papi_maybe_json_decode( $value, $this->get_setting( 'multiple' ) );
178 | }
179 |
180 | /**
181 | * Update value before it's saved to the database.
182 | *
183 | * @param mixed $value
184 | * @param string $slug
185 | * @param int $post_id
186 | *
187 | * @return mixed
188 | */
189 | public function update_value( $value, $slug, $post_id ) {
190 | if ( ! ( $value = $this->prepare_value( $value ) ) ) {
191 | return;
192 | }
193 |
194 | return papi_maybe_json_encode( $value );
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-editor.php:
--------------------------------------------------------------------------------
1 | [],
40 | 'mce_buttons_2' => [],
41 | 'mce_buttons_3' => [],
42 | 'mce_buttons_4' => [],
43 | 'media_buttons' => true,
44 | 'teeny' => false,
45 | 'drag_drop_upload' => true
46 | ];
47 | }
48 |
49 | /**
50 | * Filter TinyMCE buttons (Visual tab).
51 | *
52 | * @param array $buttons
53 | *
54 | * @return array
55 | */
56 | public function mce_buttons( array $buttons = [] ) {
57 | if ( $new = papi_to_array( $this->get_setting( current_filter(), [] ) ) ) {
58 | return $new;
59 | }
60 |
61 | return $buttons;
62 | }
63 |
64 | /**
65 | * Render property html.
66 | */
67 | public function html() {
68 | $value = $this->get_value();
69 | $value = html_entity_decode( $value );
70 | $id = str_replace(
71 | '[',
72 | '',
73 | str_replace( ']', '', $this->html_name() )
74 | ) . '-' . uniqid();
75 |
76 | // Add `mce_buttons` filters.
77 | $this->add_mce_buttons();
78 |
79 | wp_editor( $value, $id, [
80 | 'textarea_name' => esc_attr( $this->html_name() ),
81 | 'media_buttons' => $this->get_setting( 'media_buttons', true ),
82 | 'teeny' => $this->get_setting( 'teeny', false ),
83 | 'drag_drop_upload' => $this->get_setting( 'drag_drop_upload', true ),
84 | ] );
85 |
86 | // Remove `mce_buttons` filters.
87 | $this->reove_mce_buttons();
88 |
89 | if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
90 | add_filter( 'mce_external_plugins', '__return_empty_array' );
91 | }
92 | }
93 |
94 | /**
95 | * Remove filters that filter TinyMCE buttons.
96 | */
97 | protected function reove_mce_buttons() {
98 | for ( $i = 0; $i < 4; $i++ ) {
99 | $num = $i === 0 ? '' : '_' . ( $i + 1 );
100 | remove_filter( 'mce_buttons' . $num, [$this, 'mce_buttons'] );
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-email.php:
--------------------------------------------------------------------------------
1 | true
30 | ];
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-group.php:
--------------------------------------------------------------------------------
1 | get_parent_property() instanceof Papi_Property_Repeater ) {
27 | $this->cache = false;
28 | }
29 |
30 | $value = parent::format_value( $value, $slug, $post_id );
31 |
32 | return array_shift( $value );
33 | }
34 |
35 | /**
36 | * Get default settings.
37 | *
38 | * @return array
39 | */
40 | public function get_default_settings() {
41 | return [
42 | 'items' => []
43 | ];
44 | }
45 |
46 | /**
47 | * Get settings properties.
48 | *
49 | * @return array
50 | */
51 | protected function get_settings_properties() {
52 | $settings = $this->get_settings();
53 |
54 | if ( is_null( $settings ) ) {
55 | return [];
56 | }
57 |
58 | return array_filter( array_map( 'papi_property', papi_to_array( $settings->items ) ), 'papi_is_property' );
59 | }
60 |
61 | /**
62 | * Render property html.
63 | */
64 | public function html() {
65 | $properties = $this->get_settings_properties();
66 | $properties = $this->prepare_properties( $properties );
67 |
68 | // Fix so group is not render over the title and description.
69 | if ( $this->get_option( 'layout' ) === 'vertical' ) {
70 | echo '
';
71 | }
72 |
73 | echo '';
74 | papi_render_properties( $properties );
75 | echo '
';
76 | }
77 |
78 | /**
79 | * Prepare properties and set right slug and value.
80 | *
81 | * @param array $properties
82 | *
83 | * @return array
84 | */
85 | protected function prepare_properties( $properties ) {
86 | $result = [];
87 | $value = $this->get_value();
88 | $value = is_array( $value ) ? $value : [];
89 |
90 | foreach ( $properties as $property ) {
91 | $render_property = clone $property->get_options();
92 | $value_slug = $property->get_slug( true );
93 |
94 | if ( array_key_exists( $value_slug, $value ) ) {
95 | $render_property->value = $value[$value_slug];
96 | } else {
97 | $render_property->value = null;
98 | }
99 |
100 | $render_property->slug = $this->html_name( $property );
101 |
102 | $result[] = $render_property;
103 | }
104 |
105 | return $result;
106 | }
107 |
108 | /**
109 | * Update value before it's saved to the database.
110 | *
111 | * @param mixed $values
112 | * @param string $slug
113 | * @param int $post_id
114 | *
115 | * @return array
116 | */
117 | public function update_value( $values, $slug, $post_id ) {
118 | if ( ! isset( $values[0] ) && ! empty( $values ) ) {
119 | $values = [$values];
120 | }
121 |
122 | return parent::update_value( $values, $slug, $post_id );
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-hidden.php:
--------------------------------------------------------------------------------
1 | '',
23 | 'save' => false
24 | ];
25 | }
26 |
27 | /**
28 | * Render property html.
29 | */
30 | public function html() {
31 | $settings = $this->get_settings();
32 | $html = papi_maybe_get_callable_value( $settings->html );
33 |
34 | if ( $settings->save ) {
35 | $value = $this->get_value();
36 |
37 | if ( ! empty( $value ) && is_string( $value ) ) {
38 | $html = $value;
39 | }
40 |
41 | papi_render_html_tag( 'input', [
42 | 'name' => esc_attr( $this->html_name() ),
43 | 'type' => 'hidden',
44 | 'value' => $html
45 | ] );
46 | }
47 |
48 | papi_render_html_tag( 'div', [
49 | 'data-papi-rule' => esc_attr( $this->html_name() ),
50 | 'class' => 'property-html',
51 | $html
52 | ] );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-image.php:
--------------------------------------------------------------------------------
1 | __( 'Add image', 'papi' ),
23 | 'no_file' => __( 'No image selected', 'papi' )
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-number.php:
--------------------------------------------------------------------------------
1 | get_value();
22 |
23 | return is_float( $value ) ? 'float' : $this->convert_type;
24 | }
25 |
26 | /**
27 | * Format the value of the property before it's returned
28 | * to WordPress admin or the site.
29 | *
30 | * @param mixed $value
31 | * @param string $slug
32 | * @param int $post_id
33 | *
34 | * @return float|int
35 | */
36 | public function format_value( $value, $slug, $post_id ) {
37 | $value = is_string( $value ) && is_numeric( $value ) ? $value + 0 : $value;
38 |
39 | if ( is_float( $value ) ) {
40 | return floatval( $value );
41 | } else {
42 | return intval( $value );
43 | }
44 | }
45 |
46 | /**
47 | * Get default settings.
48 | *
49 | * @return array
50 | */
51 | public function get_default_settings() {
52 | return [
53 | 'max' => '',
54 | 'min' => '',
55 | 'step' => 'any',
56 | 'type' => 'number'
57 | ];
58 | }
59 |
60 | /**
61 | * Get value from the database.
62 | *
63 | * @return float|int
64 | */
65 | public function get_value() {
66 | return $this->format_value(
67 | parent::get_value(),
68 | $this->get_slug(),
69 | papi_get_post_id()
70 | );
71 | }
72 |
73 | /**
74 | * Render property html.
75 | */
76 | public function html() {
77 | $settings = $this->get_settings();
78 | $value = $this->get_value();
79 |
80 | // If range type is used change the default values if empty.
81 | if ( $settings->type === 'range' ) {
82 | $settings->max = papi_is_empty( $settings->max )
83 | ? 100 : $settings->max;
84 | $settings->min = papi_is_empty( $settings->min )
85 | ? 0 : $settings->min;
86 | $settings->step = papi_is_empty( $settings->step )
87 | ? 1 : $settings->step;
88 | }
89 |
90 | if ( $settings->min !== 0 && $value < $settings->min ) {
91 | $value = $settings->min;
92 | }
93 |
94 | papi_render_html_tag( 'input', [
95 | 'id' => $this->html_id(),
96 | 'max' => $settings->max,
97 | 'min' => $settings->min,
98 | 'name' => esc_attr( $this->html_name() ),
99 | 'step' => $settings->step,
100 | 'type' => esc_attr( $settings->type ),
101 | 'value' => $value
102 | ] );
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-radio.php:
--------------------------------------------------------------------------------
1 | [],
31 | 'selected' => ''
32 | ];
33 | }
34 |
35 | /**
36 | * Render property html.
37 | */
38 | public function html() {
39 | $settings = $this->get_settings();
40 | $value = papi_cast_string_value( $this->get_value() );
41 |
42 | // Override selected setting with
43 | // database value if not null.
44 | if ( ! papi_is_empty( $value ) ) {
45 | $settings->selected = $value;
46 | }
47 |
48 | echo '';
49 |
50 | foreach ( $settings->items as $key => $value ) {
51 | $key = is_numeric( $key ) ? $value : $key;
52 |
53 | papi_render_html_tag( 'p', [
54 | papi_html_tag( 'label', [
55 | 'class' => 'light',
56 | 'for' => esc_attr( $this->html_id( $key ) ),
57 |
58 | papi_html_tag( 'input', [
59 | 'id' => esc_attr( $this->html_id( $key ) ),
60 | 'name' => esc_attr( $this->html_name() ),
61 | 'type' => 'radio',
62 | 'checked' => $value === $settings->selected,
63 | 'value' => $value
64 | ] ),
65 |
66 | esc_html( papi_convert_to_string( $key ) )
67 | ] )
68 | ] );
69 | }
70 |
71 | echo '
';
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-reference.php:
--------------------------------------------------------------------------------
1 | [],
17 | 'page_type' => []
18 | ];
19 | }
20 |
21 | /**
22 | * Render property html.
23 | */
24 | public function html() {
25 | $post_id = papi_get_post_id();
26 | $settings = $this->get_settings();
27 |
28 | // Create query array for every page type.
29 | $page_types = array_map( function ( $page_type ) {
30 | return [
31 | 'key' => papi_get_page_type_key(),
32 | 'value' => $page_type,
33 | 'compare' => 'LIKE'
34 | ];
35 | }, papi_to_array( $settings->page_type ) );
36 |
37 | // Add relation.
38 | $page_types['relation'] = 'OR';
39 |
40 | // Prepare arguments for WP_Query.
41 | $args = [
42 | 'post_type' => 'any',
43 | 'no_found_rows' => true,
44 | 'update_post_meta_cache' => false,
45 | 'update_post_term_cache' => false,
46 | 'meta_query' => $page_types
47 | ];
48 |
49 | $posts = ( new WP_Query( $args ) )->posts;
50 |
51 | $values = [];
52 |
53 | foreach ( papi_to_array( $settings->slug ) as $slug ) {
54 | foreach ( $posts as $post ) {
55 | $val = papi_get_field( $post->ID, $slug );
56 |
57 | $val = array_filter( papi_to_array( $val ), function ( $item ) use ( $post_id ) {
58 | return is_object( $item ) && $item->ID === $post_id;
59 | } );
60 |
61 | if ( empty( $val ) ) {
62 | continue;
63 | }
64 |
65 | $page_type = papi_get_entry_type_by_meta_id( $post->ID );
66 |
67 | if ( empty( $page_type ) ) {
68 | continue;
69 | }
70 |
71 | // Create the array
72 | if ( ! isset( $values[$post->post_type] ) ) {
73 | $values[$post->post_type] = [];
74 | }
75 |
76 | if ( ! isset( $values[$post->post_type][$page_type->name] ) ) {
77 | $values[$post->post_type][$page_type->name] = [];
78 | }
79 |
80 | // Add the post
81 | if ( ! isset( $values[$post->post_type][$page_type->name][$post->ID] ) && ! empty( $val ) ) {
82 | $values[$post->post_type][$page_type->name][$post->ID] = $post;
83 | }
84 | }
85 | }
86 |
87 | ?>
88 |
89 |
90 |
91 |
92 |
93 | $val ):
96 | $post_type = get_post_type_object( $title );
97 | ?>
98 | -
99 |
labels->name ); ?>
100 |
101 |
102 | -
103 |
104 |
105 | $posts ): ?>
106 | -
107 |
108 |
109 |
110 | -
111 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | settings->render ) {
27 | return $value;
28 | }
29 |
30 | ob_start();
31 | if ( is_active_sidebar( $value ) ) {
32 | dynamic_sidebar( $value );
33 | }
34 |
35 | return ob_get_clean();
36 | }
37 |
38 | /**
39 | * Get default settings.
40 | *
41 | * @return array
42 | */
43 | public function get_default_settings() {
44 | return [
45 | 'allow_clear' => true,
46 | 'placeholder' => '',
47 | 'render' => true,
48 | 'select2' => true
49 | ];
50 | }
51 |
52 | /**
53 | * Get registered sidebars as dropdown items.
54 | *
55 | * @return array
56 | */
57 | public function get_items() {
58 | global $wp_registered_sidebars;
59 | $items = [];
60 |
61 | foreach ( $wp_registered_sidebars as $item ) {
62 | $items[$item['name']] = $item['id'];
63 | }
64 |
65 | ksort( $items );
66 |
67 | return $items;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-string.php:
--------------------------------------------------------------------------------
1 | get_setting( 'allow_html' ) && $this->input_type === 'text' ) {
27 | $value = papi_maybe_json_decode( maybe_unserialize( $value ) );
28 |
29 | if ( ! is_string( $value ) ) {
30 | $value = '';
31 | }
32 |
33 | $value = wp_strip_all_tags( $value );
34 | }
35 |
36 | return $value;
37 | }
38 |
39 | /**
40 | * Get default settings.
41 | *
42 | * @return array
43 | */
44 | public function get_default_settings() {
45 | return [
46 | 'allow_html' => false,
47 | 'placeholder' => ''
48 | ];
49 | }
50 |
51 | /**
52 | * Get value from the database.
53 | *
54 | * @return string
55 | */
56 | public function get_value() {
57 | $value = $this->format_value(
58 | parent::get_value(),
59 | $this->get_slug(),
60 | papi_get_post_id()
61 | );
62 |
63 | return $this->get_setting( 'allow_html' ) ? $value : esc_html( $value );
64 | }
65 |
66 | /**
67 | * Render property html.
68 | */
69 | public function html() {
70 | papi_render_html_tag( 'input', [
71 | 'id' => esc_attr( $this->html_id() ),
72 | 'name' => esc_attr( $this->html_name() ),
73 | 'type' => esc_attr( $this->input_type ),
74 | 'value' => $this->get_value(),
75 | 'placeholder' => esc_attr( $this->get_setting( 'placeholder' ) )
76 | ] );
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-table.php:
--------------------------------------------------------------------------------
1 | ';
22 | $allow_html = $this->get_setting( 'allow_html' );
23 |
24 | if ( $child ) {
25 | $html .= '';
26 |
27 | foreach ( $arr[0] as $key => $value ) {
28 | if ( $allow_html ) {
29 | $key = html_entity_decode( $key );
30 | }
31 |
32 | $html .= sprintf( '%s | ', $key );
33 | }
34 |
35 | $html .= '';
36 | }
37 |
38 | foreach ( $arr as $key => $value ) {
39 | $html .= '';
40 |
41 | foreach ( $value as $key2 => $value2 ) {
42 | if ( is_array( $value2 ) ) {
43 | $value2 = $this->build_table( $value2, true );
44 | }
45 |
46 | $value2 = papi_convert_to_string( $value2 );
47 |
48 | if ( $allow_html ) {
49 | $value2 = html_entity_decode( $value2 );
50 | }
51 |
52 | $html .= sprintf( '%s | ', $value2 );
53 | }
54 |
55 | $html .= '
';
56 | }
57 |
58 | return $html . '
';
59 | }
60 |
61 | /**
62 | * Get default settings.
63 | *
64 | * @return array
65 | */
66 | public function get_default_settings() {
67 | return [
68 | 'allow_html' => false,
69 | 'items' => [],
70 | ];
71 | }
72 |
73 | /**
74 | * Render property html.
75 | */
76 | public function html() {
77 | $value = $this->get_value();
78 | $data = $this->get_setting( 'items' );
79 |
80 | if ( ! is_array( $data ) ) {
81 | return;
82 | }
83 |
84 | // Convert key/value array to [key, value] value.
85 | foreach ( $data as $key => $value ) {
86 | if ( is_array( $value ) ) {
87 | continue;
88 | }
89 |
90 | $data[$key] = [$key, $value];
91 | }
92 |
93 | echo $this->build_table( $data ); // wpcs: xss ok
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-text.php:
--------------------------------------------------------------------------------
1 | get_setting( 'allow_html' ) ) {
20 | $value = maybe_unserialize( $value );
21 |
22 | if ( ! is_string( $value ) ) {
23 | $value = '';
24 | }
25 |
26 | $value = wp_strip_all_tags( $value );
27 |
28 | if ( ! papi_is_admin() ) {
29 | $value = $this->get_setting( 'nl2br' ) ? nl2br( $value ) : $value;
30 | }
31 | }
32 |
33 | return $value;
34 | }
35 |
36 | /**
37 | * Get default settings.
38 | *
39 | * @return array
40 | */
41 | public function get_default_settings() {
42 | return [
43 | 'allow_html' => false,
44 | 'nl2br' => true
45 | ];
46 | }
47 |
48 | /**
49 | * Get value from the database.
50 | *
51 | * @return string
52 | */
53 | public function get_value() {
54 | $value = $this->format_value(
55 | parent::get_value(),
56 | $this->get_slug(),
57 | papi_get_post_id()
58 | );
59 |
60 | return $this->get_setting( 'allow_html' ) ? $value : esc_html( $value );
61 | }
62 |
63 | /**
64 | * Render property html.
65 | */
66 | public function html() {
67 | papi_render_html_tag( 'textarea', [
68 | 'class' => 'papi-property-text',
69 | 'id' => esc_attr( $this->html_id() ),
70 | 'name' => esc_attr( $this->html_name() ),
71 | $this->get_value()
72 | ] );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-url.php:
--------------------------------------------------------------------------------
1 | false
16 | ];
17 | }
18 |
19 | /**
20 | * Render property html.
21 | */
22 | public function html() {
23 | $settings = $this->get_settings();
24 |
25 | papi_render_html_tag( 'input', [
26 | 'class' => $settings->mediauploader ? 'papi-url-media-input' : null,
27 | 'id' => esc_attr( $this->html_id() ),
28 | 'name' => esc_attr( $this->html_name() ),
29 | 'type' => 'url',
30 | 'value' => $this->get_value()
31 | ] );
32 |
33 | if ( $settings->mediauploader ) {
34 | echo ' ';
35 |
36 | papi_render_html_tag( 'input', [
37 | 'class' => 'button papi-url-media-button',
38 | 'data-papi-action' => 'mediauploader',
39 | 'id' => esc_attr( $this->html_id() ),
40 | 'name' => esc_attr( $this->html_name() . '_button' ),
41 | 'type' => 'button',
42 | 'value' => esc_attr__( 'Select file', 'papi' )
43 | ] );
44 | }
45 | }
46 |
47 | /**
48 | * Change value after it's loaded from the database.
49 | *
50 | * @param mixed $value
51 | * @param string $slug
52 | * @param int $post_id
53 | *
54 | * @return mixed
55 | */
56 | public function load_value( $value, $slug, $post_id ) {
57 | if ( filter_var( $value, FILTER_VALIDATE_URL ) ) {
58 | return $value;
59 | }
60 | }
61 |
62 | /**
63 | * Update value before it's saved to the database.
64 | *
65 | * @param mixed $value
66 | * @param string $slug
67 | * @param int $post_id
68 | *
69 | * @return mixed
70 | */
71 | public function update_value( $value, $slug, $post_id ) {
72 | return $this->load_value( $value, $slug, $post_id );
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property-user.php:
--------------------------------------------------------------------------------
1 | ID ) ) {
27 | $value = $value->ID;
28 | }
29 |
30 | if ( is_numeric( $value ) ) {
31 | return $value === 0 ? null : new WP_User( $value );
32 | }
33 |
34 | return $value;
35 | }
36 |
37 | /**
38 | * Get default settings.
39 | *
40 | * @return array
41 | */
42 | public function get_default_settings() {
43 | return [
44 | 'allow_clear' => true,
45 | 'capabilities' => [],
46 | 'placeholder' => '',
47 | 'select2' => true
48 | ];
49 | }
50 |
51 | /**
52 | * Get value from database.
53 | *
54 | * @return int
55 | */
56 | public function get_value() {
57 | $user = parent::get_value();
58 |
59 | if ( is_object( $user ) && isset( $user->ID ) ) {
60 | return $user->ID;
61 | }
62 |
63 | return 0;
64 | }
65 |
66 | /**
67 | * Get users as dropdown items.
68 | *
69 | * @return array
70 | */
71 | public function get_items() {
72 | $capabilities = papi_to_array( $this->get_setting( 'capabilities' ) );
73 | $users = get_users();
74 | $items = [];
75 |
76 | foreach ( $users as $user ) {
77 | $allcaps = $user->allcaps;
78 |
79 | if ( count( array_diff( $capabilities, array_keys( $allcaps ) ) ) === 0 ) {
80 | $items[$user->display_name] = $user->ID;
81 | }
82 | }
83 |
84 | ksort( $items );
85 |
86 | return $items;
87 | }
88 |
89 | /**
90 | * Change value after it's loaded from the database.
91 | *
92 | * @param mixed $value
93 | * @param string $slug
94 | * @param int $post_id
95 | *
96 | * @return int
97 | */
98 | public function load_value( $value, $slug, $post_id ) {
99 | return (int) $value;
100 | }
101 |
102 | /**
103 | * Update value before it's saved to the database.
104 | *
105 | * @param mixed $value
106 | * @param string $slug
107 | * @param int $post_id
108 | *
109 | * @return int
110 | */
111 | public function update_value( $value, $slug, $post_id ) {
112 | if ( $value instanceof WP_User ) {
113 | $value = $value->ID;
114 | }
115 |
116 | return (int) $value;
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/properties/class-papi-property.php:
--------------------------------------------------------------------------------
1 | get_option( 'value' );
16 |
17 | if ( papi_is_empty( $value ) ) {
18 | $type = papi_get_meta_type();
19 | $slug = $this->get_slug( true );
20 | $value = papi_get_field( $slug, null, $type );
21 | $post_status = get_post_status( $this->get_post_id() );
22 |
23 | if ( papi_is_empty( $value ) && ( $post_status === false || $post_status === 'auto-draft' ) ) {
24 | $value = $this->get_option( 'default' );
25 | }
26 | }
27 |
28 | if ( papi_is_empty( $value ) ) {
29 | return $this->default_value;
30 | }
31 |
32 | if ( $this->convert_type === 'string' ) {
33 | $value = papi_convert_to_string( $value );
34 | }
35 |
36 | return papi_santize_data( $value );
37 | }
38 |
39 | /**
40 | * Render property html.
41 | */
42 | public function html() {
43 | }
44 |
45 | /**
46 | * Determine if the property can be rendered or not.
47 | *
48 | * @return bool
49 | */
50 | public function can_render() {
51 | // Check if current user can view the property.
52 | if ( ! $this->current_user_can() ) {
53 | return false;
54 | }
55 |
56 | // A disabled property should not be rendered.
57 | if ( $this->disabled() ) {
58 | return false;
59 | }
60 |
61 | // Check language option, so we don't render properties on a different language.
62 | if ( $lang = $this->get_option( 'lang' ) ) {
63 | return in_array( papi_get_lang(), papi_to_array( $lang ), true );
64 | }
65 |
66 | // If no valid lang query string exists we have to override the display property.
67 | return $this->get_option( 'lang' ) === false;
68 | }
69 |
70 | /**
71 | * Render the property.
72 | */
73 | public function render() {
74 | // Bail if we can't render the property.
75 | if ( ! $this->can_render() ) {
76 | return;
77 | }
78 |
79 | // Override display with rules check.
80 | if ( $this->display() ) {
81 | $this->display = $this->render_is_allowed_by_rules();
82 | }
83 |
84 | // Render property.
85 | $this->render_row_html();
86 | }
87 |
88 | /**
89 | * Render AJAX request.
90 | */
91 | public function render_ajax_request() {
92 | papi_render_property( $this );
93 | }
94 |
95 | /**
96 | * Render the property description.
97 | */
98 | protected function render_description_html() {
99 | if ( papi_is_empty( $this->get_option( 'description' ) ) ) {
100 | return;
101 | }
102 |
103 | papi_render_html_tag( 'p', [
104 | papi_nl2br( $this->get_option( 'description' ) )
105 | ] );
106 | }
107 |
108 | /**
109 | * Output hidden input field that cointains which property is used.
110 | */
111 | protected function render_hidden_html() {
112 | $slug = $this->get_option( 'slug' );
113 |
114 | if ( substr( $slug, - 1 ) === ']' ) {
115 | $slug = substr( $slug, 0, - 1 );
116 | $slug = papi_get_property_type_key( $slug );
117 | $slug .= ']';
118 | } else {
119 | $slug = papi_get_property_type_key( $slug );
120 | }
121 |
122 | $slug = papify( $slug );
123 | $options = $this->get_options();
124 | $property_json = base64_encode( papi_maybe_json_encode( $options ) );
125 |
126 | papi_render_html_tag( 'input', [
127 | 'data-property' => strtolower( $this->get_option( 'type' ) ),
128 | 'name' => $slug,
129 | 'type' => 'hidden',
130 | 'value' => $property_json
131 | ] );
132 | }
133 |
134 | /**
135 | * Render label for the property.
136 | */
137 | protected function render_label_html() {
138 | $title = $this->get_option( 'title' );
139 |
140 | papi_render_html_tag( 'label', [
141 | 'for' => $this->html_id(),
142 | 'title' => trim( $title . ' ' . papi_property_require_text( $this->get_options() ) ),
143 | $title,
144 | papi_property_required_html( $this )
145 | ] );
146 | }
147 |
148 | /**
149 | * Render property html.
150 | */
151 | protected function render_property_html() {
152 | papi_render_html_tag( 'div', [
153 | 'class' => 'papi-before-html ' . $this->get_option( 'before_class' ),
154 | 'data-property' => $this->get_option( 'type' ),
155 | papi_maybe_get_callable_value( $this->get_option( 'before_html' ) )
156 | ] );
157 |
158 | $this->html();
159 |
160 | papi_render_html_tag( 'div', [
161 | 'class' => 'papi-after-html ' . $this->get_option( 'after_class' ),
162 | 'data-property' => $this->get_option( 'type' ),
163 | papi_maybe_get_callable_value( $this->get_option( 'after_html' ) )
164 | ] );
165 | }
166 |
167 | /**
168 | * Render the final html that is displayed in the table.
169 | */
170 | protected function render_row_html() {
171 | $display_class = $this->display() ? '' : ' papi-hide';
172 | $rules_class = papi_is_empty( $this->get_rules() ) ? '' : ' papi-rules-exists';
173 | $css_class = trim( $display_class . $rules_class );
174 | $css_class .= sprintf( ' papi-layout-%s', $this->get_option( 'layout' ) );
175 |
176 | if ( $this->get_option( 'raw' ) ) {
177 | echo sprintf( '', esc_attr( $css_class ) );
178 | $this->render_property_html();
179 | $this->render_hidden_html();
180 | $this->render_rules_json();
181 | echo '
';
182 | } else {
183 | ?>
184 |
185 | get_option( 'sidebar' ) && $this->get_option( 'layout' ) === 'horizontal' ): ?>
186 |
192 |
193 | get_option( 'sidebar' ) && $this->get_option( 'layout' ) === 'horizontal' ? '' : 'colspan="2"'; ?>>
194 | get_option( 'layout' ) === 'vertical' && $this->get_option( 'sidebar' ) ) {
197 | $this->render_label_html();
198 | $this->render_description_html();
199 | }
200 |
201 | $this->render_property_html();
202 | $this->render_hidden_html();
203 | $this->render_rules_json();
204 | ?>
205 | |
206 |
207 | get_rules();
216 |
217 | if ( empty( $rules ) ) {
218 | return;
219 | }
220 |
221 | $rules = $this->conditional->prepare_rules( $rules, $this );
222 |
223 | papi_render_html_tag( 'script', [
224 | 'data-papi-rule-source-slug' => $this->html_name(),
225 | 'data-papi-rules' => 'true',
226 | 'type' => 'application/json',
227 | papi_maybe_json_encode( $rules )
228 | ] );
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/src/query/class-papi-query.php:
--------------------------------------------------------------------------------
1 | ''
19 | ];
20 |
21 | /**
22 | * The query type.
23 | *
24 | * @var string
25 | */
26 | protected $type;
27 |
28 | /**
29 | * The query instance.
30 | *
31 | * @var WP_Term_Query|WP_Query
32 | */
33 | protected $query;
34 |
35 | /**
36 | * Query constructor.
37 | *
38 | * @param array $args
39 | * @param string $type
40 | */
41 | public function __construct( array $args = [], $type = 'post' ) {
42 | $this->type = $type === 'page' ? 'post' : $type;
43 | $this->query = $this->get_query_class();
44 | $this->args = $args;
45 | }
46 |
47 | /**
48 | * Dynamically access query properties.
49 | *
50 | * @param string $key
51 | *
52 | * @return mixed
53 | */
54 | public function __get( $key ) {
55 | switch ( $key ) {
56 | case 'posts':
57 | case 'terms':
58 | return $this->get_result();
59 | default:
60 | break;
61 | }
62 | }
63 |
64 | /**
65 | * Get first item of result.
66 | *
67 | * @return array
68 | */
69 | public function first() {
70 | $result = $this->get_result();
71 |
72 | return array_shift( $result );
73 | }
74 |
75 | /**
76 | * Parse query arguments.
77 | *
78 | * @param array $args
79 | */
80 | public function parse_args( array $args ) {
81 | $args = array_merge( $this->default_args, $args );
82 |
83 | // Since a page type has defined post types we should use them.
84 | // With a fallback on `post_type` args or `any` value.
85 | if ( $this->type === 'post' ) {
86 | $args = $this->parse_post_args( $args );
87 | } else if ( $this->type === 'term' ) {
88 | $args = $this->parse_term_args( $args );
89 | }
90 |
91 | $this->args = $args;
92 | }
93 |
94 | /**
95 | * Parse post query arguments.
96 | *
97 | * @param array $args
98 | *
99 | * @return array
100 | */
101 | protected function parse_post_args( array $args ) {
102 | if ( isset( $args['page_type'] ) ) {
103 | $args['entry_type'] = $args['page_type'];
104 |
105 | unset( $args['page_type'] );
106 | }
107 |
108 | $entry_type = papi_get_entry_type_by_id( $args['entry_type'] );
109 |
110 | if ( $entry_type instanceof Papi_Page_Type ) {
111 | $args['post_type'] = papi_to_array( $entry_type->post_type );
112 | } else {
113 | $args['post_type'] = isset( $args['post_type'] ) ? $args['post_type'] : '';
114 | }
115 |
116 | return $args;
117 | }
118 |
119 | /**
120 | * Parse term query arguments.
121 | *
122 | * @param array $args
123 | *
124 | * @return array
125 | */
126 | protected function parse_term_args( array $args ) {
127 | if ( isset( $args['taxonomy_type'] ) ) {
128 | $args['entry_type'] = $args['taxonomy_type'];
129 |
130 | unset( $args['taxonomy_type'] );
131 | }
132 |
133 | $entry_type = papi_get_entry_type_by_id( $args['entry_type'] );
134 |
135 | if ( $entry_type instanceof Papi_Taxonomy_Type ) {
136 | $args['taxonomy'] = papi_to_array( $entry_type->taxonomy );
137 | } else {
138 | $args['taxonomy'] = isset( $args['taxonomy'] ) ? $args['taxonomy'] : '';
139 | }
140 |
141 | return $args;
142 | }
143 |
144 | /**
145 | * Get query object for right query type.
146 | *
147 | * @return WP_Query|WP_Term_Query
148 | */
149 | public function get_query_class() {
150 | switch ( $this->type ) {
151 | case 'post':
152 | case 'page':
153 | return new WP_Query;
154 | case 'term':
155 | // `WP_Term_Query` was added in WordPress 4.6.
156 | if ( class_exists( 'WP_Term_Query' ) ) {
157 | return new WP_Term_Query;
158 | }
159 |
160 | break;
161 | default:
162 | break;
163 | }
164 | }
165 |
166 | /**
167 | * Get real query arguments without Papi Query specific arguments.
168 | *
169 | * @return array
170 | */
171 | public function get_query_args() {
172 | $args = $this->args;
173 |
174 | if ( empty( $args['meta_query'] ) ) {
175 | // Add new meta key/value if `meta_key` or `meta_value` is empty.
176 | if ( empty( $args['meta_key'] ) || empty( $args['meta_value'] ) ) {
177 | $args['meta_key'] = papi_get_page_type_key();
178 | $args['meta_value'] = $args['entry_type'];
179 | } else if ( papi_entry_type_exists( $args['entry_type'] ) ) {
180 | $item = [
181 | 'key' => $args['meta_key'],
182 | 'value' => $args['meta_value']
183 | ];
184 |
185 | // Add `meta_compare` if set.
186 | if ( isset( $args['meta_compare'] ) ) {
187 | $item['compare'] = $args['meta_compare'];
188 |
189 | unset( $args['meta_compare'] );
190 | }
191 |
192 | // Add new meta query item.
193 | $args['meta_query'][] = $item;
194 |
195 | // Add Papi entry/page type meta query.
196 | $args['meta_query'][] = [
197 | 'key' => papi_get_page_type_key(),
198 | 'value' => $args['entry_type']
199 | ];
200 |
201 | // Add meta query relation when two query items.
202 | if ( isset( $args['relation'] ) ) {
203 | $args['meta_query']['relation'] = $args['relation'];
204 | } else {
205 | $args['meta_query']['relation'] = 'AND';
206 | }
207 |
208 | unset( $args['meta_key'] );
209 | unset( $args['meta_value'] );
210 | }
211 | } else if ( papi_entry_type_exists( $args['entry_type'] ) ) {
212 | // Add Papi entry/page type meta query.
213 | $args['meta_query'][] = [
214 | 'key' => papi_get_page_type_key(),
215 | 'value' => $args['entry_type']
216 | ];
217 |
218 | // Add meta query relation if not set.
219 | if ( ! isset( $args['meta_query']['relation'] ) ) {
220 | $args['meta_query']['relation'] = 'AND';
221 | }
222 | }
223 |
224 | // Since the real query classes don't support
225 | // custom arguments the should be deleted.
226 | foreach ( array_keys( $this->default_args ) as $key ) {
227 | if ( isset( $args[$key] ) ) {
228 | unset( $args[$key] );
229 | }
230 | }
231 |
232 | return $args;
233 | }
234 |
235 | /**
236 | * Get result.
237 | *
238 | * Works for all query types.
239 | *
240 | * @return array
241 | */
242 | public function get_result() {
243 | if ( ! method_exists( $this->query, 'query' ) ) {
244 | return [];
245 | }
246 |
247 | $this->parse_args( $this->args );
248 |
249 | return $this->query->query( $this->get_query_args() );
250 | }
251 |
252 | /**
253 | * Get last item of result.
254 | *
255 | * @return array
256 | */
257 | public function last() {
258 | $result = $this->get_result();
259 |
260 | return array_pop( $result );
261 | }
262 | }
263 |
--------------------------------------------------------------------------------
/src/rest-api/class-papi-rest-api-post.php:
--------------------------------------------------------------------------------
1 | ID ) ) ) {
41 | return $post;
42 | }
43 |
44 | // Register all properties fields with register meta.
45 | foreach ( $page_type->get_properties() as $property ) {
46 | $property->register();
47 | }
48 |
49 | // Add filter to prepare the response for a post type.
50 | add_filter( 'rest_prepare_' . $post->post_type, [$this, 'prepare_response'] );
51 |
52 | return $post;
53 | }
54 |
55 | /**
56 | * Prepare response.
57 | *
58 | * @param WP_REST_Response $response
59 | *
60 | * @return WP_REST_Response
61 | */
62 | public function prepare_response( $response ) {
63 | if ( ! isset( $response->data['meta'] ) ) {
64 | return $response;
65 | }
66 |
67 | foreach ( $response->data['meta'] as $key => $value ) {
68 | $response->data['meta'][$key] = papi_get_field( $key, $value, 'post' );
69 | }
70 |
71 | return $response;
72 | }
73 |
74 | /**
75 | * Setup REST API fields.
76 | */
77 | public function setup_fields() {
78 | if ( ! function_exists( 'register_rest_field' ) ) {
79 | return;
80 | }
81 |
82 | $post_types = papi_get_post_types();
83 |
84 | foreach ( $post_types as $post_type ) {
85 | register_rest_field( $post_type, 'page_type', [
86 | 'get_callback' => [$this, 'get_page_type']
87 | ] );
88 | }
89 | }
90 | }
91 |
92 | new Papi_REST_API_Post;
93 |
--------------------------------------------------------------------------------
/src/rest-api/class-papi-rest-api-settings.php:
--------------------------------------------------------------------------------
1 | entries = papi_get_all_entry_types( [
27 | 'types' => 'option'
28 | ] );
29 |
30 | foreach ( $this->entries as $entry ) {
31 | foreach ( $entry->get_properties() as $property ) {
32 | $property->register( 'option' );
33 | }
34 | }
35 | }
36 |
37 | /**
38 | * Setup request after callbacks filter so it's only runs on settings endpoint.
39 | *
40 | * When the filter is added the `rest_pre_get_setting` will be removed since it's
41 | * not used to anything good.
42 | *
43 | * @param mixed $value
44 | *
45 | * @return mixed
46 | */
47 | public function pre_get_setting( $value ) {
48 | if ( ! has_filter( 'rest_request_after_callbacks', [$this, 'prepare_response'] ) ) {
49 | add_filter( 'rest_request_after_callbacks', [$this, 'prepare_response'] );
50 | remove_filter( 'rest_pre_get_setting', [$this, 'pre_get_setting'] );
51 | }
52 |
53 | return $value;
54 | }
55 |
56 | /**
57 | * Get setting value for a property.
58 | *
59 | * @param string $key
60 | * @param string $value
61 | *
62 | * @return mixed
63 | */
64 | public function get_setting( $key, $value ) {
65 | $property = null;
66 |
67 | foreach ( (array) $this->entries as $entry ) {
68 | if ( $property = $entry->get_property( $key ) ) {
69 | break;
70 | }
71 | }
72 |
73 | if ( is_null( $property ) ) {
74 | return $value;
75 | }
76 |
77 | $value = papi_get_option( $key );
78 |
79 | return $property->rest_prepare_value( $value );
80 | }
81 |
82 | /**
83 | * Prepare settings response.
84 | *
85 | * @param WP_HTTP_Response $response
86 | *
87 | * @return array
88 | */
89 | public function prepare_response( $response ) {
90 | $response = (array) $response;
91 |
92 | foreach ( $response as $key => $value ) {
93 | $setting = $this->get_setting( $key, $value );
94 |
95 | if ( $setting !== $value ) {
96 | $response[$key] = $setting;
97 | }
98 | }
99 |
100 | return $response;
101 | }
102 | }
103 |
104 | new Papi_REST_API_Settings;
105 |
--------------------------------------------------------------------------------
/src/rest-api/class-papi-rest-api.php:
--------------------------------------------------------------------------------
1 | load_files();
10 | $this->setup_actions();
11 | }
12 |
13 | /**
14 | * Load admin files that are not loaded by the autoload.
15 | */
16 | protected function load_files() {
17 | require_once __DIR__ . '/class-papi-rest-api-post.php';
18 | require_once __DIR__ . '/class-papi-rest-api-settings.php';
19 | }
20 |
21 | /**
22 | * Register REST API routes.
23 | */
24 | public function register_routes() {
25 | }
26 |
27 | /**
28 | * REST API init callback.
29 | */
30 | public function rest_api_init() {
31 | papi_get_all_entry_types();
32 | }
33 |
34 | /**
35 | * Setup actions.
36 | */
37 | protected function setup_actions() {
38 | add_action( 'rest_api_init', [$this, 'rest_api_init'] );
39 | add_action( 'rest_api_init', [$this, 'register_routes'] );
40 | }
41 | }
42 |
43 | new Papi_REST_API;
44 |
--------------------------------------------------------------------------------
/src/stores/class-papi-option-store.php:
--------------------------------------------------------------------------------
1 | id = 0;
23 | }
24 |
25 | /**
26 | * Load property from page type.
27 | *
28 | * @param string $slug
29 | * @param string $child_slug
30 | *
31 | * @return null|object
32 | */
33 | public function get_property( $slug, $child_slug = '' ) {
34 | $entry_type_id = papi_get_qs( 'page' );
35 |
36 | if ( empty( $entry_type_id ) ) {
37 | $property = null;
38 | $entry_types = papi_get_all_entry_types( [
39 | 'types' => 'option'
40 | ] );
41 |
42 | foreach ( $entry_types as $entry_type ) {
43 | if ( $property = $entry_type->get_property( $slug, $child_slug ) ) {
44 | break;
45 | }
46 | }
47 |
48 | if ( is_null( $property ) ) {
49 | return;
50 | }
51 |
52 | return $property;
53 | }
54 |
55 | $entry_type = papi_get_entry_type_by_id( $entry_type_id );
56 |
57 | if ( $entry_type instanceof Papi_Option_Type === false ) {
58 | return;
59 | }
60 |
61 | if ( $property = $entry_type->get_property( $slug, $child_slug ) ) {
62 | return $this->prepare_property( $property );
63 | }
64 | }
65 |
66 | /**
67 | * Check if it's a valid store.
68 | *
69 | * @return bool
70 | */
71 | public function valid() {
72 | return $this->id === 0;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/stores/class-papi-post-store.php:
--------------------------------------------------------------------------------
1 | id = papi_get_post_id( $id );
29 | $this->post = get_post( $this->id );
30 | $id = papi_get_page_type_id( $this->id );
31 | $this->type_class = papi_get_entry_type_by_id( $id );
32 | }
33 |
34 | /**
35 | * Get the permalink for the page.
36 | *
37 | * @return string
38 | */
39 | public function get_permalink() {
40 | return get_permalink( $this->id );
41 | }
42 |
43 | /**
44 | * Get the WordPress post object.
45 | *
46 | * @return WP_Post
47 | */
48 | public function get_post() {
49 | return $this->post;
50 | }
51 |
52 | /**
53 | * Get the post status of a page.
54 | *
55 | * @return string
56 | */
57 | public function get_status() {
58 | return get_post_status( $this->id );
59 | }
60 |
61 | /**
62 | * Load property from page type.
63 | *
64 | * @param string $slug
65 | * @param string $child_slug
66 | *
67 | * @return null|Papi_Core_Property
68 | */
69 | public function get_property( $slug, $child_slug = '' ) {
70 | $page_type_id = papi_get_page_type_id( $this->id );
71 | $page_type = papi_get_entry_type_by_id( $page_type_id );
72 |
73 | if ( $page_type instanceof Papi_Page_Type === false ) {
74 | return;
75 | }
76 |
77 | if ( $property = $page_type->get_property( $slug, $child_slug ) ) {
78 | return $this->prepare_property( $property );
79 | }
80 | }
81 |
82 | /**
83 | * Prepare load value.
84 | *
85 | * @param Papi_Core_Property $property
86 | * @param mixed $value
87 | *
88 | * @return mixed
89 | */
90 | protected function prepare_load_value( Papi_Core_Property $property, $value ) {
91 | if ( $property->overwrite ) {
92 | // Clear post cache to solve issue with cached post objects
93 | // when selecting post field.
94 | clean_post_cache( $this->id );
95 |
96 | $slug = $property->get_slug( true );
97 | $context = papi_is_admin() ? 'edit' : 'display';
98 | $value = get_post_field( $slug, $this->id, $context );
99 | }
100 |
101 | return $value;
102 | }
103 |
104 | /**
105 | * Check if the page has the post object and that it's not null.
106 | *
107 | * @return bool
108 | */
109 | public function valid() {
110 | return ! is_null( $this->post );
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/stores/class-papi-term-store.php:
--------------------------------------------------------------------------------
1 | id = papi_get_term_id( $id );
29 | $this->term = get_term( $this->id, '' );
30 | $id = papi_get_taxonomy_type_id( $this->id );
31 | $this->type_class = papi_get_entry_type_by_id( $id );
32 | }
33 |
34 | /**
35 | * Get the permalink for the term.
36 | *
37 | * @return string
38 | */
39 | public function get_permalink() {
40 | return get_term_link( $this->id );
41 | }
42 |
43 | /**
44 | * Get the WordPress term object.
45 | *
46 | * @return WP_Term
47 | */
48 | public function get_term() {
49 | return $this->term;
50 | }
51 |
52 | /**
53 | * Check if the term is a valid term object.
54 | *
55 | * @return bool
56 | */
57 | public function valid() {
58 | return $this->term instanceof WP_Term;
59 | }
60 |
61 | /**
62 | * Load property from page type.
63 | *
64 | * @param string $slug
65 | * @param string $child_slug
66 | *
67 | * @return null|Papi_Core_Property
68 | */
69 | public function get_property( $slug, $child_slug = '' ) {
70 | $taxonomy_type_id = papi_get_taxonomy_type_id( $this->id, 'term' );
71 | $taxonomy_type = papi_get_entry_type_by_id( $taxonomy_type_id );
72 |
73 | if ( $taxonomy_type instanceof Papi_Taxonomy_Type === false ) {
74 | return;
75 | }
76 |
77 | if ( $property = $taxonomy_type->get_property( $slug, $child_slug ) ) {
78 | return $this->prepare_property( $property );
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/types/class-papi-attachment-type.php:
--------------------------------------------------------------------------------
1 | post_type[0];
31 | }
32 |
33 | /**
34 | * Setup filters.
35 | */
36 | protected function setup_filters() {
37 | // Don't add any filters on post.php page.
38 | if ( ! isset( $_GET['post'] ) ) {
39 | add_filter( 'attachment_fields_to_edit', [$this, 'edit_attachment'], 10, 2 );
40 | add_filter( 'attachment_fields_to_save', [$this, 'save_attachment'], 10 );
41 | }
42 | }
43 |
44 | /**
45 | * Add attachment fields.
46 | *
47 | * @param array $form_fields
48 | * @param WP_Post $post
49 | *
50 | * @return array
51 | */
52 | public function edit_attachment( $form_fields, $post ) {
53 | foreach ( $this->get_boxes() as $box ) {
54 | if ( ! empty( $box->title ) ) {
55 | $form_fields['papi-media-title-' . uniqid()] = [
56 | 'label' => '',
57 | 'input' => 'html',
58 | 'html' => ''
59 | ];
60 | }
61 |
62 | foreach ( $box->properties as $prop ) {
63 | // Raw output is required.
64 | $prop->raw = true;
65 |
66 | // Set post id to the property.
67 | $prop->set_post_id( $post->ID );
68 |
69 | // Add property to form fields.
70 | $form_fields[$prop->get_slug()] = [
71 | 'label' => $prop->title,
72 | 'input' => 'html',
73 | 'helps' => $prop->description,
74 | 'html' => papi_maybe_get_callable_value(
75 | 'papi_render_property',
76 | $prop
77 | )
78 | ];
79 | }
80 | }
81 |
82 | // Add nonce field.
83 | $form_fields['papi_meta_nonce'] = [
84 | 'label' => '',
85 | 'input' => 'html',
86 | 'html' => sprintf(
87 | '',
88 | wp_create_nonce( 'papi_save_data' )
89 | )
90 | ];
91 |
92 | return $form_fields;
93 | }
94 |
95 | /**
96 | * Save attachment post data.
97 | *
98 | * @param array $post
99 | *
100 | * @return array
101 | */
102 | public function save_attachment( $post ) {
103 | update_post_meta( $post['ID'], papi_get_page_type_key(), $this->get_id() );
104 |
105 | $handler = new Papi_Admin_Meta_Handler();
106 | $handler->save_meta_boxes( $post['ID'], $post );
107 |
108 | return $post;
109 | }
110 |
111 | /**
112 | * Check if the entry type is a singleton.
113 | *
114 | * @return bool
115 | */
116 | public function singleton() {
117 | $key = sprintf( 'entry_type_id.post_type.%s', $this->get_post_type() );
118 |
119 | if ( papi()->exists( $key ) ) {
120 | return true;
121 | }
122 |
123 | papi()->singleton( $key, $this->get_id() );
124 |
125 | return false;
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/types/class-papi-front-page-type.php:
--------------------------------------------------------------------------------
1 |
43 |
44 |
name ); ?>
45 | description ) ); // wpcs: xss ok ?>
46 |
62 |
63 | taxonomy, true );
56 | }
57 |
58 | /**
59 | * Should the Taxonomy Type be displayed in WordPress admin or not?
60 | *
61 | * @param string $taxonomy
62 | *
63 | * @return bool
64 | */
65 | public function display( $taxonomy ) {
66 | return true;
67 | }
68 |
69 | /**
70 | * Get labels that should be changed
71 | * when using `fill_labels` option.
72 | *
73 | * @return array
74 | */
75 | public function get_labels() {
76 | if ( ! $this->fill_labels ) {
77 | return $this->labels;
78 | }
79 |
80 | return array_merge( $this->labels, [
81 | 'add_new_item' => sprintf( '%s %s', __( 'Add New', 'papi' ), $this->name ),
82 | 'edit_item' => sprintf( '%s %s', __( 'Edit', 'papi' ), $this->name ),
83 | 'view_item' => sprintf( '%s %s', __( 'View', 'papi' ), $this->name )
84 | ] );
85 | }
86 |
87 | /**
88 | * Setup actions.
89 | */
90 | protected function setup_actions() {
91 | foreach ( papi_to_array( $this->taxonomy ) as $taxonomy ) {
92 | if ( is_string( $taxonomy ) && taxonomy_exists( $taxonomy ) ) {
93 | add_action( $taxonomy . '_edit_form', [$this, 'edit_form'] );
94 | }
95 | }
96 | }
97 |
98 | /**
99 | * Render term edit form.
100 | */
101 | public function edit_form() {
102 | ?>
103 |
104 |
105 |
106 |
107 |
108 | boxes as $box ) {
110 | do_meta_boxes(
111 | $box->id,
112 | 'normal',
113 | null
114 | );
115 | }
116 | ?>
117 |
118 |
119 | taxonomy = papi_to_array( $this->taxonomy );
128 | }
129 | }
130 |
--------------------------------------------------------------------------------