├── .editorconfig ├── .github └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .phpcs.xml.dist ├── .phpunit.xml.dist ├── .wp-env.json ├── classes ├── class.config.php ├── class.rest-api.php ├── class.scf.php ├── controller │ ├── class.controller-base.php │ ├── class.editor.php │ ├── class.option.php │ ├── class.profile.php │ ├── class.settings.php │ └── class.taxonomy.php ├── fields │ ├── class.field-boolean.php │ ├── class.field-check.php │ ├── class.field-colorpicker.php │ ├── class.field-datepicker.php │ ├── class.field-datetime-picker.php │ ├── class.field-file.php │ ├── class.field-image.php │ ├── class.field-message.php │ ├── class.field-radio.php │ ├── class.field-related-posts.php │ ├── class.field-related-terms.php │ ├── class.field-select.php │ ├── class.field-text.php │ ├── class.field-textarea.php │ └── class.field-wysiwyg.php └── models │ ├── class.abstract-field-base.php │ ├── class.ajax.php │ ├── class.cache.php │ ├── class.group.php │ ├── class.meta.php │ ├── class.options-page.php │ ├── class.revisions.php │ ├── class.setting.php │ └── class.yoast-seo-analysis.php ├── composer.json ├── composer.lock ├── css ├── editor.css ├── option.css ├── profile.css ├── settings.css ├── taxonomy.css └── wysiwyg.css ├── images └── handle.png ├── js ├── editor-colorpicker.js ├── editor-datepicker.js ├── editor-relation-common.js ├── editor-relation-post-types.js ├── editor-relation-taxonomies.js ├── editor-wysiwyg.js ├── editor.js ├── settings-colorpicker.js ├── settings-datepicker.js ├── settings-datetime-picker.js ├── settings.js └── yoast-seo-analysis.js ├── languages ├── smart-custom-fields-ja.mo ├── smart-custom-fields-ja.po ├── smart-custom-fields-pt_BR.mo ├── smart-custom-fields-pt_BR.po └── smart-custom-fields.pot ├── libs ├── iosCheckbox │ ├── README.md │ ├── iosCheckbox.css │ ├── iosCheckbox.js │ ├── iosCheckbox.min.css │ └── iosCheckbox.min.js └── selectivity-3.1.0 │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── selectivity-jquery.css │ ├── selectivity-jquery.js │ ├── selectivity-jquery.min.css │ └── selectivity-jquery.min.js ├── package-lock.json ├── package.json ├── readme.txt ├── smart-custom-fields.php └── tests ├── bootstrap.php ├── test-scf.php ├── test-smart-custom-fields-ajax.php ├── test-smart-custom-fields-cache.php ├── test-smart-custom-fields-controller-base.php ├── test-smart-custom-fields-meta.php ├── test-smart-custom-fields-revision.php └── test-smart-custom-fields.php /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | # WordPress Coding Standards 5 | # https://make.wordpress.org/core/handbook/coding-standards/ 6 | 7 | root = true 8 | 9 | [*] 10 | charset = utf-8 11 | end_of_line = lf 12 | insert_final_newline = true 13 | trim_trailing_whitespace = true 14 | indent_style = tab 15 | 16 | [*.yml] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | paths-ignore: 5 | - '**.md' 6 | push: 7 | branches: 8 | - '**' 9 | tags: 10 | - "!*" 11 | paths-ignore: 12 | - '**.md' 13 | 14 | jobs: 15 | test: 16 | name: Test 17 | 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - name: Cache node modules 24 | uses: actions/cache@v4 25 | env: 26 | cache-name: cache-node-modules 27 | with: 28 | # npm cache files are stored in `~/.npm` on Linux/macOS 29 | path: ~/.npm 30 | key: ${{ runner.os }}-node-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} 31 | restore-keys: | 32 | ${{ runner.os }}-node-${{ env.cache-name }}- 33 | ${{ runner.os }}-node- 34 | ${{ runner.os }}- 35 | 36 | - name: Use Node.js 37 | uses: actions/setup-node@v4 38 | with: 39 | node-version-file: 'package.json' 40 | 41 | - name: Npm install 42 | run: npm ci 43 | 44 | - name: Get Composer Cache Directory 45 | id: composer-cache 46 | run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT 47 | 48 | - name: Cache vendor 49 | uses: actions/cache@v4 50 | with: 51 | path: ${{ steps.composer-cache.outputs.dir }} 52 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} 53 | restore-keys: | 54 | ${{ runner.os }}-composer-${{ env.cache-name }}- 55 | ${{ runner.os }}-composer- 56 | ${{ runner.os }}- 57 | 58 | - name: Composer install 59 | run: composer install 60 | 61 | - name: Running the tests 62 | run: npm run test 63 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - '[0-9]+.[0-9]+.[0-9]*' 5 | 6 | name: Upload Release Asset 7 | 8 | jobs: 9 | build: 10 | name: Upload Release Asset 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: Cache node modules 18 | uses: actions/cache@v4 19 | env: 20 | cache-name: cache-node-modules 21 | with: 22 | # npm cache files are stored in `~/.npm` on Linux/macOS 23 | path: ~/.npm 24 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} 25 | restore-keys: | 26 | ${{ runner.os }}-build-${{ env.cache-name }}- 27 | ${{ runner.os }}-build- 28 | ${{ runner.os }}- 29 | 30 | - name: Use Node.js 31 | uses: actions/setup-node@v4 32 | with: 33 | node-version-file: 'package.json' 34 | 35 | - name: Npm install 36 | run: npm ci 37 | 38 | - name: Get Composer Cache Directory 39 | id: composer-cache 40 | run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT 41 | 42 | - name: Cache vendor 43 | uses: actions/cache@v4 44 | with: 45 | path: ${{ steps.composer-cache.outputs.dir }} 46 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} 47 | restore-keys: | 48 | ${{ runner.os }}-composer-${{ env.cache-name }}- 49 | ${{ runner.os }}-composer- 50 | ${{ runner.os }}- 51 | 52 | - name: Composer install 53 | run: composer install 54 | 55 | - name: Build project 56 | run: npm run zip 57 | 58 | - name: Create Release 59 | id: create_release 60 | uses: actions/create-release@v1 61 | env: 62 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 63 | with: 64 | tag_name: ${{ github.ref }} 65 | release_name: ${{ github.ref }} 66 | draft: true 67 | prerelease: false 68 | 69 | - name: Upload Release Asset 70 | id: upload-release-asset 71 | uses: actions/upload-release-asset@v1 72 | env: 73 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 74 | with: 75 | upload_url: ${{ steps.create_release.outputs.upload_url }} 76 | asset_path: ./smart-custom-fields.zip 77 | asset_name: smart-custom-fields.zip 78 | asset_content_type: application/zip 79 | 80 | - name: Upload to github release 81 | uses: eregon/publish-release@v1 82 | env: 83 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 84 | with: 85 | release_id: ${{ steps.create_release.outputs.id }} 86 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | node_modules/ 3 | .idea/ 4 | .vscode/ 5 | .DS_Store 6 | .wp-env.override.json 7 | /.export/* 8 | smart-custom-fields/ 9 | smart-custom-fields.zip 10 | .phpunit.result.cache 11 | -------------------------------------------------------------------------------- /.phpcs.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | Apply WordPress Coding Standards to all files 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | *\.php 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | * 59 | 60 | 61 | * 62 | 63 | 64 | * 65 | 66 | 67 | * 68 | 69 | 70 | * 71 | 72 | 73 | * 74 | 75 | 76 | * 77 | 78 | 79 | * 80 | 81 | 82 | * 83 | 84 | 85 | * 86 | 87 | 88 | * 89 | 90 | 91 | * 92 | 93 | 94 | * 95 | 96 | 97 | * 98 | 99 | 100 | * 101 | 102 | 103 | 104 | 105 | . 106 | /vendor/* 107 | /node_modules/* 108 | /.export/* 109 | /bin/* 110 | /dist/* 111 | /languages/* 112 | 113 | -------------------------------------------------------------------------------- /.phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | ./tests/ 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.wp-env.json: -------------------------------------------------------------------------------- 1 | { 2 | "core": null, 3 | "plugins": [ "." ], 4 | "config": { 5 | "WP_DEBUG": true 6 | }, 7 | "mappings": { 8 | ".export": "./.export" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /classes/class.config.php: -------------------------------------------------------------------------------- 1 | 'GET', 36 | 'callback' => array( $this, 'get_all_posts' ), 37 | 'permission_callback' => function () { 38 | return current_user_can( 'edit_posts' ); 39 | }, 40 | ) 41 | ); 42 | } 43 | 44 | /** 45 | * Get all posts and pages 46 | */ 47 | public function get_all_posts() { 48 | $all_posts = get_posts( 49 | array( 50 | 'post_type' => $this->get_post_type(), 51 | 'post_status' => 'publish', 52 | 'orderby' => 'date', 53 | 'order' => 'ASC', 54 | 'posts_per_page' => -1, // all posts 55 | ) 56 | ); 57 | 58 | if ( $all_posts ) { 59 | $source = array(); 60 | 61 | foreach ( $all_posts as $k => $post ) { 62 | $source[ $k ]['id'] = $post->ID; 63 | $source[ $k ]['text'] = $post->ID . ' - ' . $post->post_title; 64 | } 65 | } 66 | 67 | return $source; 68 | } 69 | 70 | /** 71 | * Get posts type. 72 | */ 73 | public function get_post_type() { 74 | $post_type = $this->post_type; 75 | return apply_filters( SCF_Config::PREFIX . 'rest_api_post_type', $post_type ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /classes/controller/class.editor.php: -------------------------------------------------------------------------------- 1 | get_id(), 33 | $setting->get_title(), 34 | array( $this, 'display_meta_box' ), 35 | $post_type, 36 | 'normal', 37 | 'default', 38 | $setting->get_groups() 39 | ); 40 | } 41 | } 42 | 43 | /** 44 | * Saving meta data from custom fields in post edit page. 45 | * 46 | * @param int $post_id Post id. 47 | */ 48 | public function save_post( $post_id ) { 49 | if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { 50 | return; 51 | } 52 | 53 | if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) { 54 | return; 55 | } 56 | 57 | if ( ! filter_input( INPUT_POST, SCF_Config::NAME, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ) ) { 58 | return; 59 | } 60 | 61 | $this->save( filter_input_array( INPUT_POST ), get_post( $post_id ) ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /classes/controller/class.option.php: -------------------------------------------------------------------------------- 1 | 50 |
51 | 52 | get_groups(); ?> 53 | 54 | 55 | 56 | 57 | 58 |
get_title() ); ?>display_meta_box( $option, $callback_args ); ?>
59 | 60 |

61 | 62 |

63 |
64 | save( filter_input_array( INPUT_POST ), $option ); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /classes/controller/class.profile.php: -------------------------------------------------------------------------------- 1 | %s', esc_html__( 'Custom Fields', 'smart-custom-fields' ) ); 47 | $settings = SCF::get_settings( $user ); 48 | $callback_args = array(); 49 | foreach ( $settings as $setting ) { 50 | $callback_args['args'] = $setting->get_groups(); 51 | ?> 52 | 53 | 54 | 55 | 56 | 57 |
get_title() ); ?>display_meta_box( $user, $callback_args ); ?>
58 | save( filter_input_array( INPUT_POST ), get_userdata( $user_id ) ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /classes/controller/class.taxonomy.php: -------------------------------------------------------------------------------- 1 | get_groups(); 54 | ?> 55 | 56 | 57 | 58 | 59 | 60 |
get_title() ); ?>display_meta_box( $term, $callback_args ); ?>
61 | save( filter_input_array( INPUT_POST ), $term ); 82 | } 83 | 84 | /** 85 | * Delete meta data. 86 | * 87 | * @param int $term_id Term ID. 88 | * @param int $term_taxonomy_id Term taxonomy ID. 89 | * @param string $taxonomy Taxonomy slug. 90 | * @param object $deleted_term Copy of the already-deleted term. 91 | */ 92 | public function delete( $term_id, $term_taxonomy_id, $taxonomy, $deleted_term ) { 93 | $meta = new Smart_Custom_Fields_Meta( $deleted_term ); 94 | $meta->delete(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /classes/fields/class.field-boolean.php: -------------------------------------------------------------------------------- 1 | 'boolean', 22 | 'display-name' => __( 'Boolean', 'smart-custom-fields' ), 23 | 'optgroup' => 'basic-fields', 24 | ); 25 | } 26 | 27 | /** 28 | * Set the non required items. 29 | * 30 | * @return array 31 | */ 32 | protected function options() { 33 | return array( 34 | 'default' => 0, 35 | 'instruction' => '', 36 | 'notes' => '', 37 | 'true_label' => __( 'Yes', 'smart-custom-fields' ), 38 | 'false_label' => __( 'No', 'smart-custom-fields' ), 39 | ); 40 | } 41 | 42 | /** 43 | * Getting the field. 44 | * 45 | * @param int $index Field index. 46 | * @param int $value The value. 47 | * @return string 48 | */ 49 | public function get_field( $index, $value ) { 50 | $name = $this->get_field_name_in_editor( $index ); 51 | $disabled = $this->get_disable_attribute( $index ); 52 | $value = ( true === $value || 1 === $value || '1' === $value ) ? 1 : 0; 53 | 54 | $true = sprintf( 55 | '', 56 | esc_attr( $name ), 57 | checked( 1, $value, false ), 58 | disabled( true, $disabled, false ), 59 | wp_kses_post( $this->get( 'true_label' ) ) 60 | ); 61 | 62 | $false = sprintf( 63 | '', 64 | esc_attr( $name ), 65 | checked( 0, $value, false ), 66 | disabled( true, $disabled, false ), 67 | wp_kses_post( $this->get( 'false_label' ) ) 68 | ); 69 | 70 | return $true . $false; 71 | } 72 | 73 | /** 74 | * Displaying the option fields in custom field settings page. 75 | * 76 | * @param int $group_key Group key. 77 | * @param int $field_key Field key. 78 | */ 79 | public function display_field_options( $group_key, $field_key ) { 80 | $this->display_label_option( $group_key, $field_key ); 81 | $this->display_name_option( $group_key, $field_key ); 82 | ?> 83 | 84 | 85 | 86 |
87 | 88 |   96 | 104 | 105 |
106 | 107 | 108 | 109 | 110 | 111 | 116 | 117 | 118 | 119 | 120 | 121 | 126 | 127 | 128 | 129 | 130 | 131 | 133 | 134 | 135 | 136 | 137 | 138 | 143 | 144 | 145 | get_attribute( 'type' ) ) { 157 | if ( is_array( $value ) ) { 158 | foreach ( $value as $key => $val ) { 159 | $value[ $key ] = ! ! $val; 160 | } 161 | } else { 162 | $value = ! ! $value; 163 | } 164 | } 165 | return $value; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /classes/fields/class.field-check.php: -------------------------------------------------------------------------------- 1 | 'check', 21 | 'display-name' => __( 'Check', 'smart-custom-fields' ), 22 | 'optgroup' => 'select-fields', 23 | 'allow-multiple-data' => true, 24 | ); 25 | } 26 | 27 | /** 28 | * Set the non required items. 29 | * 30 | * @return array 31 | */ 32 | protected function options() { 33 | return array( 34 | 'choices' => '', 35 | 'check_direction' => 'horizontal', // or vertical 36 | 'default' => '', 37 | 'instruction' => '', 38 | 'notes' => '', 39 | ); 40 | } 41 | 42 | /** 43 | * Getting the field. 44 | * 45 | * @param int $index Field index. 46 | * @param array $value The value. 47 | * @return string 48 | */ 49 | public function get_field( $index, $value ) { 50 | $name = $this->get_field_name_in_editor( $index ); 51 | $disabled = $this->get_disable_attribute( $index ); 52 | $choices = SCF::choices_eol_to_array( $this->get( 'choices' ) ); 53 | $direction = $this->get( 'check_direction' ); 54 | 55 | $form_field = sprintf( 56 | '', 57 | esc_attr( $name ), 58 | disabled( true, $disabled, false ) 59 | ); 60 | foreach ( $choices as $key => $choice ) { 61 | $choice = trim( $choice ); 62 | if ( ! SCF::is_assoc( $choices ) ) { 63 | $key = $choice; 64 | } 65 | $form_field .= sprintf( 66 | '', 67 | esc_attr( SCF_Config::PREFIX . 'item-' . $direction ), 68 | esc_attr( $name . '[]' ), 69 | esc_attr( $key ), 70 | checked( true, is_array( $value ) && in_array( $key, $value, true ), false ), 71 | disabled( true, $disabled, false ), 72 | esc_html( $choice ) 73 | ); 74 | } 75 | return $form_field; 76 | } 77 | 78 | /** 79 | * Displaying the option fields in custom field settings page. 80 | * 81 | * @param int $group_key Group key. 82 | * @param int $field_key Field key. 83 | */ 84 | public function display_field_options( $group_key, $field_key ) { 85 | $this->display_label_option( $group_key, $field_key ); 86 | $this->display_name_option( $group_key, $field_key ); 87 | ?> 88 | 89 | 90 | 91 | 95 | value', 'smart-custom-fields' ); ?> 96 | 97 | 98 | 99 | 100 | 101 | __( 'horizontal', 'smart-custom-fields' ), 104 | 'vertical' => __( 'vertical', 'smart-custom-fields' ), 105 | ); 106 | foreach ( $directions as $key => $value ) { 107 | printf( 108 | '   ', 109 | esc_attr( $this->get_field_name_in_setting( $group_key, $field_key, 'check_direction' ) ), 110 | esc_attr( $key ), 111 | checked( $this->get( 'check_direction' ), $key, false ), 112 | esc_html( $value ) 113 | ); 114 | } 115 | ?> 116 | 117 | 118 | 119 | 120 | 121 | 125 | 126 | 127 | 128 | 129 | 130 | 132 | 133 | 134 | 135 | 136 | 137 | 142 | 143 | 144 | 'colorpicker', 29 | 'display-name' => __( 'Color picker', 'smart-custom-fields' ), 30 | 'optgroup' => 'other-fields', 31 | ); 32 | } 33 | 34 | /** 35 | * Set the non required items. 36 | * 37 | * @return array 38 | */ 39 | protected function options() { 40 | return array( 41 | 'default' => '', 42 | 'instruction' => '', 43 | 'notes' => '', 44 | ); 45 | } 46 | 47 | /** 48 | * Loading resources for editor. 49 | */ 50 | public function editor_enqueue_scripts() { 51 | wp_enqueue_style( 'wp-color-picker' ); 52 | 53 | wp_enqueue_script( 54 | SCF_Config::PREFIX . 'editor-colorpicker', 55 | SMART_CUSTOM_FIELDS_URL . '/js/editor-colorpicker.js', 56 | array( 'jquery', 'wp-color-picker' ), 57 | filemtime( SMART_CUSTOM_FIELDS_PATH . '/js/editor-colorpicker.js' ), 58 | true 59 | ); 60 | } 61 | 62 | /** 63 | * Loading resources for editor for custom field settings page. 64 | */ 65 | public function settings_enqueue_scripts() { 66 | wp_enqueue_style( 'wp-color-picker' ); 67 | 68 | wp_enqueue_script( 69 | SCF_Config::PREFIX . 'settings-colorpicker', 70 | SMART_CUSTOM_FIELDS_URL . '/js/settings-colorpicker.js', 71 | array( 'jquery', 'wp-color-picker' ), 72 | filemtime( SMART_CUSTOM_FIELDS_PATH . '/js/settings-colorpicker.js' ), 73 | true 74 | ); 75 | } 76 | 77 | /** 78 | * Getting the field. 79 | * 80 | * @param int $index Field index. 81 | * @param string $value The value. 82 | * @return string 83 | */ 84 | public function get_field( $index, $value ) { 85 | $name = $this->get_field_name_in_editor( $index ); 86 | $disabled = $this->get_disable_attribute( $index ); 87 | return sprintf( 88 | '', 89 | esc_attr( $name ), 90 | esc_attr( $value ), 91 | esc_attr( SCF_Config::PREFIX . 'colorpicker' ), 92 | disabled( true, $disabled, false ) 93 | ); 94 | } 95 | 96 | /** 97 | * Displaying the option fields in custom field settings page. 98 | * 99 | * @param int $group_key Group key. 100 | * @param int $field_key Field key. 101 | */ 102 | public function display_field_options( $group_key, $field_key ) { 103 | $this->display_label_option( $group_key, $field_key ); 104 | $this->display_name_option( $group_key, $field_key ); 105 | ?> 106 | 107 | 108 | 109 | 113 | 114 | 115 | 116 | 117 | 118 | 120 | 121 | 122 | 123 | 124 | 125 | 130 | 131 | 132 | 'datepicker', 29 | 'display-name' => __( 'Date picker', 'smart-custom-fields' ), 30 | 'optgroup' => 'other-fields', 31 | ); 32 | } 33 | 34 | /** 35 | * Set the non required items. 36 | * 37 | * @return array 38 | */ 39 | protected function options() { 40 | return array( 41 | 'date_format' => '', 42 | 'max_date' => '', 43 | 'min_date' => '', 44 | 'default' => '', 45 | 'instruction' => '', 46 | 'notes' => '', 47 | ); 48 | } 49 | 50 | /** 51 | * Loading resources for editor. 52 | */ 53 | public function editor_enqueue_scripts() { 54 | global $wp_scripts; 55 | $ui = $wp_scripts->query( 'jquery-ui-core' ); 56 | wp_enqueue_style( 57 | 'jquery.ui', 58 | '//ajax.googleapis.com/ajax/libs/jqueryui/' . $ui->ver . '/themes/smoothness/jquery-ui.min.css', 59 | array(), 60 | $ui->ver 61 | ); 62 | wp_enqueue_script( 'jquery-ui-datepicker' ); 63 | wp_enqueue_script( 64 | SCF_Config::PREFIX . 'editor-datepicker', 65 | SMART_CUSTOM_FIELDS_URL . '/js/editor-datepicker.js', 66 | array( 'jquery', 'jquery-ui-datepicker' ), 67 | filemtime( SMART_CUSTOM_FIELDS_PATH . '/js/editor-datepicker.js' ), 68 | true 69 | ); 70 | } 71 | 72 | /** 73 | * Loading resources for editor for custom field settings page. 74 | */ 75 | public function settings_enqueue_scripts() { 76 | global $wp_scripts; 77 | $ui = $wp_scripts->query( 'jquery-ui-core' ); 78 | 79 | wp_enqueue_style( 80 | 'jquery.ui', 81 | '//ajax.googleapis.com/ajax/libs/jqueryui/' . $ui->ver . '/themes/smoothness/jquery-ui.min.css', 82 | array(), 83 | $ui->ver 84 | ); 85 | 86 | wp_enqueue_script( 'jquery-ui-datepicker' ); 87 | 88 | wp_enqueue_script( 89 | SCF_Config::PREFIX . 'settings-datepicker', 90 | SMART_CUSTOM_FIELDS_URL . '/js/settings-datepicker.js', 91 | array( 'jquery', 'jquery-ui-datepicker' ), 92 | filemtime( SMART_CUSTOM_FIELDS_PATH . '/js/settings-datepicker.js' ), 93 | true 94 | ); 95 | } 96 | 97 | /** 98 | * Getting the field. 99 | * 100 | * @param int $index Field index. 101 | * @param string $value The value. 102 | * @return string 103 | */ 104 | public function get_field( $index, $value ) { 105 | $name = $this->get_field_name_in_editor( $index ); 106 | $disabled = $this->get_disable_attribute( $index ); 107 | $data_js = $this->get_data_js(); 108 | 109 | return sprintf( 110 | '', 111 | esc_attr( $name ), 112 | esc_attr( $value ), 113 | esc_attr( SCF_Config::PREFIX . 'datepicker' ), 114 | disabled( true, $disabled, false ), 115 | esc_attr( $data_js ) 116 | ); 117 | } 118 | 119 | /** 120 | * Displaying the option fields in custom field settings page. 121 | * 122 | * @param int $group_key Group key. 123 | * @param int $field_key Field key. 124 | */ 125 | public function display_field_options( $group_key, $field_key ) { 126 | $this->display_label_option( $group_key, $field_key ); 127 | $this->display_name_option( $group_key, $field_key ); 128 | ?> 129 | 130 | 131 | 132 | 137 | 138 | 139 | 140 | 141 | 142 |
147 | 148 | 149 | , %2$s: 152 | esc_html__( 'Prease see %1$sdateFormat%1$s', 'smart-custom-fields' ), 153 | '', 154 | '' 155 | ); 156 | ?> 157 | 158 | 159 | 160 | 161 | 162 | 163 |
168 | 169 | 170 | , %2$s: 173 | esc_html__( 'Prease see %1$smaxData%2$s', 'smart-custom-fields' ), 174 | '', 175 | '' 176 | ); 177 | ?> 178 | 179 | 180 | 181 | 182 | 183 | 184 |
189 | 190 | 191 | , %2$s: 194 | esc_html__( 'Prease see %1$sminData%2$s', 'smart-custom-fields' ), 195 | '', 196 | '' 197 | ); 198 | ?> 199 | 200 | 201 | 202 | 203 | 204 | 205 | 207 | 208 | 209 | 210 | 211 | 212 | 217 | 218 | 219 | true, 230 | 'changeYear' => true, 231 | 'changeMonth' => true, 232 | ); 233 | 234 | // If locale is Japanese, change in Japanese notation 235 | if ( get_locale() === 'ja' ) { 236 | $js = array_merge( 237 | $js, 238 | array( 239 | 'yearSuffix' => '年', 240 | 'dateFormat' => 'yy-mm-dd', 241 | 'dayNames' => array( 242 | '日曜日', 243 | '月曜日', 244 | '火曜日', 245 | '水曜日', 246 | '木曜日', 247 | '金曜日', 248 | '土曜日', 249 | ), 250 | 'dayNamesMin' => array( 251 | '日', 252 | '月', 253 | '火', 254 | '水', 255 | '木', 256 | '金', 257 | '土', 258 | ), 259 | 'dayNamesShort' => array( 260 | '日曜', 261 | '月曜', 262 | '火曜', 263 | '水曜', 264 | '木曜', 265 | '金曜', 266 | '土曜', 267 | ), 268 | 'monthNames' => array( 269 | '1月', 270 | '2月', 271 | '3月', 272 | '4月', 273 | '5月', 274 | '6月', 275 | '7月', 276 | '8月', 277 | '9月', 278 | '10月', 279 | '11月', 280 | '12月', 281 | ), 282 | 'monthNamesShort' => array( 283 | '1月', 284 | '2月', 285 | '3月', 286 | '4月', 287 | '5月', 288 | '6月', 289 | '7月', 290 | '8月', 291 | '9月', 292 | '10月', 293 | '11月', 294 | '12月', 295 | ), 296 | ) 297 | ); 298 | } 299 | 300 | if ( $this->get( 'date_format' ) ) { 301 | $js['dateFormat'] = $this->get( 'date_format' ); 302 | } 303 | 304 | if ( $this->get( 'max_date' ) ) { 305 | $js['maxDate'] = $this->get( 'max_date' ); 306 | } 307 | 308 | if ( $this->get( 'min_date' ) ) { 309 | $js['minDate'] = $this->get( 'min_date' ); 310 | } 311 | 312 | return wp_json_encode( $js ); 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /classes/fields/class.field-file.php: -------------------------------------------------------------------------------- 1 | 'file', 21 | 'display-name' => __( 'File', 'smart-custom-fields' ), 22 | 'optgroup' => 'content-fields', 23 | ); 24 | } 25 | 26 | /** 27 | * Set the non required items. 28 | * 29 | * @return array 30 | */ 31 | protected function options() { 32 | return array( 33 | 'instruction' => '', 34 | 'notes' => '', 35 | ); 36 | } 37 | 38 | /** 39 | * Getting the field. 40 | * 41 | * @param int $index Field index. 42 | * @param string $value The value. 43 | * @return string 44 | */ 45 | public function get_field( $index, $value ) { 46 | $name = $this->get_field_name_in_editor( $index ); 47 | $disabled = $this->get_disable_attribute( $index ); 48 | 49 | $btn_remove = sprintf( 50 | '%s', 51 | esc_html__( 'Delete', 'smart-custom-fields' ) 52 | ); 53 | 54 | $hide_class = 'hide'; 55 | $image = $btn_remove; 56 | $image_src = null; 57 | $image_alt = ''; 58 | if ( $value ) { 59 | // Usually, $value is attachment ID. 60 | // If a customized, for example, $value is not an ID, 61 | // Regarded the $value is file URL. 62 | if ( preg_match( '/^\d+$/', $value ) ) { 63 | $image_src = wp_get_attachment_image_src( $value, 'thumbnail', true ); 64 | $image_alt = get_the_title( $value ); 65 | if ( is_array( $image_src ) && isset( $image_src[0] ) ) { 66 | $image_src = $image_src[0]; 67 | } 68 | } else { 69 | $image_url = $value; 70 | $path = str_replace( home_url(), '', $value ); 71 | $image_path = ABSPATH . untrailingslashit( $path ); 72 | if ( file_exists( $image_path ) ) { 73 | $wp_check_filetype = wp_check_filetype( $image_path ); 74 | if ( ! empty( $wp_check_filetype['type'] ) ) { 75 | $image_src = $image_url; 76 | } 77 | } 78 | } 79 | 80 | if ( $image_src && ! is_array( $image_src ) ) { 81 | $filename = wp_basename( get_attached_file( $value ) ); 82 | $image = sprintf( 83 | '%s%s%s', 84 | wp_get_attachment_url( $value ), 85 | esc_url( $image_src ), 86 | $image_alt, 87 | esc_attr( $filename ), 88 | $btn_remove 89 | ); 90 | $hide_class = ''; 91 | } 92 | } 93 | 94 | return sprintf( 95 | '%s
96 | %s 97 | ', 98 | esc_html__( 'File Select', 'smart-custom-fields' ), 99 | esc_attr( SCF_Config::PREFIX . 'upload-file' ), 100 | esc_attr( $hide_class ), 101 | wp_kses_post( $image ), 102 | esc_attr( $name ), 103 | esc_attr( $value ), 104 | disabled( true, $disabled, false ) 105 | ); 106 | } 107 | 108 | /** 109 | * Displaying the option fields in custom field settings page. 110 | * 111 | * @param int $group_key Group key. 112 | * @param int $field_key Field key. 113 | */ 114 | public function display_field_options( $group_key, $field_key ) { 115 | $this->display_label_option( $group_key, $field_key ); 116 | $this->display_name_option( $group_key, $field_key ); 117 | ?> 118 | 119 | 120 | 121 | 123 | 124 | 125 | 126 | 127 | 128 | 133 | 134 | 135 | 'image', 21 | 'display-name' => __( 'Image', 'smart-custom-fields' ), 22 | 'optgroup' => 'content-fields', 23 | ); 24 | } 25 | 26 | /** 27 | * Set the non required items. 28 | * 29 | * @return array 30 | */ 31 | protected function options() { 32 | return array( 33 | 'instruction' => '', 34 | 'notes' => '', 35 | 'size' => 'full', 36 | ); 37 | } 38 | 39 | /** 40 | * Getting the field. 41 | * 42 | * @param int $index Field index. 43 | * @param string $value The value. 44 | * @return string 45 | */ 46 | public function get_field( $index, $value ) { 47 | $name = $this->get_field_name_in_editor( $index ); 48 | $disabled = $this->get_disable_attribute( $index ); 49 | 50 | $btn_remove = sprintf( 51 | '%s', 52 | esc_html__( 'Delete', 'smart-custom-fields' ) 53 | ); 54 | 55 | $hide_class = 'hide'; 56 | $image = $btn_remove; 57 | $image_src = null; 58 | $image_alt = ''; 59 | if ( $value ) { 60 | // Usually, $value is attachment ID. 61 | // If a customized, for example, $value is not an ID, 62 | // Regarded the $value is file URL. 63 | if ( preg_match( '/^\d+$/', $value ) ) { 64 | $image_src = wp_get_attachment_image_src( $value, $this->get( 'size' ) ); 65 | $image_alt = get_the_title( $value ); 66 | if ( is_array( $image_src ) && isset( $image_src[0] ) ) { 67 | $image_src = $image_src[0]; 68 | } 69 | } else { 70 | $image_url = $value; 71 | $path = str_replace( home_url(), '', $value ); 72 | $image_path = ABSPATH . untrailingslashit( $path ); 73 | if ( file_exists( $image_path ) ) { 74 | $wp_check_filetype = wp_check_filetype( $image_path ); 75 | if ( ! empty( $wp_check_filetype['type'] ) ) { 76 | $image_src = $image_url; 77 | } 78 | } 79 | } 80 | 81 | if ( $image_src && ! is_array( $image_src ) ) { 82 | $image = sprintf( 83 | '%s%s', 84 | esc_url( $image_src ), 85 | $image_alt, 86 | $btn_remove 87 | ); 88 | $hide_class = ''; 89 | } 90 | } 91 | 92 | return sprintf( 93 | '%s
94 | %s 95 | ', 96 | esc_html__( 'Image Select', 'smart-custom-fields' ), 97 | esc_attr( SCF_Config::PREFIX . 'upload-image' ), 98 | esc_attr( $hide_class ), 99 | esc_attr( $this->get( 'size' ) ), 100 | wp_kses_post( $image ), 101 | esc_attr( $name ), 102 | esc_attr( $value ), 103 | disabled( true, $disabled, false ) 104 | ); 105 | } 106 | 107 | /** 108 | * Displaying the option fields in custom field settings page. 109 | * 110 | * @param int $group_key Group key. 111 | * @param int $field_key Field key. 112 | */ 113 | public function display_field_options( $group_key, $field_key ) { 114 | $this->display_label_option( $group_key, $field_key ); 115 | $this->display_name_option( $group_key, $field_key ); 116 | ?> 117 | 118 | 119 | 120 | 122 | 123 | 124 | 125 | 126 | 127 | 132 | 133 | 134 | 135 | 136 | 137 | 143 | 144 | 145 | 'message', 21 | 'display-name' => __( 'Message', 'smart-custom-fields' ), 22 | 'optgroup' => 'basic-fields', 23 | 'allow-multiple-data' => false, 24 | 'layout' => 'full-width', 25 | ); 26 | } 27 | 28 | /** 29 | * Set the non required items. 30 | * 31 | * @return array 32 | */ 33 | protected function options() { 34 | return array( 35 | 'default' => '', 36 | 'notes' => '', 37 | ); 38 | } 39 | 40 | /** 41 | * Getting the field. 42 | * 43 | * @param int $index Field index. 44 | * @param string $value The value. 45 | * @return string 46 | */ 47 | public function get_field( $index, $value ) { 48 | $name = $this->get_field_name_in_editor( $index ); 49 | $disabled = $this->get_disable_attribute( $index ); 50 | return sprintf( 51 | '
%s
', 52 | esc_attr( $name ), 53 | disabled( true, $disabled, false ), 54 | esc_textarea( $value ) 55 | ); 56 | } 57 | 58 | /** 59 | * Displaying the option fields in custom field settings page. 60 | * 61 | * @param int $group_key Group key. 62 | * @param int $field_key Field key. 63 | */ 64 | public function display_field_options( $group_key, $field_key ) { 65 | $this->display_name_option( $group_key, $field_key ); 66 | ?> 67 | 68 | 69 | 70 | 74 | 75 | 76 | 77 | 78 | 79 | 84 | 85 | 86 | 'radio', 21 | 'display-name' => __( 'Radio', 'smart-custom-fields' ), 22 | 'optgroup' => 'select-fields', 23 | ); 24 | } 25 | 26 | /** 27 | * Set the non required items. 28 | * 29 | * @return array 30 | */ 31 | protected function options() { 32 | return array( 33 | 'choices' => '', 34 | 'radio_direction' => 'horizontal', // or vertical 35 | 'default' => '', 36 | 'instruction' => '', 37 | 'notes' => '', 38 | ); 39 | } 40 | 41 | /** 42 | * Getting the field. 43 | * 44 | * @param int $index Field index. 45 | * @param string $value The value. 46 | * @return string 47 | */ 48 | public function get_field( $index, $value ) { 49 | $name = $this->get_field_name_in_editor( $index ); 50 | $disabled = $this->get_disable_attribute( $index ); 51 | $choices = SCF::choices_eol_to_array( $this->get( 'choices' ) ); 52 | $direction = $this->get( 'radio_direction' ); 53 | 54 | $form_field = sprintf( 55 | '', 56 | esc_attr( $name ), 57 | disabled( true, $disabled, false ) 58 | ); 59 | foreach ( $choices as $key => $choice ) { 60 | $choice = trim( $choice ); 61 | if ( ! SCF::is_assoc( $choices ) ) { 62 | $key = $choice; 63 | } 64 | $form_field .= sprintf( 65 | '', 66 | esc_attr( SCF_Config::PREFIX . 'item-' . $direction ), 67 | esc_attr( $name ), 68 | esc_attr( $key ), 69 | checked( $value, $key, false ), 70 | disabled( true, $disabled, false ), 71 | esc_html( $choice ) 72 | ); 73 | } 74 | return $form_field; 75 | } 76 | 77 | /** 78 | * Displaying the option fields in custom field settings page. 79 | * 80 | * @param int $group_key Group key. 81 | * @param int $field_key Field key. 82 | */ 83 | public function display_field_options( $group_key, $field_key ) { 84 | $this->display_label_option( $group_key, $field_key ); 85 | $this->display_name_option( $group_key, $field_key ); 86 | ?> 87 | 88 | 89 | 90 | 94 | value', 'smart-custom-fields' ); ?> 95 | 96 | 97 | 98 | 99 | 100 | __( 'horizontal', 'smart-custom-fields' ), 103 | 'vertical' => __( 'vertical', 'smart-custom-fields' ), 104 | ); 105 | foreach ( $directions as $key => $value ) { 106 | printf( 107 | '   ', 108 | esc_attr( $this->get_field_name_in_setting( $group_key, $field_key, 'radio_direction' ) ), 109 | esc_attr( $key ), 110 | checked( $this->get( 'radio_direction' ), $key, false ), 111 | esc_html( $value ) 112 | ); 113 | } 114 | ?> 115 | 116 | 117 | 118 | 119 | 120 | 124 | 125 | 126 | 127 | 128 | 129 | 131 | 132 | 133 | 134 | 135 | 136 | 141 | 142 | 143 | 'select', 21 | 'display-name' => __( 'Select', 'smart-custom-fields' ), 22 | 'optgroup' => 'select-fields', 23 | ); 24 | } 25 | 26 | /** 27 | * Set the non required items. 28 | * 29 | * @return array 30 | */ 31 | protected function options() { 32 | return array( 33 | 'choices' => '', 34 | 'default' => '', 35 | 'instruction' => '', 36 | 'notes' => '', 37 | ); 38 | } 39 | 40 | /** 41 | * Getting the field. 42 | * 43 | * @param int $index Field index. 44 | * @param string $value The value. 45 | * @return string 46 | */ 47 | public function get_field( $index, $value ) { 48 | $name = $this->get_field_name_in_editor( $index ); 49 | $disabled = $this->get_disable_attribute( $index ); 50 | $choices = SCF::choices_eol_to_array( $this->get( 'choices' ) ); 51 | 52 | $form_field = ''; 53 | foreach ( $choices as $key => $choice ) { 54 | $choice = trim( $choice ); 55 | if ( ! SCF::is_assoc( $choices ) ) { 56 | $key = $choice; 57 | } 58 | $form_field .= sprintf( 59 | '', 60 | esc_attr( $key ), 61 | selected( $value, $key, false ), 62 | esc_html( $choice ) 63 | ); 64 | } 65 | return sprintf( 66 | '', 67 | esc_attr( $name ), 68 | disabled( true, $disabled, false ), 69 | $form_field 70 | ); 71 | } 72 | 73 | /** 74 | * Displaying the option fields in custom field settings page. 75 | * 76 | * @param int $group_key Group key. 77 | * @param int $field_key Field key. 78 | */ 79 | public function display_field_options( $group_key, $field_key ) { 80 | $this->display_label_option( $group_key, $field_key ); 81 | $this->display_name_option( $group_key, $field_key ); 82 | ?> 83 | 84 | 85 | 86 | 90 | value', 'smart-custom-fields' ); ?> 91 | 92 | 93 | 94 | 95 | 96 | 100 | 101 | 102 | 103 | 104 | 105 | 107 | 108 | 109 | 110 | 111 | 112 | 117 | 118 | 119 | 'text', 21 | 'display-name' => __( 'Text', 'smart-custom-fields' ), 22 | 'optgroup' => 'basic-fields', 23 | ); 24 | } 25 | 26 | /** 27 | * Set the non required items. 28 | * 29 | * @return array 30 | */ 31 | protected function options() { 32 | return array( 33 | 'default' => '', 34 | 'instruction' => '', 35 | 'notes' => '', 36 | ); 37 | } 38 | 39 | /** 40 | * Getting the field. 41 | * 42 | * @param int $index Field index. 43 | * @param string $value The value. 44 | * @return string 45 | */ 46 | public function get_field( $index, $value ) { 47 | $name = $this->get_field_name_in_editor( $index ); 48 | $disabled = $this->get_disable_attribute( $index ); 49 | return sprintf( 50 | '', 51 | esc_attr( $name ), 52 | esc_attr( $value ), 53 | disabled( true, $disabled, false ) 54 | ); 55 | } 56 | 57 | /** 58 | * Displaying the option fields in custom field settings page. 59 | * 60 | * @param int $group_key Group key. 61 | * @param int $field_key Field key. 62 | */ 63 | public function display_field_options( $group_key, $field_key ) { 64 | $this->display_label_option( $group_key, $field_key ); 65 | $this->display_name_option( $group_key, $field_key ); 66 | ?> 67 | 68 | 69 | 70 | 74 | 75 | 76 | 77 | 78 | 79 | 81 | 82 | 83 | 84 | 85 | 86 | 91 | 92 | 93 | 'textarea', 21 | 'display-name' => __( 'Textarea', 'smart-custom-fields' ), 22 | 'optgroup' => 'basic-fields', 23 | ); 24 | } 25 | 26 | /** 27 | * Set the non required items. 28 | * 29 | * @return array 30 | */ 31 | protected function options() { 32 | return array( 33 | 'rows' => 5, 34 | 'default' => '', 35 | 'instruction' => '', 36 | 'notes' => '', 37 | ); 38 | } 39 | 40 | /** 41 | * Getting the field. 42 | * 43 | * @param int $index Field index. 44 | * @param string $value The value. 45 | * @return string 46 | */ 47 | public function get_field( $index, $value ) { 48 | $name = $this->get_field_name_in_editor( $index ); 49 | $disabled = $this->get_disable_attribute( $index ); 50 | $rows = $this->get( 'rows' ); 51 | return sprintf( 52 | '', 53 | esc_attr( $name ), 54 | esc_attr( $rows ), 55 | disabled( true, $disabled, false ), 56 | esc_textarea( $value ) 57 | ); 58 | } 59 | 60 | /** 61 | * Displaying the option fields in custom field settings page. 62 | * 63 | * @param int $group_key Group key. 64 | * @param int $field_key Field key. 65 | */ 66 | public function display_field_options( $group_key, $field_key ) { 67 | $this->display_label_option( $group_key, $field_key ); 68 | $this->display_name_option( $group_key, $field_key ); 69 | ?> 70 | 71 | 72 | 73 | 78 | 79 | 80 | 81 | 82 | 83 | 87 | 88 | 89 | 90 | 91 | 92 | 94 | 95 | 96 | 97 | 98 | 99 | 104 | 105 | 106 | 'wysiwyg', 26 | 'display-name' => __( 'Wysiwyg', 'smart-custom-fields' ), 27 | 'optgroup' => 'content-fields', 28 | ); 29 | } 30 | 31 | /** 32 | * Set the non required items. 33 | * 34 | * @return array 35 | */ 36 | protected function options() { 37 | return array( 38 | 'default' => '', 39 | 'instruction' => '', 40 | 'notes' => '', 41 | ); 42 | } 43 | 44 | /** 45 | * Loading js after loading TinyMCE in editor page. 46 | */ 47 | public function editor_enqueue_scripts() { 48 | add_action( 'after_wp_tiny_mce', array( $this, 'after_wp_tiny_mce' ) ); 49 | } 50 | 51 | /** 52 | * Add script for wysiwyg. 53 | */ 54 | public function after_wp_tiny_mce() { 55 | // phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedScript 56 | printf( 57 | '', 58 | esc_url( plugins_url( SCF_Config::NAME ) . '/js/editor-wysiwyg.js' ) 59 | ); 60 | // phpcs:enable 61 | } 62 | 63 | /** 64 | * Processing to be executed immediately after the field initialization. 65 | * If not exec this, taxonomy and profile wysiwyg has js error. 66 | */ 67 | protected function after_loaded() { 68 | add_action( 'admin_footer', array( $this, 'admin_footer' ) ); 69 | } 70 | 71 | /** 72 | * Add dummy editor. 73 | */ 74 | public function admin_footer() { 75 | ?> 76 |
77 | 78 |
79 | get_field_name_in_editor( $index ); 91 | $wysiwyg_id = str_replace( array( '[', ']', '-' ), '_', $name ); 92 | $disabled = $this->get_disable_attribute( $index ); 93 | $value = format_for_editor( $value ); 94 | 95 | return sprintf( 96 | '
97 |
98 |
%1$s
99 |
100 | 101 | 102 |
103 |
104 |
105 |
106 | 107 |
108 |
', 109 | $this->media_buttons( $wysiwyg_id ), 110 | esc_attr( $wysiwyg_id ), 111 | esc_attr( $name ), 112 | disabled( true, $disabled, false ), 113 | wp_kses_post( $value ), 114 | esc_html__( 'Visual', 'smart-custom-fields' ), 115 | esc_html__( 'Text', 'smart-custom-fields' ) 116 | ); 117 | } 118 | 119 | /** 120 | * Displaying the option fields in custom field settings page. 121 | * 122 | * @param int $group_key Group key. 123 | * @param int $field_key Field key. 124 | */ 125 | public function display_field_options( $group_key, $field_key ) { 126 | $this->display_label_option( $group_key, $field_key ); 127 | $this->display_name_option( $group_key, $field_key ); 128 | ?> 129 | 130 | 131 | 132 | 136 | 137 | 138 | 139 | 140 | 141 | 143 | 144 | 145 | 146 | 147 | 148 | 153 | 154 | 155 | '; 166 | return sprintf( 167 | '%s', 168 | esc_attr( $editor_id ), 169 | // phpcs:ignore WordPress.WP.I18n.MissingArgDomain 170 | esc_attr__( 'Add Media' ), 171 | // phpcs:ignore WordPress.WP.I18n.MissingArgDomain 172 | $img . __( 'Add Media' ) 173 | ); 174 | } 175 | 176 | /** 177 | * Validating when displaying meta data. 178 | * 179 | * @param mixed $value The value. 180 | * @param string $field_type Field type. 181 | * @return string|array 182 | */ 183 | public function validate_get_value( $value, $field_type ) { 184 | if ( $field_type === $this->get_attribute( 'type' ) ) { 185 | if ( is_array( $value ) ) { 186 | $validated_value = array(); 187 | foreach ( $value as $k => $v ) { 188 | $validated_value[ $k ] = $this->add_the_content_filter( $v ); 189 | } 190 | $value = $validated_value; 191 | } else { 192 | $value = $this->add_the_content_filter( $value ); 193 | } 194 | } 195 | return $value; 196 | } 197 | 198 | /** 199 | * Hooking functions that is hooked to the_content. 200 | * 201 | * @param string $value The value. 202 | * @return string 203 | */ 204 | protected function add_the_content_filter( $value ) { 205 | if ( has_filter( 'the_content', 'wptexturize' ) ) { 206 | $value = wptexturize( $value ); 207 | } 208 | if ( has_filter( 'the_content', 'convert_smilies' ) ) { 209 | $value = convert_smilies( $value ); 210 | } 211 | if ( has_filter( 'the_content', 'convert_chars' ) ) { 212 | $value = convert_chars( $value ); 213 | } 214 | if ( has_filter( 'the_content', 'wpautop' ) ) { 215 | $value = wpautop( $value ); 216 | } 217 | if ( has_filter( 'the_content', 'shortcode_unautop' ) ) { 218 | $value = shortcode_unautop( $value ); 219 | } 220 | if ( has_filter( 'the_content', 'prepend_attachment' ) ) { 221 | $value = prepend_attachment( $value ); 222 | } 223 | return $value; 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /classes/models/class.abstract-field-base.php: -------------------------------------------------------------------------------- 1 | '', // eg. text 20 | 'display-name' => '', // eg. Text 21 | 'optgroup' => 'other-fields', 22 | 'allow-multiple-data' => false, 23 | 'layout' => 'default', // or "full-width" (new attribute to choose layout type) 24 | ); 25 | 26 | /** 27 | * Options of this field 28 | * 29 | * @var array 30 | */ 31 | protected $options = array( 32 | 'name' => '', 33 | 'label' => '', 34 | ); 35 | 36 | /** 37 | * __construct 38 | */ 39 | public function __construct() { 40 | $attributes = array_merge( $this->attributes, $this->init() ); 41 | $options = array_merge( $this->options, $this->options() ); 42 | if ( empty( $attributes['type'] ) || empty( $attributes['display-name'] ) ) { 43 | exit( 'This field object is invalid. Field object must have type and display-name attributes.' ); 44 | } 45 | if ( empty( $attributes['optgroup'] ) ) { 46 | $attributes['optgroup'] = 'basic-fields'; 47 | } 48 | $this->attributes = $attributes; 49 | $this->options = $options; 50 | add_filter( 51 | SCF_Config::PREFIX . 'field-select-' . $attributes['optgroup'], 52 | array( $this, 'field_select' ) 53 | ); 54 | $this->after_loaded(); 55 | 56 | SCF::add_form_field_instance( $this ); 57 | } 58 | 59 | /** 60 | * Set the required items 61 | * 62 | * @return array 63 | */ 64 | abstract protected function init(); 65 | 66 | /** 67 | * Set the non required items 68 | * 69 | * @return array 70 | */ 71 | abstract protected function options(); 72 | 73 | /** 74 | * Processing to be executed immediately after the field initialization 75 | */ 76 | protected function after_loaded() { 77 | } 78 | 79 | /** 80 | * Getting the field. 81 | * 82 | * @param int $index Field index. 83 | * @param mixed $value Field value. 84 | * @return string 85 | */ 86 | abstract public function get_field( $index, $value ); 87 | 88 | /** 89 | * Adding the type of this field to fields selection in custom field settings page. 90 | * 91 | * @param array $attributes List of fields that belong to the optgroup. 92 | * @return array 93 | */ 94 | public function field_select( $attributes ) { 95 | $attributes[ $this->get_attribute( 'type' ) ] = $this->get_attribute( 'display-name' ); 96 | return $attributes; 97 | } 98 | 99 | /** 100 | * Displaying the option fields in custom field settings page ( Common ). 101 | * 102 | * @param int $group_key Group key. 103 | * @param int $field_key Field key. 104 | */ 105 | public function display_options( $group_key, $field_key ) { 106 | $fields = SCF::get_form_field_instances(); 107 | foreach ( $fields as $field ) { 108 | if ( $field->get_attribute( 'type' ) === $this->get_attribute( 'type' ) ) { 109 | foreach ( $this->options as $key => $value ) { 110 | $field->set( $key, $value ); 111 | } 112 | } 113 | $field->_display_field_options( $group_key, $field_key ); 114 | } 115 | } 116 | 117 | /** 118 | * Displaying the name in custom field settings page. 119 | * 120 | * @param int $group_key Group key. 121 | * @param int $field_key Field key. 122 | */ 123 | protected function display_name_option( $group_key, $field_key ) { 124 | ?> 125 | 126 | * 127 | 128 | 134 | 135 | 136 | 147 | 148 | 149 | 150 | 156 | 157 | 158 | 177 | 178 | 179 | 180 | display_field_options( $group_key, $field_key ); ?> 181 |
182 | 183 | 184 | get( 'name' ), 198 | $index 199 | ); 200 | } 201 | 202 | /** 203 | * Whether to disabled. 204 | * Return true only when the null because data that all users have saved when $index is not null 205 | * 206 | * @param string $index Field index. 207 | * @return bool 208 | */ 209 | protected function get_disable_attribute( $index ) { 210 | $disabled = false; 211 | if ( is_null( $index ) ) { 212 | $disabled = true; 213 | } 214 | return $disabled; 215 | } 216 | 217 | /** 218 | * Getting the name attribute in custom field settings page. 219 | * 220 | * @param int $group_key Group key. 221 | * @param int $field_key Field key. 222 | * @param string $name Field name. 223 | * @return string 224 | */ 225 | public function get_field_name_in_setting( $group_key, $field_key, $name ) { 226 | return sprintf( 227 | '%s[%s][fields][%s][%s]', 228 | SCF_Config::NAME, 229 | $group_key, 230 | $field_key, 231 | $name 232 | ); 233 | } 234 | 235 | /** 236 | * Getting saved option value. 237 | * 238 | * @param string $key Key of options of this field. 239 | * @return mixed 240 | */ 241 | public function get( $key ) { 242 | if ( array_key_exists( $key, $this->options ) ) { 243 | return $this->options[ $key ]; 244 | } 245 | } 246 | 247 | /** 248 | * Set option value. 249 | * 250 | * @param string $key Key of options of this field. 251 | * @param mixed $value Value of options of this field. 252 | */ 253 | public function set( $key, $value ) { 254 | if ( array_key_exists( $key, $this->options ) ) { 255 | $this->options[ $key ] = $value; 256 | } 257 | } 258 | 259 | /** 260 | * Getting the attribute value. 261 | * 262 | * @param string $key Internal attribute key. 263 | * @return mixed 264 | */ 265 | public function get_attribute( $key ) { 266 | if ( array_key_exists( $key, $this->attributes ) ) { 267 | return $this->attributes[ $key ]; 268 | } 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /classes/models/class.ajax.php: -------------------------------------------------------------------------------- 1 | delete_term_meta_for_wp43(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /classes/models/class.cache.php: -------------------------------------------------------------------------------- 1 | clear_meta(); 74 | $this->clear_settings_posts(); 75 | $this->clear_settings(); 76 | $this->clear_repeat_multiple_data(); 77 | } 78 | 79 | /** 80 | * Saving to cache. 81 | * 82 | * @param WP_Post|WP_User|WP_Term|stdClass $wp_object Object type object. 83 | * @param string $name Cache name. 84 | * @param mixed $data Cache data. 85 | */ 86 | public function save_meta( $wp_object, $name, $data ) { 87 | $meta = new Smart_Custom_Fields_Meta( $wp_object ); 88 | $id = $meta->get_id(); 89 | $type = $meta->get_type(); 90 | $meta_type = $meta->get_meta_type(); 91 | if ( ! empty( $id ) && ! empty( $type ) && ! empty( $meta_type ) ) { 92 | $this->meta[ $meta_type . '_' . $type . '_' . $id ][ $name ] = $data; 93 | } 94 | } 95 | 96 | /** 97 | * Getting the cache. 98 | * 99 | * @param WP_Post|WP_User|WP_Term|stdClass $wp_object Object type object. 100 | * @param string $name Cache name. 101 | * @return mixed 102 | */ 103 | public function get_meta( $wp_object, $name = null ) { 104 | $meta = new Smart_Custom_Fields_Meta( $wp_object ); 105 | $id = $meta->get_id(); 106 | $type = $meta->get_type(); 107 | $meta_type = $meta->get_meta_type(); 108 | if ( ! empty( $id ) && ! empty( $type ) && ! empty( $meta_type ) ) { 109 | if ( is_null( $name ) ) { 110 | if ( isset( $this->meta[ $meta_type . '_' . $type . '_' . $id ] ) ) { 111 | return $this->meta[ $meta_type . '_' . $type . '_' . $id ]; 112 | } 113 | } elseif ( isset( $this->meta[ $meta_type . '_' . $type . '_' . $id ][ $name ] ) ) { 114 | return $this->meta[ $meta_type . '_' . $type . '_' . $id ][ $name ]; 115 | } 116 | } 117 | } 118 | 119 | /** 120 | * Clear caches. 121 | */ 122 | public function clear_meta() { 123 | $this->meta = array(); 124 | } 125 | 126 | /** 127 | * Saving to cache that enabled custom field settings in the post type or the role or the term. 128 | * 129 | * @param WP_Post|WP_User|WP_Term|stdClass $wp_object Object type object. 130 | * @param array $settings_posts Settings. 131 | */ 132 | public function save_settings_posts( $wp_object, $settings_posts ) { 133 | $meta = new Smart_Custom_Fields_Meta( $wp_object ); 134 | $type = $meta->get_type( false ); 135 | $meta_type = $meta->get_meta_type(); 136 | $this->settings_posts[ $meta_type . '_' . $type ] = $settings_posts; 137 | } 138 | 139 | /** 140 | * Getting cache that enabled custom field settings in the post type or the role or the term. 141 | * 142 | * @param WP_Post|WP_User|WP_Term|stdClass $wp_object Object type object. 143 | * @return array|null 144 | */ 145 | public function get_settings_posts( $wp_object ) { 146 | $meta = new Smart_Custom_Fields_Meta( $wp_object ); 147 | $type = $meta->get_type( false ); 148 | $meta_type = $meta->get_meta_type(); 149 | if ( isset( $this->settings_posts[ $meta_type . '_' . $type ] ) ) { 150 | return $this->settings_posts[ $meta_type . '_' . $type ]; 151 | } 152 | } 153 | 154 | /** 155 | * Clear the $settings_posts. 156 | */ 157 | public function clear_settings_posts() { 158 | $this->settings_posts = array(); 159 | } 160 | 161 | /** 162 | * Saving the Setting object to cache. 163 | * 164 | * @param int $settings_post_id Settings id. 165 | * @param Smart_Custom_Fields_Setting $setting Smart_Custom_Fields_Setting object. 166 | * @param WP_Post|WP_User|WP_Term|stdClass $wp_object Object type object. 167 | */ 168 | public function save_settings( $settings_post_id, $setting, $wp_object = null ) { 169 | if ( ! is_null( $wp_object ) ) { 170 | $meta = new Smart_Custom_Fields_Meta( $wp_object ); 171 | $id = $meta->get_id(); 172 | $meta_type = $meta->get_meta_type(); 173 | } 174 | if ( ! empty( $meta_type ) && ! empty( $id ) ) { 175 | $this->settings[ $settings_post_id ][ $meta_type . '_' . $id ] = $setting; 176 | } else { 177 | $this->settings[ $settings_post_id ][0] = $setting; 178 | } 179 | } 180 | 181 | /** 182 | * Getting the Setting object cache 183 | * If there isn't the custom field settings ... null 184 | * If there is custom field settings 185 | * If there is no data for the specified $meta_type + $id 186 | * There is a thing of the General ... Smart_Custom_Fields_Setting 187 | * There isn't a thing of the General ... false 188 | * If there the data for the specified $meta_type + $id ... Smart_Custom_Fields_Setting 189 | * 190 | * @param int $settings_post_id Settings id. 191 | * @param WP_Post|WP_User|WP_Term|stdClass $wp_object Object type object. 192 | * @return Smart_Custom_Fields_Setting|false|null 193 | */ 194 | public function get_settings( $settings_post_id, $wp_object = null ) { 195 | if ( ! is_null( $wp_object ) ) { 196 | $meta = new Smart_Custom_Fields_Meta( $wp_object ); 197 | $id = $meta->get_id(); 198 | $meta_type = $meta->get_meta_type(); 199 | } 200 | 201 | if ( isset( $this->settings[ $settings_post_id ] ) ) { 202 | $settings = $this->settings[ $settings_post_id ]; 203 | if ( ! empty( $id ) && ! empty( $meta_type ) && isset( $settings[ $meta_type . '_' . $id ] ) ) { 204 | return $settings[ $meta_type . '_' . $id ]; 205 | } 206 | if ( isset( $settings[0] ) ) { 207 | return $settings[0]; 208 | } 209 | return false; 210 | } 211 | } 212 | 213 | /** 214 | * Clear the $settings 215 | */ 216 | public function clear_settings() { 217 | $this->settings = array(); 218 | } 219 | 220 | /** 221 | * Saving the delimited identification data of the repeated multi-value items to cache. 222 | * 223 | * @param WP_Post|WP_User|WP_Term|stdClass $wp_object Object type object. 224 | * @param mixed $repeat_multiple_data Repeat multiple data. 225 | */ 226 | public function save_repeat_multiple_data( $wp_object, $repeat_multiple_data ) { 227 | $meta = new Smart_Custom_Fields_Meta( $wp_object ); 228 | $id = $meta->get_id(); 229 | $type = $meta->get_type(); 230 | $meta_type = $meta->get_meta_type(); 231 | if ( ! empty( $id ) && ! empty( $type ) && ! empty( $meta_type ) ) { 232 | $this->repeat_multiple_data[ $meta_type . '_' . $type . '_' . $id ] = $repeat_multiple_data; 233 | } 234 | } 235 | 236 | /** 237 | * Getting delimited identification data of the repeated multi-value items from cache. 238 | * 239 | * @param WP_Post|WP_User|WP_Term|stdClass $wp_object Object type object. 240 | * @return mixed 241 | */ 242 | public function get_repeat_multiple_data( $wp_object ) { 243 | $meta = new Smart_Custom_Fields_Meta( $wp_object ); 244 | $id = $meta->get_id(); 245 | $type = $meta->get_type(); 246 | $meta_type = $meta->get_meta_type(); 247 | if ( ! empty( $id ) && ! empty( $type ) ) { 248 | if ( isset( $this->repeat_multiple_data[ $meta_type . '_' . $type . '_' . $id ] ) ) { 249 | return $this->repeat_multiple_data[ $meta_type . '_' . $type . '_' . $id ]; 250 | } 251 | } 252 | } 253 | 254 | /** 255 | * Clear delimited identification data of the repeated multi-value items cache. 256 | */ 257 | public function clear_repeat_multiple_data() { 258 | $this->repeat_multiple_data = array(); 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /classes/models/class.group.php: -------------------------------------------------------------------------------- 1 | name = $group_name; 43 | $this->repeat = true === $repeat ? true : false; 44 | $fields = array(); 45 | foreach ( $_fields as $field_attributes ) { 46 | $field = SCF::get_form_field_instance( $field_attributes['type'] ); 47 | if ( ! is_a( $field, 'Smart_Custom_Fields_Field_Base' ) ) { 48 | continue; 49 | } 50 | foreach ( $field_attributes as $key => $value ) { 51 | $field->set( $key, $value ); 52 | } 53 | 54 | if ( ! empty( $field ) ) { 55 | $fields[ $field->get( 'name' ) ] = $field; 56 | } 57 | } 58 | $this->fields = $fields; 59 | } 60 | 61 | /** 62 | * Getting group name 63 | * 64 | * @return string 65 | */ 66 | public function get_name() { 67 | if ( is_numeric( $this->name ) ) { 68 | return; 69 | } 70 | return $this->name; 71 | } 72 | 73 | /** 74 | * Getting fields that saved in this settings page 75 | * 76 | * @return array 77 | */ 78 | public function get_fields() { 79 | return $this->fields; 80 | } 81 | 82 | /** 83 | * Getting the field. 84 | * 85 | * @param string $field_name Field name. 86 | * @return Smart_Custom_Fields_Field_Base|null 87 | */ 88 | public function get_field( $field_name ) { 89 | $fields = $this->get_fields(); 90 | if ( isset( $fields[ $field_name ] ) ) { 91 | return $fields[ $field_name ]; 92 | } 93 | } 94 | 95 | /** 96 | * Whether repeating group. 97 | * 98 | * @return bool 99 | */ 100 | public function is_repeatable() { 101 | return $this->repeat; 102 | } 103 | 104 | /** 105 | * Displaying "hide" if $repeatable is empty. 106 | * 107 | * @param string $repeatable Repeatable. 108 | */ 109 | private function add_hide_class( $repeatable ) { 110 | if ( ! $repeatable ) { 111 | echo 'hide'; 112 | } 113 | } 114 | 115 | /** 116 | * Displaying the option fields in custom field settings page ( Common ). 117 | * 118 | * @param int $group_key Group key. 119 | */ 120 | public function display_options( $group_key ) { 121 | ?> 122 |
123 |
124 | 132 |
133 | 134 | 135 | 136 | 144 | 145 |
* 137 | 143 |
146 | page_title = $page_title; 69 | $this->menu_title = $menu_title; 70 | $this->capability = $capability; 71 | $this->menu_slug = $menu_slug; 72 | $this->icon_url = $icon_url; 73 | $this->position = $position; 74 | add_action( 'admin_menu', array( $this, 'add_options_page_menu' ) ); 75 | } 76 | 77 | /** 78 | * Add options page menu. 79 | */ 80 | public function add_options_page_menu() { 81 | return add_menu_page( 82 | $this->page_title, 83 | $this->menu_title, 84 | $this->capability, 85 | $this->menu_slug, 86 | array( $this, 'display' ), 87 | $this->icon_url, 88 | $this->position 89 | ); 90 | } 91 | 92 | /** 93 | * Display option. 94 | */ 95 | public function display() { 96 | $option = SCF::generate_option_object( filter_input( INPUT_GET, 'page' ) ); 97 | if ( ! $option ) { 98 | return; 99 | } 100 | ?> 101 |
102 |

menu_title ); ?>

103 | 104 |
105 | restore( $revision ); 48 | } 49 | 50 | /** 51 | * リビジョンデータを保存 52 | * *_post_meta はリビジョンIDのときに自動的に本物IDに変換して処理してしまうので、*_metadata を使うこと 53 | * 54 | * @param int $post_id The revision post id. 55 | */ 56 | public function wp_insert_post( $post_id ) { 57 | if ( ! isset( $_POST[ SCF_Config::NAME ] ) ) { 58 | return; 59 | } 60 | if ( ! wp_is_post_revision( $post_id ) ) { 61 | return; 62 | } 63 | $settings = SCF::get_settings( get_post( $post_id ) ); 64 | if ( ! $settings ) { 65 | return; 66 | } 67 | 68 | check_admin_referer( 69 | SCF_Config::NAME . '-fields', 70 | SCF_Config::PREFIX . 'fields-nonce' 71 | ); 72 | 73 | $meta = new Smart_Custom_Fields_Meta( get_post( $post_id ) ); 74 | $meta->save( $_POST ); 75 | } 76 | 77 | /** 78 | * プレビューのときはプレビューのメタデータを返す。ただし、アイキャッチはリビジョンが無いので除外する 79 | * 80 | * @param mixed $value The value to return, either a single metadata value or an array of values depending on the value of $single. Default null. 81 | * @param int $post_id ID of the object metadata is for. 82 | * @param string $meta_key Metadata key. 83 | * @param bool $single Whether to return only the first value of the specified $meta_key. 84 | * @return mixed 85 | */ 86 | public function get_post_metadata( $value, $post_id, $meta_key, $single ) { 87 | if ( ! is_preview() ) { 88 | return $value; 89 | } 90 | 91 | if ( is_null( SCF::get_field( get_post( $post_id ), $meta_key ) ) ) { 92 | return $value; 93 | } 94 | 95 | $preview_id = $this->get_preview_id( $post_id ); 96 | if ( $preview_id && '_thumbnail_id' !== $meta_key ) { 97 | if ( $post_id !== $preview_id ) { 98 | $value = get_post_meta( $preview_id, $meta_key, $single ); 99 | } 100 | } 101 | return $value; 102 | } 103 | 104 | /** 105 | * プレビューの Post ID を返す 106 | * 107 | * @param int $post_id The post id. 108 | * @return int 109 | */ 110 | protected function get_preview_id( $post_id ) { 111 | global $post; 112 | $preview_id = 0; 113 | if ( isset( $post->ID ) && intval( $post->ID ) === intval( $post_id ) ) { 114 | $preview = wp_get_post_autosave( $post_id ); 115 | if ( is_preview() && $preview ) { 116 | $preview_id = $preview->ID; 117 | } 118 | } 119 | return $preview_id; 120 | } 121 | 122 | /** 123 | * リビジョン比較画面でメタデータを表示させるためにキーを追加する 124 | * 125 | * @param array $fields List of fields to revision. Contains 'post_title', 'post_content', and 'post_excerpt' by default. 126 | * @return array 127 | */ 128 | public function _wp_post_revision_fields( $fields ) { 129 | $fields[ SCF_Config::PREFIX . 'debug-preview' ] = esc_html__( 'Smart Custom Fields', 'smart-custom-fields' ); 130 | return $fields; 131 | } 132 | 133 | /** 134 | * プレビュー時にメタデータを保存するためにキーとなる項目を出力する 135 | */ 136 | public function edit_form_after_title() { 137 | printf( 138 | '', 139 | esc_attr( SCF_Config::PREFIX . 'debug-preview' ) 140 | ); 141 | } 142 | 143 | /** 144 | * Display metadata on revision comparison screen. 145 | * 146 | * @param string $value The current revision field to compare to or from. 147 | * @param string $column The current revision field. 148 | * @param WP_Post $post The revision post object to compare to or from. 149 | * @return string 150 | */ 151 | public function _wp_post_revision_field_debug_preview( $value, $column, $post ) { 152 | $output = ''; 153 | $values = SCF::gets( $post->ID ); 154 | foreach ( $values as $field_name_or_group_name => $value ) { 155 | $output .= sprintf( "■ %s\n", $field_name_or_group_name ); 156 | if ( is_array( $value ) ) { 157 | if ( isset( $value[0] ) && is_array( $value[0] ) ) { 158 | foreach ( $value as $i => $repeat_data_values ) { 159 | $output .= sprintf( "- #%s\n", $i ); 160 | foreach ( $repeat_data_values as $field_name => $repeat_data_value ) { 161 | $output .= sprintf( ' %s: ', $field_name ); 162 | if ( is_array( $repeat_data_value ) ) { 163 | $output .= sprintf( "[%s]\n", implode( ', ', $repeat_data_value ) ); 164 | } else { 165 | $output .= sprintf( "%s\n", $repeat_data_value ); 166 | } 167 | } 168 | } 169 | } else { 170 | $output .= sprintf( "[%s]\n", implode( ', ', $value ) ); 171 | } 172 | } else { 173 | $output .= sprintf( "%s\n", $value ); 174 | } 175 | } 176 | return $output; 177 | } 178 | 179 | /** 180 | * If false, it is saved as a revision. 181 | * 182 | * @param bool $check_for_changes Whether to check for changes before saving a new revision. Default true. 183 | * @param WP_Post $last_revision The last revision post object. 184 | * @param WP_Post $post The post object. 185 | * @return bool 186 | */ 187 | public function wp_save_post_revision_check_for_changes( $check_for_changes, $last_revision, $post ) { 188 | $post_meta = array(); 189 | $p = get_post_custom( $post->ID ); 190 | foreach ( $p as $key => $value ) { 191 | $v = SCF::get( $key ); 192 | if ( ! is_null( $v ) ) { 193 | $post_meta[ $key ][] = $v; 194 | } 195 | } 196 | 197 | $posted_data = filter_input( INPUT_POST, SCF_Config::NAME, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ); 198 | if ( $posted_data && maybe_serialize( $post_meta ) !== maybe_serialize( $posted_data ) ) { 199 | return false; 200 | } 201 | 202 | return true; 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /classes/models/class.setting.php: -------------------------------------------------------------------------------- 1 | id = $id; 42 | $this->title = $title; 43 | $post_meta = get_post_meta( 44 | $this->get_id(), 45 | SCF_Config::PREFIX . 'setting', 46 | true 47 | ); 48 | if ( is_array( $post_meta ) ) { 49 | foreach ( $post_meta as $group ) { 50 | $group = shortcode_atts( 51 | array( 52 | 'group-name' => '', 53 | 'repeat' => false, 54 | 'fields' => array(), 55 | ), 56 | $group 57 | ); 58 | $this->add_group( 59 | $group['group-name'], 60 | $group['repeat'], 61 | $group['fields'] 62 | ); 63 | } 64 | } 65 | } 66 | 67 | /** 68 | * Getting the post ID. 69 | * 70 | * @return string 71 | */ 72 | public function get_id() { 73 | return $this->id; 74 | } 75 | 76 | /** 77 | * Getting the post title. 78 | * 79 | * @return string 80 | */ 81 | public function get_title() { 82 | return $this->title; 83 | } 84 | 85 | /** 86 | * Getting the group objects. 87 | * 88 | * @return array 89 | */ 90 | public function get_groups() { 91 | return $this->groups; 92 | } 93 | 94 | /** 95 | * Getting together the fields in each group. 96 | * 97 | * @return array 98 | */ 99 | public function get_fields() { 100 | $groups = $this->get_groups(); 101 | $fields = array(); 102 | foreach ( $groups as $group ) { 103 | $fields = array_merge( $fields, $group->get_fields() ); 104 | } 105 | return $fields; 106 | } 107 | 108 | /** 109 | * Adding group to the tail. 110 | * If the argument is not, adding an empty group. 111 | * 112 | * @param string $group_name Gruop name. 113 | * @param bool $repeat If repeat, set true. 114 | * @param array $fields Fields. 115 | */ 116 | public function add_group( $group_name = null, $repeat = false, array $fields = array() ) { 117 | $group = $this->new_group( $group_name, $repeat, $fields ); 118 | $group_name = $group->get_name(); 119 | if ( $group_name ) { 120 | $this->groups[ $group_name ] = $group; 121 | } else { 122 | $this->groups[] = $group; 123 | } 124 | } 125 | 126 | /** 127 | * Getting group. 128 | * 129 | * @param string $group_name Gruop name. 130 | * @return Smart_Custom_Fields_Group|false 131 | */ 132 | public function get_group( $group_name ) { 133 | $groups = $this->get_groups(); 134 | if ( isset( $groups[ $group_name ] ) && $groups[ $group_name ]->is_repeatable() ) { 135 | return $groups[ $group_name ]; 136 | } 137 | } 138 | 139 | /** 140 | * Adding group to the head. 141 | * If the argument is not, adding an empty group. 142 | * 143 | * @param string $group_name Gruop name. 144 | * @param bool $repeat If repeat, set true. 145 | * @param array $fields Fields. 146 | */ 147 | public function add_group_unshift( $group_name = null, $repeat = false, array $fields = array() ) { 148 | $group = $this->new_group( $group_name, $repeat, $fields ); 149 | array_unshift( $this->groups, $group ); 150 | } 151 | 152 | /** 153 | * Getting generated new group. 154 | * 155 | * @param string $group_name Gruop name. 156 | * @param bool $repeat If repeat, set true. 157 | * @param array $fields Fields. 158 | */ 159 | protected function new_group( $group_name, $repeat, $fields ) { 160 | return new Smart_Custom_Fields_Group( $group_name, $repeat, $fields ); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /classes/models/class.yoast-seo-analysis.php: -------------------------------------------------------------------------------- 1 | =7.4" 19 | }, 20 | "require-dev": { 21 | "wp-coding-standards/wpcs": "^3.0", 22 | "dealerdirect/phpcodesniffer-composer-installer": "^0.7", 23 | "yoast/phpunit-polyfills": "^1.0", 24 | "phpcompatibility/phpcompatibility-wp": "*" 25 | }, 26 | "scripts" :{ 27 | "format": "phpcbf --standard=./.phpcs.xml.dist --report-summary --report-source", 28 | "lint": "phpcs --standard=./.phpcs.xml.dist" 29 | }, 30 | "config": { 31 | "allow-plugins": { 32 | "dealerdirect/phpcodesniffer-composer-installer": true 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /css/editor.css: -------------------------------------------------------------------------------- 1 | /** 2 | * editor.css 3 | * Version : 1.3.1 4 | * Author : inc2734 5 | * Created : September 23, 2014 6 | * Modified : June 4, 2016 7 | * License : GPLv2 or later 8 | * License URI: http://www.gnu.org/licenses/gpl-2.0.html 9 | */ 10 | 11 | /** ================================================== 12 | * #normal-sortables 13 | */ 14 | .smart-cf-meta-box { 15 | margin: 0 -12px; 16 | } 17 | 18 | /** ================================================== 19 | * .smart-cf-meta-box-table 20 | */ 21 | .smart-cf-meta-box-table { 22 | background: #fff; 23 | border-bottom: #eee solid 1px; 24 | padding: 10px 12px; 25 | } 26 | .smart-cf-meta-box-table table { 27 | width: 100%; 28 | } 29 | .smart-cf-meta-box-table th, 30 | .smart-cf-meta-box-table td { 31 | font-weight: normal; 32 | text-align: left; 33 | padding: 7px 5px; 34 | vertical-align: top; 35 | } 36 | .smart-cf-meta-box-table th { 37 | width: 25%; 38 | } 39 | .smart-cf-meta-box-table td label { 40 | margin-right: 10px; 41 | } 42 | .smart-cf-meta-box-table .wp-editor-tools:after { 43 | display: block; 44 | } 45 | .smart-cf-meta-box-table .wp-editor-container { 46 | clear: both; 47 | } 48 | .smart-cf-meta-box-table td .instruction { 49 | font-size: 14px; 50 | margin: 0 0 10px; 51 | } 52 | .smart-cf-meta-box-table td .description { 53 | font-size: 12px; 54 | margin: 10px 0 0; 55 | color: #888; 56 | } 57 | .smart-cf-meta-box-table td .clear { 58 | clear: both; 59 | } 60 | 61 | /** ================================================== 62 | * .smart-cf-meta-box-repeat-tables 63 | */ 64 | .smart-cf-meta-box-repeat-tables .smart-cf-meta-box-table > .smart-cf-icon-handle, 65 | .smart-cf-meta-box-repeat-tables .smart-cf-meta-box-table > .smart-cf-repeat-btn { 66 | position: relative; 67 | top: 3px; 68 | vertical-align: middle; 69 | } 70 | .smart-cf-meta-box-repeat-tables .smart-cf-repeat-btn { 71 | cursor: pointer; 72 | width: auto; 73 | height: auto; 74 | font-size: 1.3em; 75 | padding: 0; 76 | -webkit-border-radius: 50%; 77 | border-radius: 50%; 78 | display: inline-block; 79 | vertical-align: middle; 80 | text-align: center; 81 | color: #999; 82 | margin-right: 3px; 83 | } 84 | .smart-cf-meta-box-repeat-tables .smart-cf-icon-handle:hover, 85 | .smart-cf-meta-box-repeat-tables .smart-cf-repeat-btn:hover { 86 | color: #333; 87 | } 88 | .smart-cf-meta-box-repeat-tables table { 89 | margin-top: 7px; 90 | } 91 | 92 | /** ================================================== 93 | * relation 94 | */ 95 | .smart-cf-meta-box-table .smart-cf-relation-left, 96 | .smart-cf-meta-box-table .smart-cf-relation-right { 97 | border: #ddd solid 1px; 98 | border-radius: 3px; 99 | height: 160px; 100 | } 101 | .smart-cf-meta-box-table .smart-cf-relation-left ul, 102 | .smart-cf-meta-box-table .smart-cf-relation-right ul { 103 | list-style: none; 104 | margin: 0; 105 | padding: 0; 106 | } 107 | .smart-cf-meta-box-table .smart-cf-relation-left ul li, 108 | .smart-cf-meta-box-table .smart-cf-relation-right ul li { 109 | background: #fff; 110 | border-bottom: #eee solid 1px; 111 | color: #999; 112 | margin: 0; 113 | padding: 5px 10px; 114 | position: relative; 115 | } 116 | .smart-cf-meta-box-table .smart-cf-relation-left ul li[data-status="publish"], 117 | .smart-cf-meta-box-table .smart-cf-relation-right ul li[data-status="publish"] { 118 | color: #0074a2; 119 | } 120 | .smart-cf-meta-box-table .smart-cf-relation-left ul li::after, 121 | .smart-cf-meta-box-table .smart-cf-relation-right ul li::after { 122 | content: attr(data-status); 123 | display: inline-block; 124 | background-color: #999; 125 | color: #fff; 126 | border-radius: 4px; 127 | padding: 0 3px; 128 | font-size: 10px; 129 | margin-left: .5em; 130 | position: relative; 131 | top: -1px; 132 | } 133 | .smart-cf-meta-box-table .smart-cf-relation-left ul li[data-status="publish"]::after, 134 | .smart-cf-meta-box-table .smart-cf-relation-right ul li[data-status="publish"]::after { 135 | display: none; 136 | } 137 | .smart-cf-meta-box-table .smart-cf-relation-left { 138 | float: left; 139 | width: 47%; 140 | overflow: hidden; 141 | } 142 | .smart-cf-meta-box-table .smart-cf-relation-left .smart-cf-search { 143 | background-color: #f5f5f5; 144 | border-bottom: 1px solid #eee; 145 | padding: 5px; 146 | } 147 | .smart-cf-meta-box-table .smart-cf-relation-left .smart-cf-relation-children-select { 148 | overflow: auto; 149 | height: 122px; 150 | } 151 | .smart-cf-meta-box-table .smart-cf-relation-left ul li { 152 | cursor: pointer; 153 | } 154 | .smart-cf-meta-box-table .smart-cf-relation-left ul li:hover { 155 | background: #e4f6fd; 156 | } 157 | .smart-cf-meta-box-table .smart-cf-relation-left .load-relation-items { 158 | background: #e4f6fd; 159 | cursor: pointer; 160 | margin: 0; 161 | padding: 6px 10px; 162 | text-align: center; 163 | } 164 | .smart-cf-meta-box-table .smart-cf-relation-left .load-relation-items:hover { 165 | background: #c1ebfc; 166 | } 167 | .smart-cf-meta-box-table .smart-cf-relation-right { 168 | float: right; 169 | width: 50%; 170 | overflow: auto; 171 | } 172 | .smart-cf-meta-box-table .smart-cf-relation-right ul li { 173 | padding-right: 30px; 174 | padding-left: 30px; 175 | } 176 | .smart-cf-meta-box-table .smart-cf-relation-right ul li .smart-cf-icon-handle { 177 | position: absolute; 178 | top: 4px; 179 | left: 5px; 180 | margin: 0; 181 | } 182 | .smart-cf-meta-box-table .smart-cf-relation-right ul li .relation-remove { 183 | cursor: pointer; 184 | display: block; 185 | display: flex; 186 | align-items: center; 187 | justify-content: center; 188 | height: 12px; 189 | width: 12px; 190 | line-height: 1; 191 | border-radius: 3px; 192 | position: absolute; 193 | top: 7px; 194 | right: 6px; 195 | color: #fff; 196 | background-color: #32373c; 197 | } 198 | 199 | /** ================================================== 200 | * .smart-cf-upload-image, .smart-cf-upload-file 201 | */ 202 | .smart-cf-upload-image, 203 | .smart-cf-upload-file { 204 | display: inline-block; 205 | position: relative; 206 | } 207 | .smart-cf-upload-image img, 208 | .smart-cf-upload-file img { 209 | margin-top: 5px; 210 | max-width: 100%; 211 | vertical-align: top; 212 | } 213 | .smart-cf-upload-image .btn-remove-image, 214 | .smart-cf-upload-file .btn-remove-file { 215 | background: red; 216 | border-radius: 3px; 217 | color: #fff; 218 | cursor: pointer; 219 | display: block; 220 | font-size: 10px; 221 | padding: 2px 6px; 222 | position: absolute; 223 | left: 5px; 224 | bottom: 5px; 225 | } 226 | 227 | /** ================================================== 228 | * .hide 229 | */ 230 | .smart-cf-upload-image.hide, 231 | .smart-cf-upload-file.hide, 232 | .smart-cf-upload-image .btn-remove-image.hide, 233 | .smart-cf-upload-file .btn-remove-file.hide, 234 | .load-relation-items.hide { 235 | display: none; 236 | } 237 | 238 | /** ================================================== 239 | * classes 240 | */ 241 | .smart-cf-icon-handle { 242 | cursor: move; 243 | display: inline-block; 244 | margin-right: 10px; 245 | overflow: hidden; 246 | position: relative; 247 | color: #CCC; 248 | } 249 | 250 | .smart-cf-item-vertical { 251 | display: block; 252 | margin: 0 0 3px; 253 | } 254 | -------------------------------------------------------------------------------- /css/option.css: -------------------------------------------------------------------------------- 1 | /** 2 | * option.css 3 | * Version : 1.0.0 4 | * Author : inc2734 5 | * Created : May 30, 2016 6 | * Modified : 7 | * License : GPLv2 or later 8 | * License URI: http://www.gnu.org/licenses/gpl-2.0.html 9 | */ 10 | -------------------------------------------------------------------------------- /css/profile.css: -------------------------------------------------------------------------------- 1 | /** 2 | * profile.css 3 | * Version : 1.0.0 4 | * Author : inc2734 5 | * Created : March 18, 2014 6 | * Modified : 7 | * License : GPLv2 or later 8 | * License URI: http://www.gnu.org/licenses/gpl-2.0.html 9 | */ 10 | 11 | /** ================================================== 12 | * .smart-cf-meta-box 13 | */ 14 | .smart-cf-meta-box:first-child { 15 | border-top: #ddd solid 1px; 16 | } 17 | 18 | /** ================================================== 19 | * .smart-cf-meta-box-table 20 | */ 21 | .smart-cf-meta-box-table { 22 | background: transparent; 23 | border-bottom: #ddd solid 1px; 24 | padding: 10px 0; 25 | } 26 | -------------------------------------------------------------------------------- /css/settings.css: -------------------------------------------------------------------------------- 1 | /** 2 | * settings.css 3 | * Version : 1.1.0 4 | * Author : inc2734 5 | * Created : September 23, 2014 6 | * Modified : July 14, 2018 7 | * License : GPLv2 or later 8 | * License URI: http://www.gnu.org/licenses/gpl-2.0.html 9 | */ 10 | 11 | /** ================================================== 12 | * #normal-sortables 13 | */ 14 | #normal-sortables { 15 | display: none; 16 | } 17 | 18 | /** ================================================== 19 | * .btn-add-group 20 | */ 21 | .smart-cf-fields-wrapper .btn-add-group { 22 | margin-top: 10px; 23 | } 24 | 25 | /** ================================================== 26 | * .smart-cf-group 27 | */ 28 | .smart-cf-group { 29 | background: #f5f5f5; 30 | border: #eee solid 1px; 31 | margin: 10px 0 0; 32 | padding: 10px; 33 | position: relative; 34 | } 35 | .smart-cf-group .smart-cf-require { 36 | color: #f60; 37 | font-size: 90%; 38 | margin-left: 3px; 39 | } 40 | .smart-cf-group .smart-cf-notes { 41 | color: #999; 42 | font-size: 90%; 43 | } 44 | 45 | /** 46 | * .btn-remove-group 47 | */ 48 | .smart-cf-group .btn-remove-group { 49 | cursor: pointer; 50 | position: absolute; 51 | top: 10px; 52 | right: 10px; 53 | } 54 | .smart-cf-group .btn-remove-group .dashicons, 55 | .smart-cf-group .btn-remove-group .dashicons:before { 56 | font-size: 14px; 57 | height: 14px; 58 | width: 14px; 59 | } 60 | 61 | /** 62 | * .btn-add-field 63 | */ 64 | .smart-cf-group .btn-add-field { 65 | margin-top: 5px; 66 | } 67 | 68 | /** 69 | * .smart-cf-group-repeat 70 | */ 71 | .smart-cf-group .smart-cf-group-repeat { 72 | margin: 0 0 5px; 73 | } 74 | .smart-cf-group .smart-cf-group-repeat label { 75 | position: relative; 76 | top: -2px; 77 | } 78 | @media (max-width:750px) { 79 | .smart-cf-group .smart-cf-group-name { 80 | max-width:79%; 81 | } 82 | } 83 | 84 | /** 85 | * .smart-cf-group-names 86 | */ 87 | .smart-cf-group .smart-cf-group-names { 88 | width: 100%; 89 | } 90 | .smart-cf-group .smart-cf-group-names th { 91 | text-align: left; 92 | width: 20%; 93 | } 94 | 95 | /** 96 | * .smart-cf-alert 97 | */ 98 | .smart-cf-alert { 99 | color: #f60; 100 | display: block; 101 | font-size: 90%; 102 | margin-top: 2px 0; 103 | } 104 | 105 | /** ================================================== 106 | * .smart-cf-fields 107 | */ 108 | .smart-cf-group .smart-cf-fields { 109 | margin-top: 7px; 110 | } 111 | 112 | /** ================================================== 113 | * .smart-cf-field 114 | */ 115 | .smart-cf-group .smart-cf-field { 116 | background: #fff; 117 | border: #eee solid 1px; 118 | margin: 5px 0 0; 119 | padding: 10px; 120 | overflow: hidden; 121 | *zoom: 1; 122 | } 123 | .smart-cf-group .smart-cf-field:first-child { 124 | margin-top: 0; 125 | } 126 | .smart-cf-group .smart-cf-field table { 127 | border-collapse: collapse; 128 | width: 100%; 129 | } 130 | .smart-cf-group .smart-cf-field table th, 131 | .smart-cf-group .smart-cf-field table td { 132 | padding: 5px 0; 133 | } 134 | .smart-cf-group .smart-cf-field table th { 135 | font-weight: normal; 136 | padding-top: 10px; 137 | padding-right: 15px; 138 | text-align: left; 139 | vertical-align: top; 140 | width: 15%; 141 | } 142 | .smart-cf-group .smart-cf-field table table { 143 | margin: -5px 0; 144 | } 145 | 146 | /** 147 | * .smart-cf-icon-handle 148 | */ 149 | .smart-cf-group .smart-cf-field .smart-cf-icon-handle { 150 | float: left; 151 | margin-top: 4px; 152 | margin-right: 8px; 153 | } 154 | 155 | /** 156 | * .field-label 157 | */ 158 | .smart-cf-group .smart-cf-field .field-label { 159 | cursor: pointer; 160 | position: relative; 161 | overflow: hidden; 162 | *zoom: 1; 163 | } 164 | .smart-cf-group .smart-cf-field .field-label small { 165 | color: #999; 166 | font-size: 90%; 167 | } 168 | 169 | /** 170 | * .btn-remove-field 171 | */ 172 | .smart-cf-group .smart-cf-field .btn-remove-field { 173 | cursor: pointer; 174 | float: right; 175 | } 176 | .smart-cf-group .smart-cf-field .btn-remove-field .dashicons, 177 | .smart-cf-group .smart-cf-field .btn-remove-field .dashicons:before { 178 | font-size: 14px; 179 | height: 14px; 180 | width: 14px; 181 | } 182 | 183 | /** ================================================== 184 | * #smart-cf-meta-box-condition 185 | */ 186 | #smart-cf-meta-box-condition-post b, 187 | #smart-cf-meta-box-condition-profile b, 188 | #smart-cf-meta-box-condition-taxonomy b, 189 | #smart-cf-meta-box-condition-options-page b { 190 | display: block; 191 | margin: 0 0 5px; 192 | } 193 | #smart-cf-meta-box-condition-post label, 194 | #smart-cf-meta-box-condition-profile label, 195 | #smart-cf-meta-box-condition-taxonomy label, 196 | #smart-cf-meta-box-condition-options-page label { 197 | display: block; 198 | margin: 0 0 5px; 199 | } 200 | 201 | #smart-cf-meta-box-condition-post .selectivity-multiple-input { 202 | box-shadow: none; 203 | } 204 | 205 | #smart-cf-meta-box-condition-post .selectivity-multiple-selected-item { 206 | margin-right: 5px; 207 | } 208 | 209 | #smart-cf-meta-box-condition-post .selectivity-multiple-selected-item-remove { 210 | font-weight: bold; 211 | color: #fff; 212 | } 213 | 214 | #smart-cf-meta-box-condition-post .selectivity-multiple-input-container { 215 | border: 1px solid #ddd; 216 | box-shadow: inset 0 1px 2px rgba(0,0,0,.07); 217 | background-color: #fff; 218 | color: #32373c; 219 | outline: 0; 220 | transition: 50ms border-color ease-in-out; 221 | border-radius: 0; 222 | } 223 | 224 | #smart-cf-meta-box-condition-post .selectivity-dropdown, 225 | #smart-cf-meta-box-condition-post .selectivity-result-item:first-child, 226 | #smart-cf-meta-box-condition-post .selectivity-load-more, 227 | #smart-cf-meta-box-condition-post .selectivity-result-item:last-child, 228 | #smart-cf-meta-box-condition-post .selectivity-result-children:last-child .selectivity-result-item:last-child { 229 | border-radius: 0; 230 | } 231 | 232 | .smart-cf-group .smart-cf-group-repeat label .ios-ui-select, 233 | #smart-cf-meta-box-condition-post .ios-ui-select, 234 | #smart-cf-meta-box-condition-profile .ios-ui-select, 235 | #smart-cf-meta-box-condition-taxonomy .ios-ui-select, 236 | #smart-cf-meta-box-condition-options-page .ios-ui-select { 237 | height: 18px; 238 | width: 32px; 239 | margin-bottom: -5px; 240 | position: relative; 241 | background: #ddd; 242 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, .07); 243 | 244 | } 245 | 246 | .smart-cf-group .smart-cf-group-repeat label .ios-ui-select .inner, 247 | #smart-cf-meta-box-condition-post .ios-ui-select .inner, 248 | #smart-cf-meta-box-condition-profile .ios-ui-select .inner, 249 | #smart-cf-meta-box-condition-taxonomy .ios-ui-select .inner, 250 | #smart-cf-meta-box-condition-options-page .ios-ui-select .inner { 251 | width: 12px; 252 | height: 12px; 253 | } 254 | 255 | .smart-cf-group .smart-cf-group-repeat label .ios-ui-select.checked .inner, 256 | #smart-cf-meta-box-condition-post .ios-ui-select.checked .inner, 257 | #smart-cf-meta-box-condition-profile .ios-ui-select.checked .inner, 258 | #smart-cf-meta-box-condition-taxonomy .ios-ui-select.checked .inner, 259 | #smart-cf-meta-box-condition-options-page .ios-ui-select.checked .inner { 260 | left: 17px; 261 | } 262 | 263 | 264 | /** ================================================== 265 | * .hide 266 | */ 267 | .smart-cf-group .smart-cf-field table tr.hide, 268 | .smart-cf-group.hide, 269 | .smart-cf-group .btn-add-field.hide, 270 | .smart-cf-group .smart-cf-group-names.hide, 271 | .smart-cf-group .smart-cf-field.hide, 272 | .smart-cf-group .smart-cf-field table.hide { 273 | display: none; 274 | } 275 | 276 | /** ================================================== 277 | * classes 278 | */ 279 | .smart-cf-icon-handle { 280 | background: url( ../images/handle.png ) no-repeat; 281 | cursor: move; 282 | display: inline-block; 283 | margin-right: 10px; 284 | height: 10px; 285 | width: 10px; 286 | overflow: hidden; 287 | position: relative; 288 | } 289 | -------------------------------------------------------------------------------- /css/taxonomy.css: -------------------------------------------------------------------------------- 1 | /** 2 | * taxonomy.css 3 | * Version : 1.0.0 4 | * Author : inc2734 5 | * Created : April 26, 2014 6 | * Modified : 7 | * License : GPLv2 or later 8 | * License URI: http://www.gnu.org/licenses/gpl-2.0.html 9 | */ 10 | 11 | /** ================================================== 12 | * .smart-cf-meta-box-table 13 | */ 14 | .smart-cf-meta-box-table { 15 | background: transparent; 16 | border-bottom-color: #ddd; 17 | } 18 | -------------------------------------------------------------------------------- /css/wysiwyg.css: -------------------------------------------------------------------------------- 1 | /** 2 | * wysiwyg.css 3 | * Version : 1.0.0 4 | * Author : inc2734 5 | * Created : April 11, 2015 6 | * Modified : 7 | * License : GPLv2 or later 8 | * License URI: http://www.gnu.org/licenses/gpl-2.0.html 9 | */ 10 | 11 | body { 12 | font-family: "Open Sans", Helvetica, Arial, sans-serif; 13 | font-size: 13px; 14 | } -------------------------------------------------------------------------------- /images/handle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inc2734/smart-custom-fields/2de9335232b25056bce9ecedb564867d9850d8e8/images/handle.png -------------------------------------------------------------------------------- /js/editor-colorpicker.js: -------------------------------------------------------------------------------- 1 | jQuery( function( $ ) { 2 | $( '.smart-cf-meta-box-table' ).each( function( i, e ) { 3 | $( e ).find( '.smart-cf-colorpicker' ).each( function( i, e ) { 4 | if ( $( e ).attr( 'disabled' ) !== 'disabled' ) { 5 | $( e ).wpColorPicker(); 6 | } 7 | } ); 8 | } ); 9 | 10 | $( document ).on( 'smart-cf-after-add-group', function( e, obj ) { 11 | var parent = $( obj.button ).parents( '.smart-cf-meta-box-repeat-tables' ); 12 | parent.find( '.smart-cf-colorpicker' ).each( function( i, e ) { 13 | if ( $( e ).attr( 'disabled' ) !== 'disabled' ) { 14 | $( e ).wpColorPicker(); 15 | } 16 | } ); 17 | } ); 18 | } ); 19 | -------------------------------------------------------------------------------- /js/editor-datepicker.js: -------------------------------------------------------------------------------- 1 | jQuery( function( $ ) { 2 | $( '.smart-cf-meta-box-table' ).each( function( i, e ) { 3 | $( e ).find( '.smart-cf-datepicker' ).each( function( i, e ) { 4 | if ( $( e ).attr( 'disabled' ) !== 'disabled' ) { 5 | $( e ).datepicker( $( e ).data( 'js' ) ); 6 | } 7 | } ); 8 | } ); 9 | 10 | $( document ).on( 'smart-cf-after-add-group', function( e, obj ) { 11 | var parent = $( obj.button ).parents( '.smart-cf-meta-box-repeat-tables' ); 12 | parent.find( '.smart-cf-datepicker' ).each( function( i, e ) { 13 | if ( $( e ).attr( 'disabled' ) !== 'disabled' ) { 14 | $( e ).datepicker( $( e ).data( 'js' ) ); 15 | } 16 | } ); 17 | 18 | $( '.smart-cf-datetime_picker.add' ).each( function ( i, e ) { 19 | var data = e.getAttribute( 'data-js' ); 20 | data = JSON.parse( data ); 21 | data['enableTime'] = true; 22 | flatpickr( this, data ); 23 | $( this ).removeClass( 'add' ); 24 | } ); 25 | } ); 26 | } ); 27 | -------------------------------------------------------------------------------- /js/editor-relation-common.js: -------------------------------------------------------------------------------- 1 | jQuery( function( $ ) { 2 | 3 | var table_class = 'tr'; 4 | 5 | /** 6 | * 選択肢 7 | */ 8 | var choices_li = '.smart-cf-relation-children-select li'; 9 | $( '.smart-cf-meta-box' ).on( 'click', choices_li, function() { 10 | var id = $( this ).data( 'id' ); 11 | var parent = $( this ).closest( table_class ); 12 | var limit = parent.find( '.smart-cf-relation-left' ).data( 'limit' ); 13 | 14 | if ( limit > 0 && limit <= parent.find( '.smart-cf-relation-right li' ).length ) { 15 | return true; 16 | } 17 | 18 | if ( parent.find( '.smart-cf-relation-right li[data-id="' + id + '"]' ).length !== 0 ) { 19 | return true; 20 | } 21 | 22 | var clone = $( this ).clone(); 23 | clone 24 | .prepend( $( '' ) ) 25 | .append( $( '-' ) ); 26 | parent.find( '.smart-cf-relation-right ul' ).append( clone ); 27 | update_relation_value( $( this ).closest( 'tr' ) ); 28 | } ); 29 | 30 | /** 31 | * 選択済み項目の削除 32 | */ 33 | var relation_remove = '.smart-cf-relation-right li .relation-remove'; 34 | $( '.smart-cf-meta-box' ).on( 'click', relation_remove, function() { 35 | var tr = $( this ).closest( 'tr' ); 36 | $( this ).parent().remove(); 37 | update_relation_value( tr ); 38 | } ); 39 | 40 | /** 41 | * update_relation_value 42 | * @param dom tr 43 | */ 44 | function update_relation_value( tr ) { 45 | var hidden = tr.find( 'input[type="hidden"]' ); 46 | hidden.each( function( i, e ) { 47 | if ( i !== 0 ) { 48 | $( this ).remove(); 49 | } 50 | } ); 51 | tr.find( '.smart-cf-relation-right li' ).each( function( i, e ) { 52 | var hidden_box = $( this ).closest( table_class ).find( '.smart-cf-relation-children-select' ); 53 | var id = $( this ).data( 'id' ); 54 | var clone = hidden.first().clone(); 55 | var name = clone.attr( 'name' ); 56 | clone.attr( 'name', name + '[]' ); 57 | clone.val( id ); 58 | hidden_box.append( clone ); 59 | } ); 60 | } 61 | 62 | /** 63 | * sortable 64 | */ 65 | $( '.smart-cf-meta-box' ).find( '.smart-cf-relation-right ul' ) 66 | .on( 'mousedown', function( event ) { 67 | event.stopPropagation(); 68 | } ) 69 | .sortable( { 70 | handle: '.smart-cf-icon-handle', 71 | update: function() { 72 | update_relation_value( $( this ).closest( 'tr' ) ); 73 | } 74 | } ); 75 | 76 | } ); 77 | -------------------------------------------------------------------------------- /js/editor-relation-post-types.js: -------------------------------------------------------------------------------- 1 | jQuery( function( $ ) { 2 | 3 | var table_class = 'tr'; 4 | 5 | /** 6 | * 初期化 7 | * click_count はロードボタンを押すごとに加算。 8 | * 検索ボックスが変更されるたびに 0 にリセットすること。 9 | */ 10 | $( '.smart-cf-meta-box .load-relation-post-types' ).closest( table_class ) 11 | .data( 'click_count', 0 ) 12 | .data( 'search_timer', null ) 13 | .data( 'recent_search_query', '' ); 14 | 15 | /** 16 | * 検索ボタン 17 | */ 18 | $( document ).on( 'keyup', '.smart-cf-meta-box .search-input-post-types', function() { 19 | var parent = $( this ).closest( table_class ); 20 | var search_timer = parent.data( 'search_timer' ); 21 | clearTimeout( search_timer ); 22 | 23 | parent.data( 'click_count', 0 ); 24 | parent.find( '.smart-cf-relation-children-select ul li' ).remove(); 25 | 26 | var search_query = $( this ).val(); 27 | parent.data( 'recent_search_query', search_query ); 28 | parent.data( 'search_timer', setTimeout( function() { 29 | get_posts( { s: search_query }, parent ); 30 | }, 2000 ) ); 31 | } ); 32 | 33 | /** 34 | * 読み込みボタン 35 | */ 36 | $( document ).on( 'click', '.smart-cf-meta-box .load-relation-post-types', function() { 37 | var parent = $( this ).closest( table_class ); 38 | var click_count = parent.data( 'click_count' ); 39 | click_count ++; 40 | parent.data( 'click_count', click_count ); 41 | var search_query = parent.data( 'recent_search_query' ); 42 | if ( search_query ) { 43 | get_posts( { s: search_query }, parent ); 44 | } else { 45 | get_posts( {}, parent ); 46 | } 47 | } ); 48 | 49 | /** 50 | * クエリ 51 | */ 52 | function get_posts( args, table ) { 53 | var click_count = table.data( 'click_count' ); 54 | var post_types = table.find( '.smart-cf-relation-left' ).data( 'post-types' ); 55 | var btn_load = table.find( '.load-relation-post-types' ); 56 | var btn_load_text = btn_load.text(); 57 | btn_load.text( 'Now loading...' ); 58 | 59 | var nameEl = document.getElementById('smart-cf-field-name-data'); 60 | var name = ''; 61 | if (nameEl) { 62 | name = nameEl.getAttribute('data-js'); 63 | } 64 | 65 | args = $.extend( args, { 66 | action : smart_cf_relation_post_types.action, 67 | nonce : smart_cf_relation_post_types.nonce, 68 | click_count: click_count, 69 | post_types : post_types, 70 | field_name: name 71 | } ); 72 | $.post( 73 | smart_cf_relation_post_types.endpoint, 74 | args, 75 | function( response ) { 76 | btn_load.addClass( 'hide' ); 77 | $( response ).each( function( i, e ) { 78 | table.find( '.smart-cf-relation-children-select ul' ).append( 79 | $( '
  • ' ) 80 | .attr( 'data-id', this.ID ) 81 | .attr( 'data-status', this.post_status ) 82 | .text( this.post_title ) 83 | ); 84 | } ); 85 | 86 | btn_load.text( btn_load_text ); 87 | btn_load.removeClass( 'hide' ); 88 | } 89 | ); 90 | return false; 91 | } 92 | } ); 93 | -------------------------------------------------------------------------------- /js/editor-relation-taxonomies.js: -------------------------------------------------------------------------------- 1 | jQuery( function( $ ) { 2 | 3 | var table_class = 'tr'; 4 | 5 | /** 6 | * 初期化 7 | * click_count はロードボタンを押すごとに加算。 8 | * 検索ボックスが変更されるたびに 0 にリセットすること。 9 | */ 10 | $( '.smart-cf-meta-box .load-relation-terms' ).closest( table_class ) 11 | .data( 'click_count', 0 ) 12 | .data( 'search_timer', null ) 13 | .data( 'recent_search_query', '' ); 14 | 15 | /** 16 | * 検索ボタン 17 | */ 18 | $( document ).on( 'keyup', '.smart-cf-meta-box .search-input-terms', function() { 19 | var parent = $( this ).closest( table_class ); 20 | var search_timer = parent.data( 'search_timer' ); 21 | clearTimeout( search_timer ); 22 | 23 | parent.data( 'click_count', 0 ); 24 | parent.find( '.smart-cf-relation-children-select ul li' ).remove(); 25 | 26 | var search_query = $( this ).val(); 27 | parent.data( 'recent_search_query', search_query ); 28 | parent.data( 'search_timer', setTimeout( function() { 29 | get_terms( { search: search_query }, parent ); 30 | }, 2000 ) ); 31 | } ); 32 | 33 | /** 34 | * 読み込みボタン 35 | */ 36 | $( document ).on( 'click', '.smart-cf-meta-box .load-relation-terms', function() { 37 | var parent = $( this ).closest( table_class ); 38 | var click_count = parent.data( 'click_count' ); 39 | click_count ++; 40 | parent.data( 'click_count', click_count ); 41 | var search_query = parent.data( 'recent_search_query' ); 42 | if ( search_query ) { 43 | get_terms( { search: search_query }, parent ); 44 | } else { 45 | get_terms( {}, parent ); 46 | } 47 | } ); 48 | 49 | /** 50 | * クエリ 51 | */ 52 | function get_terms( args, table ) { 53 | var click_count = table.data( 'click_count' ); 54 | var taxonomies = table.find( '.smart-cf-relation-left' ).data( 'taxonomies' ); 55 | var btn_load = table.find( '.load-relation-terms' ); 56 | var btn_load_text = btn_load.text(); 57 | btn_load.text( 'Now loading...' ); 58 | 59 | args = $.extend( args, { 60 | action : smart_cf_relation_taxonomies.action, 61 | nonce : smart_cf_relation_taxonomies.nonce, 62 | click_count: click_count, 63 | taxonomies : taxonomies 64 | } ); 65 | $.post( 66 | smart_cf_relation_taxonomies.endpoint, 67 | args, 68 | function( response ) { 69 | btn_load.addClass( 'hide' ); 70 | $( response ).each( function( i, e ) { 71 | table.find( '.smart-cf-relation-children-select ul' ).append( 72 | $( '
  • ' ) 73 | .attr( 'data-id', this.term_id ) 74 | .text( this.name ) 75 | ); 76 | } ); 77 | 78 | btn_load.text( btn_load_text ); 79 | btn_load.removeClass( 'hide' ); 80 | } 81 | ); 82 | return false; 83 | } 84 | } ); 85 | -------------------------------------------------------------------------------- /js/editor-wysiwyg.js: -------------------------------------------------------------------------------- 1 | jQuery( function( $ ) { 2 | $( window ).on( 'load', function() { 3 | $( '.smart-cf-meta-box' ).each( function( i, e ) { 4 | var wrapper = $( e ); 5 | var table_class = '.smart-cf-meta-box-table'; 6 | 7 | /** 8 | * ロード時に wysiwyg エディター用のテキストエリアがあったら wysiwyg 化する。 9 | */ 10 | wrapper.find( '.smart-cf-wp-editor' ).each( function( i, e ) { 11 | if ( $( this ).parents( table_class ).css( 'display' ) === 'none' ) { 12 | return true; 13 | } 14 | $( e ).attr( 'id', $( e ).attr( 'name' ).replace( /(\[|\]|\-)/ig, '_' ) ); 15 | var editor_id = $( e ).attr( 'id' ); 16 | var wrap = $( e ).parents( '.wp-editor-wrap' ); 17 | initialize_editor( wrap, editor_id ); 18 | 19 | var mceinit = scf_generate_mceinit( editor_id ); 20 | tinyMCEPreInit.mceInit[editor_id] = mceinit; 21 | if ( typeof tinymce !== 'undefined' ) { 22 | tinymce.init( mceinit ); 23 | } 24 | 25 | var qtinit = scf_generate_qtinit( editor_id ); 26 | tinyMCEPreInit.qtInit[editor_id] = qtinit; 27 | if ( typeof quicktags !== 'undefined' ) { 28 | quicktags( qtinit ); 29 | QTags._buttonsInit(); 30 | } 31 | } ); 32 | } ); 33 | 34 | /** 35 | * グループ追加ボタンを押したときに発火。 36 | * wysiwyg エディター用のテキストエリアがあったら wysiwyg 化する。 37 | */ 38 | $( document ).on( 'smart-cf-after-add-group', function( e, data ) { 39 | var button = data.button; 40 | var clone = data.clone; 41 | clone.find( '.smart-cf-wp-editor' ).each( function( i, e ) { 42 | $( e ).attr( 'id', $( e ).attr( 'name' ).replace( /(\[|\]|\-)/ig, '_' ) ); 43 | var editor_id = $( e ).attr( 'id' ); 44 | var wrap = $( e ).parents( '.wp-editor-wrap' ); 45 | initialize_editor( wrap, editor_id ); 46 | 47 | var mceinit = scf_generate_mceinit( editor_id ); 48 | tinyMCEPreInit.mceInit[editor_id] = mceinit; 49 | if ( typeof tinymce !== 'undefined' ) { 50 | tinymce.init( mceinit ); 51 | } 52 | 53 | var qtinit = scf_generate_qtinit( editor_id ); 54 | tinyMCEPreInit.qtInit[editor_id] = qtinit; 55 | if ( typeof quicktags !== 'undefined' ) { 56 | quicktags( qtinit ); 57 | QTags._buttonsInit(); 58 | } 59 | } ); 60 | } ); 61 | 62 | /** 63 | * ドラッグしたときに発火。 64 | * wysiwyg エディター用のテキストエリアをオフる。 65 | */ 66 | $( document ).on( 'smart-cf-repeat-table-sortable-start', function( e, ui ) { 67 | $( ui ).find( '.smart-cf-wp-editor' ).each( function( i, e ) { 68 | var editor_id = $( this ).attr( 'id' ); 69 | 70 | tinymce.execCommand( 'mceRemoveEditor', false, editor_id ); 71 | 72 | var mceinit = scf_generate_mceinit( editor_id ); 73 | tinyMCEPreInit.mceInit[editor_id] = mceinit; 74 | 75 | var qtinit = scf_generate_qtinit( editor_id ); 76 | tinyMCEPreInit.qtInit[editor_id] = qtinit; 77 | if ( typeof quicktags !== 'undefined' ) { 78 | quicktags( qtinit ); 79 | QTags._buttonsInit(); 80 | } 81 | } ); 82 | } ); 83 | 84 | /** 85 | * ドロップしたときに発火。 86 | * wysiwyg エディター用のテキストエリアを wysiwyg 化する。 87 | */ 88 | $( document ).on( 'smart-cf-repeat-table-sortable-stop', function( e, ui ) { 89 | $( ui ).find( '.smart-cf-wp-editor' ).each( function( i, e ) { 90 | var editor_id = $( this ).attr( 'id' ); 91 | 92 | var mceinit = scf_generate_mceinit( editor_id ); 93 | tinyMCEPreInit.mceInit[editor_id] = mceinit; 94 | if ( typeof tinymce !== 'undefined' ) { 95 | tinymce.init( mceinit ); 96 | } 97 | 98 | var qtinit = scf_generate_qtinit( editor_id ); 99 | tinyMCEPreInit.qtInit[editor_id] = qtinit; 100 | if ( typeof quicktags !== 'undefined' ) { 101 | quicktags( qtinit ); 102 | QTags._buttonsInit(); 103 | } 104 | } ); 105 | } ); 106 | 107 | function initialize_editor( wrap, editor_id ) { 108 | wrap.attr( 'id', 'wp-' + editor_id + '-wrap' ); 109 | wrap.find( 'a.add_media' ).attr( 'data-editor', editor_id ); 110 | wrap.find( '.switch-tmce' ) 111 | .attr( 'data-wp-editor-id', editor_id ) 112 | .attr( 'id', editor_id + '-tmce' ); 113 | wrap.find( '.switch-html' ) 114 | .attr( 'data-wp-editor-id', editor_id ) 115 | .attr( 'id', editor_id + '-html' ); 116 | wrap.find( '.quicktags-toolbar' ).attr( 'id', 'qt_' + editor_id + '_toolbar' ); 117 | } 118 | 119 | function scf_generate_mceinit( editor_id ) { 120 | var mceinit; 121 | if ( typeof tinyMCEPreInit.mceInit.content !== 'undefined' ) { 122 | mceinit = $.extend( true, {}, tinyMCEPreInit.mceInit.content ); 123 | mceinit.selector = '#' + editor_id; 124 | } else { 125 | mceinit = { 126 | content_css: ['../wp-includes/js/tinymce/skins/wordpress/wp-content.css', '../wp-content/plugins/smart-custom-fields/css/wysiwyg.css'], 127 | menubar: false, 128 | plugins: "hr,wplink,fullscreen,wordpress,textcolor,paste,charmap,lists", 129 | toolbar1: "bold,italic,strikethrough,bullist,numlist,blockquote,hr,alignleft,aligncenter,alignright,link,unlink,wp_more,spellchecker,wp_adv,fullscreen", 130 | toolbar2: "formatselect,underline,alignjustify,forecolor,pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help,code", 131 | convert_urls: false, 132 | theme: "modern", 133 | skin: "lightgray", 134 | wp_autoresize_on: true, 135 | wpautop: true, 136 | selector: '#' + editor_id 137 | }; 138 | } 139 | return mceinit; 140 | } 141 | 142 | function scf_generate_qtinit( editor_id ) { 143 | var qtinit; 144 | if ( typeof tinyMCEPreInit.qtInit.content !== 'undefined' ) { 145 | qtinit = $.extend( true, {}, tinyMCEPreInit.qtInit.content ); 146 | qtinit.id = editor_id; 147 | } else { 148 | qtinit = { 149 | id: editor_id, 150 | buttons: "strong,em,link,block,del,ins,img,ul,ol,li,code,more,close" 151 | } 152 | } 153 | return qtinit; 154 | } 155 | } ); 156 | } ); 157 | -------------------------------------------------------------------------------- /js/editor.js: -------------------------------------------------------------------------------- 1 | jQuery( function( $ ) { 2 | 3 | $( '.smart-cf-meta-box' ).each( function( i, e ) { 4 | var wrapper = $( e ); 5 | var btn_add_repeat_group = wrapper.find( '.btn-add-repeat-group' ); 6 | var btn_remove_repeat_group = wrapper.find( '.btn-remove-repeat-group' ); 7 | var table_class = '.smart-cf-meta-box-table'; 8 | var cnt = wrapper.find( table_class ).length; 9 | 10 | /** 11 | * グループ追加ボタン 12 | */ 13 | btn_add_repeat_group.click( function( e ) { 14 | cnt ++; 15 | var parent = $( this ).parents( '.smart-cf-meta-box-repeat-tables' ); 16 | add_repeat_group( $( this ) ); 17 | } ); 18 | 19 | /** 20 | * グループ削除ボタン 21 | */ 22 | btn_remove_repeat_group.click( function() { 23 | var table = $( this ).parents( table_class ); 24 | table.fadeOut( 'fast', function() { 25 | $( this ).remove(); 26 | } ); 27 | var tables = $( this ).parents( '.smart-cf-meta-box-repeat-tables' ); 28 | if ( tables.find( table_class ).length === 2 ) { 29 | cnt ++; 30 | add_repeat_group( $( this ) ); 31 | } 32 | } ); 33 | 34 | function add_repeat_group( button ) { 35 | var tables = button.parents( '.smart-cf-meta-box-repeat-tables' ); 36 | var table = tables.find( table_class ).first(); 37 | var clone = table.clone( true, true ).hide(); 38 | 39 | clone.find( 'input, select, textarea' ).each( function( i, e ) { 40 | var name = $( this ).attr( 'name' ); 41 | if ( name ) { 42 | $( this ).attr( 'name', 43 | name.replace( 44 | /^(smart-custom-fields\[.+?\])\[\]/, 45 | '$1[' + cnt + ']' 46 | ) 47 | ); 48 | $( this ).removeAttr( 'disabled' ); 49 | } 50 | } ); 51 | 52 | clone.find( '.smart-cf-datetime_picker' ).addClass( 'add' ); 53 | 54 | button.parent().after( clone.fadeIn( 'fast' ) ); 55 | button.trigger( 'smart-cf-after-add-group', { button: button, clone: clone} ); 56 | } 57 | 58 | /** 59 | * 画像アップローダー 60 | */ 61 | wrapper.find( '.btn-add-image' ).click( function( e ) { 62 | e.preventDefault(); 63 | var custom_uploader_image; 64 | var upload_button = $( this ); 65 | if ( custom_uploader_image ) { 66 | custom_uploader_image.open(); 67 | return; 68 | } 69 | 70 | wp.media.view.Modal.prototype.on( 'ready', function(){ 71 | $( 'select.attachment-filters' ) 72 | .find( '[value="uploaded"]' ) 73 | .attr( 'selected', true ) 74 | .parent() 75 | .trigger( 'change' ); 76 | } ); 77 | 78 | custom_uploader_image = wp.media( { 79 | button : { 80 | text: smart_cf_uploader.image_uploader_title 81 | }, 82 | states: [ 83 | new wp.media.controller.Library({ 84 | title : smart_cf_uploader.image_uploader_title, 85 | library : wp.media.query( { type: 'image' } ), 86 | multiple : false, 87 | filterable: 'uploaded' 88 | }) 89 | ] 90 | } ); 91 | 92 | custom_uploader_image.on( 'select', function() { 93 | var images = custom_uploader_image.state().get( 'selection' ); 94 | images.each( function( file ){ 95 | var sizes = file.get('sizes'); 96 | var image_area = upload_button.parent().find( '.smart-cf-upload-image' ); 97 | var sizename = image_area.data('size'); 98 | var img = sizes[ sizename ] || sizes.full; 99 | var alt_attr = file.get('title'); 100 | image_area.find( 'img' ).remove(); 101 | image_area.prepend( 102 | '' + alt_attr + '' 103 | ); 104 | image_area.removeClass( 'hide' ); 105 | upload_button.parent().find( 'input[type="hidden"]' ).val( file.toJSON().id ); 106 | } ); 107 | } ); 108 | 109 | custom_uploader_image.open(); 110 | } ); 111 | 112 | /** 113 | * 画像削除ボタン 114 | */ 115 | wrapper.find( '.smart-cf-upload-image' ).hover( function() { 116 | $( this ).find( '.btn-remove-image' ).fadeIn( 'fast', function() { 117 | $( this ).removeClass( 'hide' ); 118 | } ); 119 | }, function() { 120 | $( this ).find( '.btn-remove-image' ).fadeOut( 'fast', function() { 121 | $( this ).addClass( 'hide' ); 122 | } ); 123 | } ); 124 | wrapper.find( '.btn-remove-image' ).click( function() { 125 | $( this ).parent().find( 'img' ).remove(); 126 | $( this ).parent().siblings( 'input[type="hidden"]' ).val( '' ); 127 | $( this ).parent().addClass( 'hide' ); 128 | } ); 129 | 130 | /** 131 | * ファイルアップローダー 132 | */ 133 | wrapper.find( '.btn-add-file' ).click( function( e ) { 134 | e.preventDefault(); 135 | var custom_uploader_file; 136 | var upload_button = $( this ); 137 | if ( custom_uploader_file ) { 138 | custom_uploader_file.open(); 139 | return; 140 | } 141 | custom_uploader_file = wp.media( { 142 | title : smart_cf_uploader.file_uploader_title, 143 | button: { 144 | text: smart_cf_uploader.file_uploader_title 145 | }, 146 | multiple: false 147 | } ); 148 | 149 | custom_uploader_file.on( 'select', function() { 150 | var images = custom_uploader_file.state().get( 'selection' ); 151 | images.each( function( file ){ 152 | var image_area = upload_button.parent().find( '.smart-cf-upload-file' ); 153 | var alt_attr = file.get('title'); 154 | image_area.find( 'a' ).remove(); 155 | image_area.prepend( 156 | '' + alt_attr + '' + file.toJSON().filename + '' 157 | ); 158 | image_area.removeClass( 'hide' ); 159 | upload_button.parent().find( 'input[type="hidden"]' ).val( file.toJSON().id ); 160 | } ); 161 | } ); 162 | 163 | custom_uploader_file.open(); 164 | } ); 165 | 166 | /** 167 | * ファイル削除ボタン 168 | */ 169 | wrapper.find( '.smart-cf-upload-file' ).hover( function() { 170 | $( this ).find( '.btn-remove-file' ).fadeIn( 'fast', function() { 171 | $( this ).removeClass( 'hide' ); 172 | } ); 173 | }, function() { 174 | $( this ).find( '.btn-remove-file' ).fadeOut( 'fast', function() { 175 | $( this ).addClass( 'hide' ); 176 | } ); 177 | } ); 178 | wrapper.find( '.btn-remove-file' ).click( function() { 179 | $( this ).parent().find( 'img' ).remove(); 180 | $( this ).parent().siblings( 'input[type="hidden"]' ).val( '' ); 181 | $( this ).parent().addClass( 'hide' ); 182 | } ); 183 | 184 | /** 185 | * sortable 186 | */ 187 | wrapper.find( '.smart-cf-meta-box-repeat-tables' ).sortable( { 188 | handle: '.smart-cf-icon-handle', 189 | items : '> .smart-cf-meta-box-table:not( :first-child )', 190 | start : function( e, ui ) { 191 | $( this ).trigger( 'smart-cf-repeat-table-sortable-start', ui.item ); 192 | }, 193 | stop : function( e, ui ) { 194 | $( this ).trigger( 'smart-cf-repeat-table-sortable-stop', ui.item ); 195 | }, 196 | } ); 197 | 198 | } ); 199 | } ); 200 | -------------------------------------------------------------------------------- /js/settings-colorpicker.js: -------------------------------------------------------------------------------- 1 | jQuery( function( $ ) { 2 | $( document ).on( 'smart-cf-setting-field-open', function( e, options ) { 3 | if ( $( options ).hasClass( 'smart-cf-field-options-colorpicker' ) ) { 4 | $( options ).find( '.default-option' ).each( function( i, e ) { 5 | $( e ).wpColorPicker(); 6 | } ); 7 | } 8 | } ); 9 | $( document ).on( 'smart-cf-setting-show-options', function( e, options ) { 10 | if ( $( options ).hasClass( 'smart-cf-field-options-colorpicker' ) ) { 11 | $( options ).find( '.default-option' ).each( function( i, e ) { 12 | $( e ).wpColorPicker(); 13 | } ); 14 | } 15 | } ); 16 | } ); 17 | -------------------------------------------------------------------------------- /js/settings-datepicker.js: -------------------------------------------------------------------------------- 1 | jQuery( function( $ ) { 2 | $( document ).on( 'smart-cf-setting-field-open', function( e, options ) { 3 | if ( $( options ).hasClass( 'smart-cf-field-options-datepicker' ) ) { 4 | $( options ).find( '.default-option' ).each( function( i, e ) { 5 | $( e ).datepicker( $( e ).data( 'js' ) ); 6 | } ); 7 | } 8 | } ); 9 | $( document ).on( 'smart-cf-setting-show-options', function( e, options ) { 10 | if ( $( options ).hasClass( 'smart-cf-field-options-datepicker' ) ) { 11 | $( options ).find( '.default-option' ).each( function( i, e ) { 12 | $( e ).datepicker( $( e ).data( 'js' ) ); 13 | } ); 14 | } 15 | } ); 16 | } ); 17 | -------------------------------------------------------------------------------- /js/settings-datetime-picker.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('DOMContentLoaded', function() { 2 | var el = document.querySelector('.smart-cf-datetime_picker'); 3 | 4 | if (el) { 5 | var data = el.getAttribute('data-js'); 6 | data = JSON.parse(data); 7 | data['enableTime'] = true; 8 | } 9 | 10 | flatpickr('.smart-cf-datetime_picker', data); 11 | }); 12 | -------------------------------------------------------------------------------- /js/yoast-seo-analysis.js: -------------------------------------------------------------------------------- 1 | jQuery( function( $ ) { 2 | 3 | $(document).ready(function(e) { 4 | 5 | // if is Page or Post continue... 6 | if( $('body').hasClass('post-php') && typeof YoastSEO !== "undefined" && typeof SCFYoastSEOAnalysis == "undefined" ){ 7 | 8 | /** 9 | * Set up the SCF Yoast SEO Analysis plugin 10 | */ 11 | var SCFYoastSEOAnalysis = function() { 12 | 13 | console.log('SCFYoastSEOAnalysis'); 14 | 15 | YoastSEO.app.registerPlugin('SCFYoastSEOAnalysis', {status: 'ready'}); 16 | 17 | /** 18 | * @param modification {string} The name of the filter 19 | * @param callable {function} The callable 20 | * @param pluginName {string} The plugin that is registering the modification. 21 | * @param priority {number} (optional) Used to specify the order in which the callables 22 | * associated with a particular filter are called. Lower numbers 23 | * correspond with earlier execution. 24 | */ 25 | YoastSEO.app.registerModification('content', this.addScfFieldsToContent, 'SCFYoastSEOAnalysis', 5); 26 | 27 | this.analysisTimeout = 0; 28 | this.bindListeners(); 29 | 30 | // Re-analyse SEO score 31 | $('.btn-add-repeat-group, .btn-remove-image').on('click', this.bindListeners); 32 | if (wp.media) wp.media.view.Modal.prototype.on('close', function() { 33 | window.setTimeout( function() { YoastSEO.app.pluginReloaded('SCFYoastSEOAnalysis'); }, 200 ); 34 | }); 35 | 36 | }; 37 | 38 | /** 39 | * Bind listeners to text fields (input, textarea and wysiwyg) 40 | */ 41 | SCFYoastSEOAnalysis.prototype.bindListeners = function() { 42 | 43 | console.log('bindListeners'); 44 | 45 | SCFYoastSEOAnalysis.analysisTimeout = window.setTimeout( function() { YoastSEO.app.pluginReloaded('SCFYoastSEOAnalysis'); }, 200 ); 46 | 47 | $('#post-body, #edittag').find('input[type="text"][name^="smart-custom-fields"], textarea[name^="smart-custom-fields"], .smart-cf-field-type-wysiwyg iframe body#tinymce').on('keyup paste cut blur focus change', function() { 48 | 49 | if ( SCFYoastSEOAnalysis.analysisTimeout ) { 50 | window.clearTimeout(SCFYoastSEOAnalysis.analysisTimeout); 51 | } 52 | }); 53 | 54 | }; 55 | 56 | /** 57 | * Adds some text to the data... 58 | * 59 | * @param data The data to modify 60 | */ 61 | SCFYoastSEOAnalysis.prototype.addScfFieldsToContent = function(data) { 62 | console.log('addScfFieldsToContent'); 63 | 64 | var scf_content = ' '; 65 | 66 | $('#post-body, #edittag').find('input[type="text"][name^="smart-custom-fields"], textarea[name^="smart-custom-fields"]').each(function() { 67 | scf_content += ' ' + $(this).val(); 68 | }); 69 | 70 | $(".smart-cf-field-type-wysiwyg iframe").contents().find("body#tinymce").each(function() { 71 | scf_content += ' ' + $(this).html(); 72 | }); 73 | 74 | $('#post-body, #edittag').find('.smart-cf-upload-image img').each(function() { 75 | scf_content += '' + $(this).attr('alt') + ''; 76 | }); 77 | 78 | data = data + scf_content; 79 | 80 | return data.trim(); 81 | }; 82 | 83 | new SCFYoastSEOAnalysis(); 84 | } 85 | 86 | }); 87 | 88 | }); 89 | -------------------------------------------------------------------------------- /languages/smart-custom-fields-ja.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inc2734/smart-custom-fields/2de9335232b25056bce9ecedb564867d9850d8e8/languages/smart-custom-fields-ja.mo -------------------------------------------------------------------------------- /languages/smart-custom-fields-pt_BR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inc2734/smart-custom-fields/2de9335232b25056bce9ecedb564867d9850d8e8/languages/smart-custom-fields-pt_BR.mo -------------------------------------------------------------------------------- /languages/smart-custom-fields.pot: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2018 Smart Custom Fields 2 | # This file is distributed under the same license as the Smart Custom Fields package. 3 | #, fuzzy 4 | msgid "" 5 | msgstr "" 6 | "Project-Id-Version: Smart Custom Fields 3.1.7\n" 7 | "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/smart-custom-" 8 | "fields\n" 9 | "POT-Creation-Date: 2018-07-14 22:36-0300\n" 10 | "MIME-Version: 1.0\n" 11 | "Content-Type: text/plain; charset=UTF-8\n" 12 | "Content-Transfer-Encoding: 8bit\n" 13 | "PO-Revision-Date: 2018-MO-DA HO:MI+ZONE\n" 14 | "Last-Translator: FULL NAME \n" 15 | "Language-Team: Smart Custom Fields \n" 16 | "X-Generator: Poedit 2.0.9\n" 17 | "X-Poedit-SourceCharset: UTF-8\n" 18 | "X-Poedit-KeywordsList: esc_html__;__;_n;_x;_n_noop;_e\n" 19 | "X-Poedit-Basepath: ..\n" 20 | "X-Poedit-SearchPath-0: .\n" 21 | 22 | #: classes/controller/class.controller-base.php:46 23 | msgid "Image setting" 24 | msgstr "" 25 | 26 | #: classes/controller/class.controller-base.php:47 27 | msgid "File setting" 28 | msgstr "" 29 | 30 | #: classes/controller/class.profile.php:43 31 | #: classes/controller/class.settings.php:162 32 | msgid "Custom Fields" 33 | msgstr "" 34 | 35 | #: classes/controller/class.settings.php:145 36 | msgid "Same name exists!" 37 | msgstr "" 38 | 39 | #: classes/controller/class.settings.php:146 40 | msgid "Type to search a post or page" 41 | msgstr "" 42 | 43 | #: classes/controller/class.settings.php:147 44 | msgid "Loading..." 45 | msgstr "" 46 | 47 | #: classes/controller/class.settings.php:148 48 | #: classes/fields/class.field-related-posts.php:215 49 | #: classes/fields/class.field-related-terms.php:213 50 | msgid "Load more" 51 | msgstr "" 52 | 53 | #: classes/controller/class.settings.php:168 54 | msgid "Display conditions ( Post )" 55 | msgstr "" 56 | 57 | #: classes/controller/class.settings.php:175 58 | msgid "Display conditions ( Profile )" 59 | msgstr "" 60 | 61 | #: classes/controller/class.settings.php:182 62 | msgid "Display conditions ( Taxonomy )" 63 | msgstr "" 64 | 65 | #: classes/controller/class.settings.php:189 66 | msgid "Display conditions ( Options page )" 67 | msgstr "" 68 | 69 | #: classes/controller/class.settings.php:318 70 | msgid "Post Types" 71 | msgstr "" 72 | 73 | #: classes/controller/class.settings.php:367 74 | msgid "Post or Page Ids" 75 | msgstr "" 76 | 77 | #: classes/controller/class.settings.php:398 78 | msgid "Roles" 79 | msgstr "" 80 | 81 | #: classes/controller/class.settings.php:424 82 | msgid "Taxonomies" 83 | msgstr "" 84 | 85 | #: classes/controller/class.settings.php:448 86 | msgid "Options pages" 87 | msgstr "" 88 | 89 | #: classes/fields/class.field-boolean.php:23 90 | msgid "Boolean" 91 | msgstr "" 92 | 93 | #: classes/fields/class.field-boolean.php:38 94 | msgid "Yes" 95 | msgstr "" 96 | 97 | #: classes/fields/class.field-boolean.php:39 98 | msgid "No" 99 | msgstr "" 100 | 101 | #: classes/fields/class.field-check.php:21 102 | msgid "Check" 103 | msgstr "" 104 | 105 | #: classes/fields/class.field-check.php:103 106 | #: classes/fields/class.field-radio.php:102 107 | msgid "horizontal" 108 | msgstr "" 109 | 110 | #: classes/fields/class.field-check.php:104 111 | #: classes/fields/class.field-radio.php:103 112 | msgid "vertical" 113 | msgstr "" 114 | 115 | #: classes/fields/class.field-colorpicker.php:29 116 | msgid "Color picker" 117 | msgstr "" 118 | 119 | #: classes/fields/class.field-datepicker.php:29 120 | msgid "Date picker" 121 | msgstr "" 122 | 123 | #: classes/fields/class.field-file.php:21 124 | msgid "File" 125 | msgstr "" 126 | 127 | #: classes/fields/class.field-file.php:51 128 | #: classes/fields/class.field-image.php:52 129 | msgid "Delete" 130 | msgstr "" 131 | 132 | #: classes/fields/class.field-file.php:100 133 | msgid "File Select" 134 | msgstr "" 135 | 136 | #: classes/fields/class.field-image.php:21 137 | msgid "Image" 138 | msgstr "" 139 | 140 | #: classes/fields/class.field-image.php:94 141 | msgid "Image Select" 142 | msgstr "" 143 | 144 | #: classes/fields/class.field-message.php:21 145 | msgid "Message" 146 | msgstr "" 147 | 148 | #: classes/fields/class.field-radio.php:21 149 | msgid "Radio" 150 | msgstr "" 151 | 152 | #: classes/fields/class.field-related-posts.php:24 153 | msgid "Related Posts" 154 | msgstr "" 155 | 156 | #: classes/fields/class.field-related-terms.php:24 157 | msgid "Related Terms" 158 | msgstr "" 159 | 160 | #: classes/fields/class.field-select.php:21 161 | msgid "Select" 162 | msgstr "" 163 | 164 | #: classes/fields/class.field-text.php:21 165 | #: classes/fields/class.field-wysiwyg.php:108 166 | msgid "Text" 167 | msgstr "" 168 | 169 | #: classes/fields/class.field-textarea.php:21 170 | msgid "Textarea" 171 | msgstr "" 172 | 173 | #: classes/fields/class.field-wysiwyg.php:26 174 | msgid "Wysiwyg" 175 | msgstr "" 176 | 177 | #: classes/fields/class.field-wysiwyg.php:107 178 | msgid "Visual" 179 | msgstr "" 180 | 181 | #: classes/fields/class.field-wysiwyg.php:163 182 | msgid "Add Media" 183 | msgstr "" 184 | 185 | #: classes/models/class.revisions.php:128 smart-custom-fields.php:174 186 | #: smart-custom-fields.php:175 smart-custom-fields.php:176 187 | msgid "Smart Custom Fields" 188 | msgstr "" 189 | 190 | #: smart-custom-fields.php:177 smart-custom-fields.php:178 191 | #: smart-custom-fields.php:224 smart-custom-fields.php:225 192 | msgid "Add New" 193 | msgstr "" 194 | 195 | #: smart-custom-fields.php:179 196 | msgid "New Field" 197 | msgstr "" 198 | 199 | #: smart-custom-fields.php:180 200 | msgid "Edit Field" 201 | msgstr "" 202 | 203 | #: smart-custom-fields.php:181 204 | msgid "View Field" 205 | msgstr "" 206 | 207 | #: smart-custom-fields.php:182 208 | msgid "All Fields" 209 | msgstr "" 210 | 211 | #: smart-custom-fields.php:183 212 | msgid "Search Fields" 213 | msgstr "" 214 | 215 | #: smart-custom-fields.php:184 216 | msgid "Parent Fields:" 217 | msgstr "" 218 | 219 | #: smart-custom-fields.php:185 220 | msgid "No Fields found." 221 | msgstr "" 222 | 223 | #: smart-custom-fields.php:186 224 | msgid "No Fields found in Trash." 225 | msgstr "" 226 | -------------------------------------------------------------------------------- /libs/iosCheckbox/README.md: -------------------------------------------------------------------------------- 1 | iosCheckbox.js 2 | ============== 3 | 4 | A jQuery plugin that transform any checkbox element into a beautiful ios style checkbox. 5 | 6 | ![alt tag](http://s15.postimg.org/gbyj9pzk7/ios_Checbox.png) 7 | 8 | Demo: http://jsfiddle.net/bttkc3jg/31/ 9 | 10 | Demo Alternative Theme: http://jsfiddle.net/5xzevfq7/9/ 11 | 12 | Usage: 13 | 14 | Include the css 15 | 16 | ```html 17 | 18 | ``` 19 | 20 | Add some checkboxs to your page 21 | 22 | ```html 23 | 24 | 25 | ``` 26 | 27 | Load jQuery and iosCheckbox 28 | 29 | ```html 30 | 31 | 32 | ``` 33 | 34 | Transform all checkboxs with the class of `ios` 35 | 36 | ```html 37 | 42 | ``` 43 | 44 | We also have a Zepto based version thanks to [LeoUnglaub](https://github.com/LeoUnglaub) you can find it in [here](https://bitbucket.org/foxship/ioscheckbox.js) 45 | -------------------------------------------------------------------------------- /libs/iosCheckbox/iosCheckbox.css: -------------------------------------------------------------------------------- 1 | .ios-ui-select{ 2 | background: #dddddd; 3 | border: none; 4 | height: 36px; 5 | background: #dddddd; 6 | -webkit-border-radius: 18px; 7 | border-radius: 18px; 8 | width: 60px; 9 | -webkit-transition: all 0.3s ease-in-out; 10 | -moz-transition: all 0.3s ease-in-out; 11 | -ms-transition: all 0.3s ease-in-out; 12 | -o-transition: all 0.3s ease-in-out; 13 | transition: all 0.3s ease-in-out; 14 | -webkit-box-shadow: none; 15 | box-shadow: none; 16 | cursor: pointer; 17 | position: relative; 18 | display: inline-block; 19 | } 20 | .ios-ui-select.checked{ 21 | -webkit-box-shadow: inset 0 0 0 36px #6ddc5f; 22 | box-shadow: inset 0 0 0 36px #6ddc5f; 23 | } 24 | .ios-ui-select.checked .inner{ 25 | left: 27px; 26 | } 27 | .ios-ui-select .inner{ 28 | width: 30px; 29 | height: 30px; 30 | position: absolute; 31 | top: 3px; 32 | left: 3px; 33 | -webkit-border-radius: 100%; 34 | border-radius: 100%; 35 | background: white; 36 | -webkit-transition: all 350ms cubic-bezier(0, 0.89, 0.44, 1); 37 | -moz-transition: all 350ms cubic-bezier(0, 0.89, 0.44, 1); 38 | -o-transition: all 350ms cubic-bezier(0, 0.89, 0.44, 1); 39 | transition: all 350ms cubic-bezier(0, 0.89, 0.44, 1); 40 | -webkit-box-shadow: 0 1px 2px 0 rgba(0,0,0,0.2),0 3px 4px 0 rgba(0,0,0,0.1); 41 | box-shadow: 0 1px 2px 0 rgba(0,0,0,0.2),0 3px 4px 0 rgba(0,0,0,0.1); 42 | } 43 | 44 | /* Alternative Theme */ 45 | /* ---------------- */ 46 | /* 47 | .ios-ui-select{ 48 | border-color: #d1d1d1; 49 | width: 28px; 50 | height: 28px; 51 | -webkit-border-radius: 100%; 52 | border-radius: 100%; 53 | opacity: 1; 54 | -webkit-box-shadow: inset 0 0 0 2px #d6e0e6; 55 | box-shadow: inset 0 0 0 2px #d6e0e6; 56 | width: 22px; 57 | z-index: 2; 58 | text-align: center; 59 | display: inline-block; 60 | cursor: pointer; 61 | height: 22px; 62 | -webkit-border-radius: 18px; 63 | border-radius: 18px; 64 | -webkit-transition: all 350ms cubic-bezier(0, 0.89, 0.44, 1); 65 | -moz-transition: all 350ms cubic-bezier(0, 0.89, 0.44, 1); 66 | -o-transition: all 350ms cubic-bezier(0, 0.89, 0.44, 1); 67 | transition: all 350ms cubic-bezier(0, 0.89, 0.44, 1); 68 | text-indent: -9999px; 69 | display: inline-block; 70 | } 71 | .ios-ui-select.checked { 72 | -webkit-box-shadow: inset 0 0 0 14px #4ad337; 73 | box-shadow: inset 0 0 0 14px #4ad337; 74 | opacity: 1 !important; 75 | } 76 | .ios-ui-select.checked .inner{ 77 | -moz-transform: scale(1); 78 | -webkit-transform: scale(1); 79 | -o-transform: scale(1); 80 | -ms-transform: scale(1); 81 | transform: scale(1); 82 | } 83 | .ios-ui-select .inner{ 84 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAQAAADa613fAAAC70lEQVR42u3bPWgUQRgG4N0kxpjCYJFCFBVRCyFg0PgD/oAiKpGgAUEwhVhoI4I2FoIpxDSmCBZqIYopRMEUWiSIiilEBEEwKCgHRgwqKsIhxngQ89qYkMu9iTuzs7N74Z0rb+bbe/Z2Z+b79i5EMDtaRSCIIIIIIogggggiiCCCCCKIIIIIIogggggyWyE15Q+ZF3QF+WAkeB20GI1Dtl616Md4G0Nr9JHZYlSjD5PbIMJyhFSiB1Pb8qijs3OPhMH1oDXGPZyRbyPEFZS2j6got0urE6y1ldvN3k4Z7SYxssA4RRmdZlHSZxzDGGFcjj7xZgPShj+E0W3KSBuyH6OE0YNK81hpMnajQBi9qLaJlh5jG4YJ4zFq7eKlxdiAPGE8w3zbiOkwGvCdMAawwD5mGoxV+EIYb1AfJ6p/xjIMEcY7LI4X1zdjEXKEMYQVcSObda9CE9ahyvpw9XhFGF+xOv4pMuncjE//Ntd7rA5WhxeEkccaF9919K6Nk5avAvZaZONPCeMnNrq5aKN3vVX0AX5hu9GBavCIMEyjOIHkSs7lJoOiwj3CKKDZ3TQSvetLcnU3Riwq3CaMURxwOR9G79phOd+EuEZGjuGw24ndZM6xWwEu0vzvuOsVyqTzUromD864JndQxmn3S61Z95V0l/R22l3SGco4l8SeIcl96wnK6Epm82M+ZP00mUTdlH5HaFHhqnk2ntymcSvN7fqLcruDNBu/aZONJ7n73UWz7b6JbLuFvn8Xc5LbV9sO3DdD/WMHfpP3HtgVFZLPRw5RSjc20wvviW1RwUdidZTezqzg9rxkKsgUJMBJRGkD8bJxP6nu2f8ycljoI4mOH+LCjIwPWOKnGuDiWdOlaRmf4xcVfFZRQtygjG9o8FefcfU89g5Ju5p8FprcPSHvLWIMY4vfipnL3yw8nGCMYKfvCqbLYHNxHu/xA/ex1n9FOdQfKgURRBBBBBFEEEEEEUQQQQQRRBBBBBFEEEHG21/sNjJ4iVKmQwAAAABJRU5ErkJggg==) center center no-repeat; 85 | background-size: 100%; 86 | width: 100%; 87 | height: 100%; 88 | content: ''; 89 | -webkit-transition: all 350ms cubic-bezier(0, 0.89, 0.44, 1); 90 | -moz-transition: all 350ms cubic-bezier(0, 0.89, 0.44, 1); 91 | -o-transition: all 350ms cubic-bezier(0, 0.89, 0.44, 1); 92 | transition: all 350ms cubic-bezier(0, 0.89, 0.44, 1); 93 | -moz-transform: scale(0); 94 | -webkit-transform: scale(0); 95 | -o-transform: scale(0); 96 | -ms-transform: scale(0); 97 | transform: scale(0); 98 | } 99 | */ 100 | -------------------------------------------------------------------------------- /libs/iosCheckbox/iosCheckbox.js: -------------------------------------------------------------------------------- 1 | /** 2 | * iosCheckbox.js 3 | * Version: 1.0.0 4 | * Author: Ron Masas 5 | */ 6 | (function($) { 7 | $.fn.extend({ 8 | iosCheckbox: function() { 9 | this.destroy = function(){ 10 | $(this).each(function() { 11 | $(this).next('.ios-ui-select').remove(); 12 | }); 13 | }; 14 | 15 | if ($(this).attr('data-ios-checkbox') === 'true') { 16 | return; 17 | } 18 | 19 | $(this).attr('data-ios-checkbox', 'true'); 20 | 21 | $(this).each(function() { 22 | /** 23 | * Original checkbox element 24 | */ 25 | var org_checkbox = $(this); 26 | /** 27 | * iOS checkbox div 28 | */ 29 | var ios_checkbox = jQuery("
    ", { 30 | class: 'ios-ui-select' 31 | }).append(jQuery("
    ", { 32 | class: 'inner' 33 | })); 34 | 35 | // If the original checkbox is checked, add checked class to the ios checkbox. 36 | if (org_checkbox.is(":checked")) { 37 | ios_checkbox.addClass("checked"); 38 | } 39 | 40 | // Hide the original checkbox and print the new one. 41 | org_checkbox.hide().after(ios_checkbox); 42 | 43 | if (org_checkbox.is(":disabled")){ 44 | // In case the original checkbox is disabled don't register the click event. 45 | return ios_checkbox.css('opacity','0.6'); 46 | } 47 | 48 | // Add click event listener to the ios checkbox 49 | ios_checkbox.click(function() { 50 | // Toggel the check state 51 | ios_checkbox.toggleClass("checked"); 52 | // Check if the ios checkbox is checked 53 | if (ios_checkbox.hasClass("checked")) { 54 | // Update state 55 | org_checkbox.prop('checked', true); 56 | } else { 57 | // Update state 58 | org_checkbox.prop('checked', false); 59 | } 60 | 61 | // Run click even in case it was registered to the original checkbox element. 62 | org_checkbox.click(); 63 | }); 64 | }); 65 | return this; 66 | } 67 | }); 68 | })(jQuery); 69 | -------------------------------------------------------------------------------- /libs/iosCheckbox/iosCheckbox.min.css: -------------------------------------------------------------------------------- 1 | .ios-ui-select{border:none;height:36px;background:#ddd;-webkit-border-radius:18px;border-radius:18px;width:60px;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out;-webkit-box-shadow:none;box-shadow:none;cursor:pointer;position:relative;display:inline-block}.ios-ui-select.checked{-webkit-box-shadow:inset 0 0 0 36px #6ddc5f;box-shadow:inset 0 0 0 36px #6ddc5f}.ios-ui-select.checked .inner{left:27px}.ios-ui-select .inner{width:30px;height:30px;position:absolute;top:3px;left:3px;-webkit-border-radius:100%;border-radius:100%;background:#fff;-webkit-transition:all 350ms cubic-bezier(0,.89,.44,1);-moz-transition:all 350ms cubic-bezier(0,.89,.44,1);-o-transition:all 350ms cubic-bezier(0,.89,.44,1);transition:all 350ms cubic-bezier(0,.89,.44,1);-webkit-box-shadow:0 1px 2px 0 rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.1);box-shadow:0 1px 2px 0 rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.1)} -------------------------------------------------------------------------------- /libs/iosCheckbox/iosCheckbox.min.js: -------------------------------------------------------------------------------- 1 | !function(e){e.fn.extend({iosCheckbox:function(){if(this.destroy=function(){e(this).each(function(){e(this).next(".ios-ui-select").remove()})},"true"!==e(this).attr("data-ios-checkbox"))return e(this).attr("data-ios-checkbox","true"),e(this).each(function(){var c=e(this),i=jQuery("
    ",{class:"ios-ui-select"}).append(jQuery("
    ",{class:"inner"}));if(c.is(":checked")&&i.addClass("checked"),c.hide().after(i),c.is(":disabled"))return i.css("opacity","0.6");i.click(function(){i.toggleClass("checked"),i.hasClass("checked")?c.prop("checked",!0):c.prop("checked",!1),c.click()})}),this}})}(jQuery); 2 | -------------------------------------------------------------------------------- /libs/selectivity-3.1.0/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## 3.1.0 4 | 5 | - Add `data` property to `change` events. 6 | - Don't crash when some, but not all, result items have children (#227, thanks to @watsab). 7 | - Trim template results to avoid runtime errors (#210, thanks to @darekzak). 8 | - Fix clear button if item text is too long (#211, thanks to @dmarchuk). 9 | - React: Don't use `componentWillReceiveProps()` for forward compatibility with React 17. 10 | 11 | ## 3.0.6 12 | 13 | - Fix updating event listeners after initial render in React API. 14 | - Rerender single-value inputs when their enabled state changes. 15 | 16 | ## 3.0.5 17 | 18 | - Fix issue where dropdown is hard to close on Firefox (#194, thanks to @dmarchuk). 19 | - Filter selected children from results (#201, thanks to @ne0guille). 20 | - Move submenu up if otherwise it would fall below the fold of the page. 21 | 22 | ## 3.0.4 23 | 24 | - Improved compatibility with React 15.5 (no more deprecation warnings). 25 | - Improved HTML5 validation support (#188, thanks to @r4z3c). 26 | - Fix #180: Existing selection highlighted by default on multi-value search results (thanks to 27 | @ahamid). 28 | - Fix #177: Don't close dropdown when clicking scrollbar (thanks to @JEkedorff). 29 | 30 | ## 3.0.3 31 | 32 | - Fix issue when a single-value Selectivity input is reset to null throught the React API. 33 | 34 | ## 3.0.2 35 | 36 | - Fix #161: React API: Value should be re-set when the items change. 37 | 38 | ## 3.0.1 39 | 40 | - Fix #156: Don't crash when unsubscribing from non-subscribed event listener. 41 | - Don't rely on `react-dom-server` in React templates plugin to avoid issues with React 15.4. 42 | - Fix #158: Expose Selectivity object as `$.Selectivity` in jQuery builds. 43 | - Yarn compatibility: Get rid of peerDependencies. 44 | 45 | ## 3.0.0 46 | 47 | - Made jQuery dependency fully optional. 48 | - As a result, all callbacks that received jQuery containers as argument(s) now receive plain 49 | DOM nodes instead. 50 | - Added optional React API. 51 | - Fix #128: Added NPM package. 52 | - Added options: 53 | - `shouldOpenSubmenu()` - Callback that determines whether a submenu should be opened. 54 | - `selectable` - Allows to make items unselectable without having to disable them. This is 55 | mainly useful for items that trigger submenus. 56 | - Removed Bower and Component support. 57 | - Moved option validation into its own plugin. 58 | - Introduced the `"selectivity-change"` event. It's exactly the same as the `"change"` event 59 | (which is still supported as well) from version 2, but with the added benefit it cannot be 60 | confused with `"change"` events that bubble from internal `` elements. The React API's 61 | `onChange` property uses the new event. 62 | - Rewrote the AJAX plugin: 63 | - It now relies on the `fetch()` method for performing AJAX requests. This method is only 64 | available on modern browsers, so you'll need a polyfill if you want to use this with old 65 | browsers, unless you're using a jQuery build in which case the `jquery/ajax` plugin can 66 | provide a shim based on `$.ajax()` (requires jQuery 3.0 or higher). 67 | - Please check the documentation for the new options that can be passed. 68 | - Renamed the option `suppressMouseWheelSelector` to just `suppressWheelSelector`. 69 | - Renamed the `Selectivity.InputTypes` map to `Selectivity.Inputs`. 70 | - Removed dist directory from the repository. 71 | - Improved submenu positioning by automatically opening them on the left-hand side if there's 72 | insufficient space on the right side. 73 | - Improve searching behavior with multiple submenus open. 74 | - Fix #107: Remove the dropdown after timeout to fix "hover" behavior. 75 | - Fix #136: Update original `` element now uses "s9y\_" prefix for its ID (thanks 82 | to @dr-itz). 83 | - Fix: Provide correct offset in pagination when results are filtered. 84 | 85 | ## 2.1.0 86 | 87 | - Implemented `disabled` property on items. When an item is disabled it cannot be selected and by 88 | default is rendered with grey text. 89 | - PR #63: Fix problem with `closeOnSelect` behavior. 90 | - PR #80: Added CSS classes for `hover` and `open` states. 91 | - Fix #66: Respect `removeOnly` option when set after initialization. 92 | - Fix #67: Pass `queryOptions` to `url` function in AJAX module. 93 | - Fix #75: Make sure Enter key doesn't submit forms. 94 | - Fix #93: Make the rerenderSelection() method public and document that `triggerChange: false` 95 | doesn't automatically update the UI. 96 | - Fixed issue where the cursor position was constantly reset when using a tokenizer. 97 | - Miscellaneous smaller fixes and styling tweaks. 98 | 99 | ## 2.0.0 100 | -------------------------------------------------------------------------------- /libs/selectivity-3.1.0/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2016 Arend van Beelen jr. 4 | (c) 2016 Speakap BV 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /libs/selectivity-3.1.0/selectivity-jquery.css: -------------------------------------------------------------------------------- 1 | /** 2 | * All CSS that comes with Selectivity.js can be used as is, or tweaked to your heart's content :) 3 | * 4 | * Please realize though there is no "API contract" regarding styling of CSS classes, meaning that 5 | * any customized CSS made may need to be updated without warning if you want to upgrade the 6 | * Selectivity version you use. You can mitigate this problem by using your own templates instead of 7 | * those defined in src/templates.js, since templates will at the very least continue working across 8 | * patch versions and any changes necessary to templates will be documented in the changelog. 9 | */ 10 | .selectivity-clearfix { 11 | clear: both; } 12 | 13 | .selectivity-input { 14 | display: inline-block; 15 | width: 250px; } 16 | .selectivity-input select { 17 | display: none; } 18 | 19 | .selectivity-input:focus { 20 | outline: none; } 21 | 22 | .selectivity-placeholder { 23 | color: #999; } 24 | 25 | /** 26 | * Dropdown 27 | */ 28 | .selectivity-dropdown { 29 | background: #fff; 30 | border-radius: 4px; 31 | -webkit-box-shadow: 0 1px 5px 1px rgba(0, 0, 0, 0.15), 0 10px 16px 0 rgba(0, 0, 0, 0.2); 32 | box-shadow: 0 1px 5px 1px rgba(0, 0, 0, 0.15), 0 10px 16px 0 rgba(0, 0, 0, 0.2); 33 | position: fixed; 34 | z-index: 1046; } 35 | 36 | .selectivity-search-input-container { 37 | border-bottom: 1px solid #eee; } 38 | 39 | .selectivity-search-input { 40 | background: transparent; 41 | border: 0; 42 | outline: 0; 43 | width: 100%; } 44 | 45 | .selectivity-results-container { 46 | max-height: 28em; 47 | overflow: auto; 48 | position: relative; } 49 | 50 | .selectivity-load-more, 51 | .selectivity-result-item { 52 | cursor: pointer; 53 | padding: 7px; } 54 | 55 | .selectivity-result-children .selectivity-result-item { 56 | padding-left: 17px; } 57 | 58 | .selectivity-load-more.highlight, 59 | .selectivity-result-item.highlight { 60 | background: #4484c7; 61 | color: #fff; } 62 | 63 | .selectivity-result-item.disabled { 64 | cursor: default; 65 | color: #999; } 66 | 67 | .selectivity-result-item:first-child { 68 | border-radius: 4px 4px 0 0; } 69 | 70 | .selectivity-dropdown.has-search-input .selectivity-result-item:first-child { 71 | border-radius: 0; } 72 | 73 | .selectivity-result-label { 74 | font-weight: bold; } 75 | 76 | .selectivity-load-more, 77 | .selectivity-result-item:last-child, 78 | .selectivity-result-children:last-child .selectivity-result-item:last-child { 79 | border-radius: 0 0 4px 4px; } 80 | 81 | .selectivity-result-children .selectivity-result-item:last-child { 82 | border-radius: 0; } 83 | 84 | .selectivity-error, 85 | .selectivity-loading, 86 | .selectivity-search-input-container, 87 | .selectivity-result-label { 88 | padding: 7px; } 89 | 90 | /** 91 | * Multi-selection input 92 | */ 93 | .selectivity-multiple-input-container { 94 | background: #eee; 95 | border-radius: 2px; 96 | cursor: text; 97 | max-height: 10em; 98 | min-height: calc(2em + 4px); 99 | overflow: auto; 100 | padding: 5px; } 101 | 102 | .selectivity-multiple-input-container .selectivity-placeholder { 103 | height: calc(2em + 4px); 104 | line-height: calc(2em + 4px); } 105 | 106 | .selectivity-multiple-input, 107 | input[type='text'].selectivity-multiple-input { 108 | background-color: transparent; 109 | border: none; 110 | float: left; 111 | font: inherit; 112 | height: calc(2em + 4px); 113 | max-width: 100%; 114 | outline: 0; 115 | padding: 0; } 116 | .selectivity-multiple-input:focus, 117 | input[type='text'].selectivity-multiple-input:focus { 118 | background-color: transparent; 119 | -webkit-box-shadow: none; 120 | box-shadow: none; 121 | outline: none; } 122 | 123 | .selectivity-multiple-input::-ms-clear { 124 | display: none; } 125 | 126 | .selectivity-multiple-selected-item { 127 | background: #4484c7; 128 | border-radius: 3px; 129 | color: #fff; 130 | cursor: default; 131 | float: left; 132 | line-height: 2em; 133 | margin: 2px; 134 | padding: 0 5px; 135 | position: relative; 136 | -moz-user-select: none; 137 | -ms-user-select: none; 138 | -webkit-user-select: none; 139 | user-select: none; 140 | white-space: nowrap; } 141 | .selectivity-multiple-selected-item.highlighted { 142 | background-color: #ccc; } 143 | 144 | .selectivity-multiple-selected-item-remove { 145 | color: #fff; 146 | cursor: pointer; 147 | margin-left: -5px; 148 | padding: 5px; } 149 | 150 | /** 151 | * Single-selection input 152 | */ 153 | .selectivity-single-select { 154 | background: #eee; 155 | border-radius: 2px; 156 | cursor: pointer; 157 | min-height: 2em; 158 | padding: 5px; 159 | position: relative; 160 | -webkit-box-sizing: content-box; 161 | box-sizing: content-box; } 162 | 163 | .selectivity-single-select-input { 164 | opacity: 0; } 165 | 166 | .selectivity-single-result-container { 167 | position: absolute; 168 | top: 0.8em; 169 | right: 15px; 170 | left: 5px; 171 | overflow: hidden; 172 | -o-text-overflow: ellipsis; 173 | text-overflow: ellipsis; 174 | white-space: nowrap; } 175 | 176 | .selectivity-single-selected-item { 177 | color: #000; } 178 | 179 | .selectivity-single-selected-item-remove { 180 | color: #000; 181 | float: right; 182 | padding: 0 5px; 183 | position: relative; 184 | z-index: 1; } 185 | 186 | .selectivity-caret { 187 | position: absolute; 188 | right: 5px; 189 | top: 0.7em; } 190 | 191 | @media only screen and (max-device-width: 480px) { 192 | .selectivity-single-select { 193 | background: #eee; 194 | border-radius: 2px; } 195 | 196 | .selectivity-single-result-container { 197 | right: 5px; } 198 | 199 | .selectivity-caret { 200 | display: none; } } 201 | /** 202 | * Submenu 203 | */ 204 | .selectivity-submenu-icon { 205 | position: absolute; 206 | right: 4px; } 207 | -------------------------------------------------------------------------------- /libs/selectivity-3.1.0/selectivity-jquery.min.css: -------------------------------------------------------------------------------- 1 | .selectivity-clearfix{clear:both}.selectivity-input{display:inline-block;width:250px}.selectivity-input select{display:none}.selectivity-input:focus{outline:0}.selectivity-placeholder{color:#999}.selectivity-dropdown{background:#fff;border-radius:4px;-webkit-box-shadow:0 1px 5px 1px rgba(0,0,0,.15),0 10px 16px 0 rgba(0,0,0,.2);box-shadow:0 1px 5px 1px rgba(0,0,0,.15),0 10px 16px 0 rgba(0,0,0,.2);position:fixed;z-index:1046}.selectivity-search-input-container{border-bottom:1px solid #eee}.selectivity-search-input{background:0 0;border:0;outline:0;width:100%}.selectivity-results-container{max-height:28em;overflow:auto;position:relative}.selectivity-load-more,.selectivity-result-item{cursor:pointer;padding:7px}.selectivity-result-children .selectivity-result-item{padding-left:17px}.selectivity-load-more.highlight,.selectivity-result-item.highlight{background:#4484c7;color:#fff}.selectivity-result-item.disabled{cursor:default;color:#999}.selectivity-result-item:first-child{border-radius:4px 4px 0 0}.selectivity-dropdown.has-search-input .selectivity-result-item:first-child{border-radius:0}.selectivity-result-label{font-weight:700}.selectivity-load-more,.selectivity-result-children:last-child .selectivity-result-item:last-child,.selectivity-result-item:last-child{border-radius:0 0 4px 4px}.selectivity-result-children .selectivity-result-item:last-child{border-radius:0}.selectivity-error,.selectivity-loading,.selectivity-result-label,.selectivity-search-input-container{padding:7px}.selectivity-multiple-input-container{background:#eee;border-radius:2px;cursor:text;max-height:10em;min-height:calc(2em + 4px);overflow:auto;padding:5px}.selectivity-multiple-input-container .selectivity-placeholder{height:calc(2em + 4px);line-height:calc(2em + 4px)}.selectivity-multiple-input,input[type=text].selectivity-multiple-input{background-color:transparent;border:0;float:left;font:inherit;height:calc(2em + 4px);max-width:100%;outline:0;padding:0}.selectivity-multiple-input:focus,input[type=text].selectivity-multiple-input:focus{background-color:transparent;-webkit-box-shadow:none;box-shadow:none;outline:0}.selectivity-multiple-input::-ms-clear{display:none}.selectivity-multiple-selected-item{background:#4484c7;border-radius:3px;color:#fff;cursor:default;float:left;line-height:2em;margin:2px;padding:0 5px;position:relative;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;white-space:nowrap}.selectivity-multiple-selected-item.highlighted{background-color:#ccc}.selectivity-multiple-selected-item-remove{color:#fff;cursor:pointer;margin-left:-5px;padding:5px}.selectivity-single-select{background:#eee;border-radius:2px;cursor:pointer;min-height:2em;padding:5px;position:relative;-webkit-box-sizing:content-box;box-sizing:content-box}.selectivity-single-select-input{opacity:0}.selectivity-single-result-container{position:absolute;top:.8em;right:15px;left:5px;overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap}.selectivity-single-selected-item{color:#000}.selectivity-single-selected-item-remove{color:#000;float:right;padding:0 5px;position:relative;z-index:1}.selectivity-caret{position:absolute;right:5px;top:.7em}@media only screen and (max-device-width:480px){.selectivity-single-select{background:#eee;border-radius:2px}.selectivity-single-result-container{right:5px}.selectivity-caret{display:none}}.selectivity-submenu-icon{position:absolute;right:4px} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "engines": { 3 | "node": ">=20.10.0", 4 | "npm": ">=10.2.3" 5 | }, 6 | "volta": { 7 | "node": "20.11.1" 8 | }, 9 | "devDependencies": { 10 | "@wordpress/env": "9.5.0", 11 | "npm-run-all": "^4.1.5", 12 | "rimraf": "^5.0.5" 13 | }, 14 | "scripts": { 15 | "export:wp-content:themes": "npm run cli cp -- -r wp-content/themes .export/wp-content", 16 | "export:wp-content:uploads": "npm run cli cp -- -r wp-content/uploads .export/wp-content", 17 | "export:wp-content": "rimraf .export/wp-content && mkdir -p .export/wp-content/uploads && run-p export:wp-content:*", 18 | "export:db": "mkdir -p .export/sql && npm run wp db -- export .export/sql/local.sql", 19 | "export": "run-p export:*", 20 | "import:wp-content:themes": "npm run cli cp -- -r .export/wp-content/themes wp-content", 21 | "import:wp-content:uploads": "npm run cli cp -- -r .export/wp-content/uploads wp-content", 22 | "import:wp-content": "run-p import:wp-content:*", 23 | "import:db": "npm run wp db -- import .export/sql/local.sql", 24 | "import": "run-p import:*", 25 | "wp-env": "wp-env", 26 | "start": "wp-env start && open http://localhost:8888", 27 | "stop": "npm run export && wp-env stop", 28 | "cli": "wp-env run cli", 29 | "wp": "wp-env run --env-cwd=wp-content/plugins/smart-custom-fields cli wp", 30 | "composer": "wp-env run --env-cwd=wp-content/plugins/smart-custom-fields cli composer", 31 | "pretest": "wp-env start && npm run composer install -- --no-interaction", 32 | "test:lint:php": "npm run composer lint", 33 | "test:lint": "run-s test:lint:*", 34 | "test:unit:php": "wp-env start && wp-env run --env-cwd=\"wp-content/plugins/smart-custom-fields\" tests-wordpress vendor/bin/phpunit -c .phpunit.xml.dist --verbose", 35 | "test:unit": "run-s test:unit:*", 36 | "test": "run-s test:*", 37 | "clean:zip": "rimraf smart-custom-fields.zip", 38 | "zip:pack": "rsync -a --exclude='/bin' --exclude='/vendor' --exclude='/node_modules' --exclude='.*' --exclude='*.ruleset.xml' --exclude='*.config.js' --exclude='*.xml.dist' --exclude='/tests' --exclude='package*.json' --exclude='/smart-custom-fields.zip' ./ smart-custom-fields", 39 | "zip:archive": "zip -9 -qmr smart-custom-fields.zip smart-custom-fields", 40 | "zip": "npm run clean:zip && npm run zip:pack && wp-env start && npm run composer install -- --no-dev -d smart-custom-fields && npm run zip:archive" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | get_error_message(); 61 | } 62 | 63 | // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped 64 | throw new Exception( 'WordPress died: ' . $message ); 65 | } 66 | tests_add_filter( 'wp_die_handler', 'fail_if_died' ); 67 | 68 | $GLOBALS['wp_tests_options'] = array( 69 | 'gutenberg-experiments' => array( 70 | 'gutenberg-widget-experiments' => '1', 71 | ), 72 | ); 73 | 74 | // Start up the WP testing environment. 75 | require $_tests_dir . '/includes/bootstrap.php'; 76 | 77 | // Use existing behavior for wp_die during actual test execution. 78 | remove_filter( 'wp_die_handler', 'fail_if_died' ); 79 | -------------------------------------------------------------------------------- /tests/test-smart-custom-fields-ajax.php: -------------------------------------------------------------------------------- 1 | Ajax = new Smart_Custom_Fields_Ajax(); 15 | 16 | $Cache = Smart_Custom_Fields_Cache::get_instance(); 17 | $Cache->flush(); 18 | } 19 | 20 | /** 21 | * Tear down. 22 | */ 23 | public function tear_down() { 24 | parent::tear_down(); 25 | $Cache = Smart_Custom_Fields_Cache::get_instance(); 26 | $Cache->flush(); 27 | } 28 | 29 | /** 30 | * @group delete_term 31 | */ 32 | public function test_delete_term() { 33 | $taxonomy = 'category'; 34 | $term_id = $this->factory->term->create( array( 'taxonomy' => $taxonomy ) ); 35 | $term = get_term( $term_id, $taxonomy ); 36 | $Meta = new Smart_Custom_Fields_Meta( $term ); 37 | 38 | $Meta->add( 'text', 'text' ); 39 | $this->Ajax->delete_term( $term_id, '', $taxonomy, $term ); 40 | $this->assertSame( array(), $Meta->get( 'text' ) ); 41 | } 42 | 43 | /** 44 | * Register custom fields using filter hook. 45 | * 46 | * @param array $settings Array of Smart_Custom_Fields_Setting object. 47 | * @param string $type Post type or Role. 48 | * @param int $id Post ID or User ID. 49 | * @param string $meta_type post or user. 50 | */ 51 | public function _register( $settings, $type, $id, $meta_type ) { 52 | if ( type === 'category' ) { 53 | $Setting = SCF::add_setting( 'id-1', 'Register Test' ); 54 | $Setting->add_group( 55 | 0, 56 | false, 57 | array( 58 | array( 59 | 'name' => 'text', 60 | 'label' => 'text field', 61 | 'type' => 'text', 62 | ), 63 | ) 64 | ); 65 | $settings[ $Setting->get_id() ] = $Setting; 66 | } 67 | return $settings; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/test-smart-custom-fields-controller-base.php: -------------------------------------------------------------------------------- 1 | post_id = $this->factory->post->create( 22 | array( 23 | 'post_type' => 'post', 24 | 'post_status' => 'publish', 25 | ) 26 | ); 27 | 28 | // The auto draft post for custom fields 29 | $this->new_post_id = $this->factory->post->create( 30 | array( 31 | 'post_type' => 'post', 32 | 'post_status' => 'auto-draft', 33 | ) 34 | ); 35 | 36 | add_filter( 'smart-cf-register-fields', array( $this, '_register' ), 10, 4 ); 37 | 38 | require_once plugin_dir_path( __FILE__ ) . '../classes/controller/class.controller-base.php'; 39 | $this->Controller = new Smart_Custom_Fields_Controller_Base(); 40 | 41 | $Cache = Smart_Custom_Fields_Cache::get_instance(); 42 | $Cache->flush(); 43 | } 44 | 45 | /** 46 | * Tear down. 47 | */ 48 | public function tear_down() { 49 | parent::tear_down(); 50 | $Cache = Smart_Custom_Fields_Cache::get_instance(); 51 | $Cache->flush(); 52 | } 53 | 54 | /** 55 | * @group get_multiple_data_field_value 56 | */ 57 | public function test_get_multiple_data_field_value() { 58 | // When $index is null 59 | $object = get_post( $this->post_id ); 60 | $Field = SCF::get_field( $object, 'checkbox-has-default' ); 61 | $this->assertSame( array( 'a' ), $this->Controller->get_multiple_data_field_value( $object, $Field, null ) ); 62 | $Field = SCF::get_field( $object, 'checkbox' ); 63 | $this->assertSame( array(), $this->Controller->get_multiple_data_field_value( $object, $Field, null ) ); 64 | 65 | // When isn't saved meta data. At that time ,$index is ignored. 66 | $object = get_post( $this->new_post_id ); 67 | $Field = SCF::get_field( $object, 'checkbox-has-default' ); 68 | $this->assertSame( array( 'a' ), $this->Controller->get_multiple_data_field_value( $object, $Field, 0 ) ); 69 | $Field = SCF::get_field( $object, 'checkbox' ); 70 | $this->assertSame( array(), $this->Controller->get_multiple_data_field_value( $object, $Field, 0 ) ); 71 | } 72 | 73 | /** 74 | * @group get_multiple_data_field_value 75 | */ 76 | public function test_get_multiple_data_field_value__saved() { 77 | $object = get_post( $this->post_id ); 78 | $Meta = new Smart_Custom_Fields_Meta( $object ); 79 | $Field = SCF::get_field( $object, 'checkbox-has-default' ); 80 | $Meta->add( 'checkbox-has-default', 'a' ); 81 | $Meta->add( 'checkbox-has-default', 'b' ); 82 | $this->assertSame( array( 'a', 'b' ), $this->Controller->get_multiple_data_field_value( $object, $Field, 0 ) ); 83 | $Field = SCF::get_field( $object, 'checkbox' ); 84 | $Meta->add( 'checkbox', 'a' ); 85 | $Meta->add( 'checkbox', 'b' ); 86 | $this->assertSame( array( 'a', 'b' ), $this->Controller->get_multiple_data_field_value( $object, $Field, 0 ) ); 87 | } 88 | 89 | /** 90 | * @group get_multiple_data_field_value 91 | */ 92 | public function test_get_multiple_data_field_value__saved_multi() { 93 | $object = get_post( $this->post_id ); 94 | $Meta = new Smart_Custom_Fields_Meta( $object ); 95 | $Field = SCF::get_field( $object, 'repeat-checkbox' ); 96 | $POST = array( 97 | SCF_Config::NAME => array( 98 | 'repeat-checkbox' => array( 99 | array(), 100 | array( 'a', 'b' ), 101 | array( 'b', 'c' ), 102 | ), 103 | ), 104 | ); 105 | $Meta->save( $POST ); 106 | $this->assertSame( array(), $this->Controller->get_multiple_data_field_value( $object, $Field, 0 ) ); 107 | $this->assertSame( array( 'a', 'b' ), $this->Controller->get_multiple_data_field_value( $object, $Field, 1 ) ); 108 | } 109 | 110 | /** 111 | * @group get_single_data_field_value 112 | */ 113 | public function test_get_single_data_field_value() { 114 | // When $index is null 115 | $object = get_post( $this->post_id ); 116 | $Field = SCF::get_field( $object, 'text-has-default' ); 117 | $this->assertSame( 'a', $this->Controller->get_single_data_field_value( $object, $Field, null ) ); 118 | $Field = SCF::get_field( $object, 'text' ); 119 | $this->assertSame( '', $this->Controller->get_single_data_field_value( $object, $Field, null ) ); 120 | 121 | // When isn't saved meta data. At that time ,$index is ignored. 122 | $object = get_post( $this->new_post_id ); 123 | $Field = SCF::get_field( $object, 'text-has-default' ); 124 | $this->assertSame( 'a', $this->Controller->get_single_data_field_value( $object, $Field, 0 ) ); 125 | $Field = SCF::get_field( $object, 'text' ); 126 | $this->assertSame( '', $this->Controller->get_single_data_field_value( $object, $Field, 0 ) ); 127 | } 128 | 129 | /** 130 | * @group get_single_data_field_value 131 | */ 132 | public function test_get_single_data_field_value__saved() { 133 | $object = get_post( $this->post_id ); 134 | $Meta = new Smart_Custom_Fields_Meta( $object ); 135 | $Field = SCF::get_field( $object, 'text-has-default' ); 136 | $Meta->add( 'text-has-default', 'b' ); 137 | $Meta->add( 'text-has-default', 'c' ); 138 | $this->assertSame( 'b', $this->Controller->get_single_data_field_value( $object, $Field, 0 ) ); 139 | $this->assertSame( 'c', $this->Controller->get_single_data_field_value( $object, $Field, 1 ) ); 140 | 141 | $Field = SCF::get_field( $object, 'text' ); 142 | $Meta->add( 'text', 'b' ); 143 | $Meta->add( 'text', 'c' ); 144 | $this->assertSame( 'b', $this->Controller->get_single_data_field_value( $object, $Field, 0 ) ); 145 | $this->assertSame( 'c', $this->Controller->get_single_data_field_value( $object, $Field, 1 ) ); 146 | } 147 | 148 | /** 149 | * Register custom fields using filter hook 150 | * 151 | * @param array $settings Array of Smart_Custom_Fields_Setting object. 152 | * @param string $type Post type or Role. 153 | * @param int $id Post ID or User ID. 154 | * @param string $meta_type post or user. 155 | */ 156 | public function _register( $settings, $type, $id, $meta_type ) { 157 | if ( 158 | ( 'post' === $type && $id === $this->post_id ) || 159 | ( 'post' === $type && $id === $this->new_post_id ) || 160 | ( 'editor' === $type ) || 161 | ( 'category' === $type ) || 162 | ( 'option' === $meta_type && 'menu-slug' === $id ) 163 | ) { 164 | $Setting = SCF::add_setting( 'id-1', 'Register Test' ); 165 | $Setting->add_group( 166 | 0, 167 | false, 168 | array( 169 | array( 170 | 'name' => 'text', 171 | 'label' => 'text', 172 | 'type' => 'text', 173 | ), 174 | ) 175 | ); 176 | $Setting->add_group( 177 | 'text-has-default', 178 | false, 179 | array( 180 | array( 181 | 'name' => 'text-has-default', 182 | 'label' => 'text has default', 183 | 'type' => 'text', 184 | 'default' => 'a', 185 | ), 186 | ) 187 | ); 188 | $Setting->add_group( 189 | 'checkbox', 190 | false, 191 | array( 192 | array( 193 | 'name' => 'checkbox', 194 | 'label' => 'checkbox field', 195 | 'type' => 'check', 196 | 'choices' => array( 'a', 'b', 'c' ), 197 | ), 198 | ) 199 | ); 200 | $Setting->add_group( 201 | 'checkbox-has-default', 202 | false, 203 | array( 204 | array( 205 | 'name' => 'checkbox-has-default', 206 | 'label' => 'checkbox has default', 207 | 'type' => 'check', 208 | 'choices' => array( 'a', 'b', 'c' ), 209 | 'default' => array( 'a' ), 210 | ), 211 | ) 212 | ); 213 | $Setting->add_group( 214 | 'checkbox-key-value', 215 | false, 216 | array( 217 | array( 218 | 'name' => 'checkbox-key-value', 219 | 'label' => 'checkbox key value', 220 | 'type' => 'check', 221 | 'choices' => array( 222 | 'a' => 'apple', 223 | 'b' => 'banana', 224 | 'c' => 'carrot', 225 | ), 226 | 'default' => array( 'a' ), 227 | ), 228 | ) 229 | ); 230 | $Setting->add_group( 231 | 'group', 232 | true, 233 | array( 234 | array( 235 | 'name' => 'repeat-text', 236 | 'label' => 'repeat text', 237 | 'type' => 'text', 238 | ), 239 | array( 240 | 'name' => 'repeat-checkbox', 241 | 'label' => 'repeat checkbox', 242 | 'type' => 'check', 243 | 'choices' => array( 'a', 'b', 'c' ), 244 | ), 245 | ) 246 | ); 247 | $settings[ $Setting->get_id() ] = $Setting; 248 | } 249 | return $settings; 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /tests/test-smart-custom-fields-revision.php: -------------------------------------------------------------------------------- 1 | Revision = new Smart_Custom_Fields_Revisions(); 26 | 27 | // The post for custom fields 28 | $this->post_id = $this->factory->post->create( 29 | array( 30 | 'post_type' => 'post', 31 | 'post_status' => 'publish', 32 | ) 33 | ); 34 | 35 | // The revision post for custom fields 36 | $this->revision_id = $this->factory->post->create( 37 | array( 38 | 'post_type' => 'revision', 39 | 'post_parent' => $this->post_id, 40 | 'post_status' => 'inherit', 41 | 'post_name' => $this->post_id . '-autosave-v1', 42 | ) 43 | ); 44 | 45 | add_filter( 'smart-cf-register-fields', array( $this, '_register' ), 10, 4 ); 46 | 47 | $Cache = Smart_Custom_Fields_Cache::get_instance(); 48 | $Cache->flush(); 49 | } 50 | 51 | /** 52 | * Tear down. 53 | */ 54 | public function tear_down() { 55 | parent::tear_down(); 56 | $Cache = Smart_Custom_Fields_Cache::get_instance(); 57 | $Cache->flush(); 58 | } 59 | 60 | /** 61 | * @group wp_restore_post_revision 62 | */ 63 | public function test_wp_restore_post_revision() { 64 | // Meta data for the post 65 | add_post_meta( $this->post_id, 'text', 'text' ); 66 | add_post_meta( $this->post_id, 'checkbox', 1 ); 67 | 68 | // Meta data for the revision post 69 | add_metadata( 'post', $this->revision_id, 'text', 'text-revision' ); 70 | add_metadata( 'post', $this->revision_id, 'checkbox', 2 ); 71 | 72 | $this->assertEquals( 'text', get_post_meta( $this->post_id, 'text', true ) ); 73 | $this->assertEquals( array( 1 ), get_post_meta( $this->post_id, 'checkbox' ) ); 74 | 75 | $this->Revision->wp_restore_post_revision( $this->post_id, $this->revision_id ); 76 | 77 | $this->assertEquals( 'text-revision', get_post_meta( $this->post_id, 'text', true ) ); 78 | $this->assertEquals( array( 2 ), get_post_meta( $this->post_id, 'checkbox' ) ); 79 | } 80 | 81 | /** 82 | * @group wp_insert_post 83 | */ 84 | public function test_wp_insert_post() { 85 | $_REQUEST[ SCF_Config::PREFIX . 'fields-nonce' ] = wp_create_nonce( SCF_Config::NAME . '-fields' ); 86 | 87 | $_POST = array( 88 | SCF_Config::NAME => array( 89 | 'text' => array( 'text' ), 90 | ), 91 | ); 92 | $this->Revision->wp_insert_post( $this->revision_id ); 93 | $this->assertEquals( 'text', SCF::get( 'text', $this->revision_id ) ); 94 | 95 | $this->Revision->wp_insert_post( $this->post_id ); 96 | $this->assertEquals( '', SCF::get( 'text', $this->post_id ) ); 97 | } 98 | 99 | /** 100 | * @group get_post_metadata 101 | */ 102 | public function test_get_post_metadata() { 103 | update_metadata( 'post', $this->revision_id, 'text', 'text' ); 104 | 105 | $meta = $this->Revision->get_post_metadata( 'default-value', $this->post_id, 'text', true ); 106 | $this->assertEquals( 'default-value', $meta ); 107 | 108 | global $wp_query, $post; 109 | $wp_query->is_preview = true; 110 | $post = get_post( $this->post_id ); 111 | $meta = $this->Revision->get_post_metadata( 'default-value', $this->post_id, 'text', true ); 112 | $this->assertEquals( 'text', $meta ); 113 | } 114 | 115 | /** 116 | * Register custom fields using filter hook. 117 | * 118 | * @param array $settings Array of Smart_Custom_Fields_Setting object. 119 | * @param string $type Post type or Role. 120 | * @param int $id Post ID or User ID. 121 | * @param string $meta_type post or user. 122 | * @return array 123 | */ 124 | public function _register( $settings, $type, $id, $meta_type ) { 125 | if ( 'post' === $type && ( $id === $this->post_id || $id === $this->revision_id ) ) { 126 | $Setting = SCF::add_setting( 'id-1', 'Register Test' ); 127 | $Setting->add_group( 128 | 0, 129 | false, 130 | array( 131 | array( 132 | 'name' => 'text', 133 | 'label' => 'text', 134 | 'type' => 'text', 135 | ), 136 | ) 137 | ); 138 | $Setting->add_group( 139 | 'text-has-default', 140 | false, 141 | array( 142 | array( 143 | 'name' => 'text-has-default', 144 | 'label' => 'text has default', 145 | 'type' => 'text', 146 | 'default' => 'a', 147 | ), 148 | ) 149 | ); 150 | $Setting->add_group( 151 | 'checkbox', 152 | false, 153 | array( 154 | array( 155 | 'name' => 'checkbox', 156 | 'label' => 'checkbox field', 157 | 'type' => 'check', 158 | 'choices' => array( 'a', 'b', 'c' ), 159 | ), 160 | ) 161 | ); 162 | $Setting->add_group( 163 | 'checkbox-has-default', 164 | false, 165 | array( 166 | array( 167 | 'name' => 'checkbox-has-default', 168 | 'label' => 'checkbox has default', 169 | 'type' => 'check', 170 | 'choices' => array( 'a', 'b', 'c' ), 171 | 'default' => array( 'a' ), 172 | ), 173 | ) 174 | ); 175 | $Setting->add_group( 176 | 'checkbox-key-value', 177 | false, 178 | array( 179 | array( 180 | 'name' => 'checkbox-key-value', 181 | 'label' => 'checkbox key value', 182 | 'type' => 'check', 183 | 'choices' => array( 184 | 'a' => 'apple', 185 | 'b' => 'banana', 186 | 'c' => 'carrot', 187 | ), 188 | 'default' => array( 'a' ), 189 | ), 190 | ) 191 | ); 192 | $Setting->add_group( 193 | 'group', 194 | true, 195 | array( 196 | array( 197 | 'name' => 'repeat-text', 198 | 'label' => 'repeat text', 199 | 'type' => 'text', 200 | ), 201 | array( 202 | 'name' => 'repeat-checkbox', 203 | 'label' => 'repeat checkbox', 204 | 'type' => 'check', 205 | 'choices' => array( 'a', 'b', 'c' ), 206 | ), 207 | ) 208 | ); 209 | $settings[ $Setting->get_id() ] = $Setting; 210 | } 211 | return $settings; 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /tests/test-smart-custom-fields.php: -------------------------------------------------------------------------------- 1 | post_ids = $this->factory->post->create_many( 16 | 5, 17 | array( 18 | 'post_type' => SCF_Config::NAME, 19 | ) 20 | ); 21 | 22 | foreach ( $this->post_ids as $post_id ) { 23 | update_post_meta( $post_id, SCF_Config::PREFIX . 'repeat-multiple-data', 'dummy' ); 24 | } 25 | 26 | for ( $i = 1; $i <= 5; $i++ ) { 27 | update_option( SCF_Config::PREFIX . $i, 'dummy' ); 28 | } 29 | 30 | $Cache = Smart_Custom_Fields_Cache::get_instance(); 31 | $Cache->flush(); 32 | } 33 | 34 | /** 35 | * Tear down. 36 | */ 37 | public function tear_down() { 38 | parent::tear_down(); 39 | $Cache = Smart_Custom_Fields_Cache::get_instance(); 40 | $Cache->flush(); 41 | } 42 | 43 | /** 44 | * @group uninstall 45 | */ 46 | public function test_uninstall__post() { 47 | Smart_Custom_Fields::uninstall(); 48 | $posts = get_posts( 49 | array( 50 | 'post_type' => SCF_Config::NAME, 51 | 'posts_per_page' => -1, 52 | 'post_status' => 'any', 53 | ) 54 | ); 55 | $this->assertEquals( 0, count( $posts ) ); 56 | } 57 | 58 | /** 59 | * @group uninstall 60 | */ 61 | public function test_uninstall__repeat_multiple_data() { 62 | Smart_Custom_Fields::uninstall(); 63 | 64 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 65 | global $wpdb; 66 | $var = $wpdb->get_var( 67 | $wpdb->prepare( 68 | " 69 | SELECT count( * ) FROM $wpdb->postmeta 70 | WHERE meta_key = %s 71 | ", 72 | SCF_Config::PREFIX . 'repeat-multiple-data' 73 | ) 74 | ); 75 | // phpcs:enable 76 | 77 | $this->assertEquals( 0, $var ); 78 | } 79 | 80 | /** 81 | * @group uninstall 82 | */ 83 | public function test_uninstall__option() { 84 | Smart_Custom_Fields::uninstall(); 85 | 86 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 87 | global $wpdb; 88 | $var = $wpdb->get_var( 89 | $wpdb->prepare( 90 | " 91 | SELECT count( * ) FROM $wpdb->options 92 | WHERE option_name LIKE %s 93 | ", 94 | SCF_Config::PREFIX . '%' 95 | ) 96 | ); 97 | // phpcs:enable 98 | 99 | $this->assertEquals( 0, $var ); 100 | } 101 | } 102 | --------------------------------------------------------------------------------