base.php
3 weeks ago
exporter.php
3 weeks ago
helpers.php
3 weeks ago
resolver.php
3 weeks ago
updater.php
3 weeks ago
view.php
3 weeks ago
base.php
284 lines
| 1 | <?php |
| 2 | |
| 3 | namespace Wpae\AddonAPI; |
| 4 | |
| 5 | if ( ! defined( 'ABSPATH' ) ) exit; |
| 6 | |
| 7 | abstract class PMXE_Addon_Base { |
| 8 | use HasError; |
| 9 | |
| 10 | public $slug = 'not-implemented'; |
| 11 | public PMXE_Addon_View $view; |
| 12 | public PMXE_Addon_Exporter $exporter; |
| 13 | |
| 14 | // Extra fields created by the addon |
| 15 | public $fields = []; |
| 16 | |
| 17 | // Cast values to something else without having to create a custom field |
| 18 | public $casts = []; |
| 19 | |
| 20 | public function __construct() { |
| 21 | $this->preflight(); |
| 22 | $this->initEed(); |
| 23 | |
| 24 | $this->view = new PMXE_Addon_View( $this ); |
| 25 | $this->exporter = new PMXE_Addon_Exporter( $this ); |
| 26 | |
| 27 | // Register |
| 28 | |
| 29 | add_filter( "pmxe_addons", [ $this, 'register' ] ); |
| 30 | |
| 31 | // Data |
| 32 | add_filter( "pmxe_get_{$this->slug}_addon_meta_keys", [ $this, 'getExistingMetaKeys' ], 10, 1 ); |
| 33 | add_filter( "pmxe_get_{$this->slug}_addon_available_data", [ $this, 'getAvailableData' ], 10, 1 ); |
| 34 | add_filter( "pmxe_get_{$this->slug}_addon_fields_options", [ $this, 'getFieldOptions' ], 10, 2 ); |
| 35 | add_filter( "pmxe_get_{$this->slug}_addon_auto_generate_fields", [$this, 'getAutoGenerateFields']); |
| 36 | |
| 37 | // Render |
| 38 | add_action( "pmxe_render_{$this->slug}_addon", [ $this->view, 'render' ] ); |
| 39 | add_action( "pmxe_render_{$this->slug}_addon_filters", [ $this->view, 'filters' ] ); |
| 40 | add_action( "pmxe_render_{$this->slug}_addon_new_field", [ $this->view, 'newField' ] ); |
| 41 | |
| 42 | // Export |
| 43 | add_filter( "pmxe_{$this->slug}_addon_export_field", [ $this->exporter, 'run' ], 10, 11 ); |
| 44 | add_filter( "pmxe_{$this->slug}_addon_get_headers", [ $this->exporter, 'getHeaders' ], 10, 6 ); |
| 45 | add_filter( "wp_all_export_csv_rows", [ $this->exporter, "filterCsvRows" ], 10, 3 ); |
| 46 | add_filter( "pmxe_{$this->slug}_addon_override_import_template", [ $this, 'prepareImportTemplate' ], 99, 5 ); |
| 47 | } |
| 48 | |
| 49 | // Bulk Edit / Migrate |
| 50 | |
| 51 | /** |
| 52 | * @param array $templateOptions |
| 53 | * @param array $exportOptions |
| 54 | * @param string $name |
| 55 | * @param array $field |
| 56 | * @param string|bool $parent_delimiter |
| 57 | * |
| 58 | * @return array |
| 59 | */ |
| 60 | public function prepareImportTemplate( $templateOptions, $exportOptions, $name, $field, $parent_delimiter = false ) { |
| 61 | $field_tpl_key = ( preg_match( '/^[0-9]/', $name ) ) ? 'el_' . $name . '[1]' : $name . '[1]'; |
| 62 | $is_xml_template = $exportOptions['export_to'] == 'xml'; |
| 63 | $xpath_separator = $is_xml_template ? '/' : '_'; |
| 64 | |
| 65 | // Check if the addon groups key exists and if the current group ID is not already in the array |
| 66 | if ( ! in_array( $field['group_id'], $templateOptions[ $field['addon'] . '_groups' ] ) ) { |
| 67 | $templateOptions[ $field['addon'] . '_groups' ][] = $field['group_id']; |
| 68 | } |
| 69 | |
| 70 | $implode_delimiter = \XmlExportEngine::$implode; |
| 71 | |
| 72 | if ( ! empty( $parent_delimiter ) ) { |
| 73 | $implode_delimiter = ( $parent_delimiter == '|' ? ',' : '|' ); |
| 74 | } |
| 75 | |
| 76 | $field_class = getFieldClass( $field, $this->fields ); |
| 77 | $field_template = $field_class::getImportTemplate( $field, $name, $field_tpl_key, $implode_delimiter, $is_xml_template ); |
| 78 | $templateOptions[ $field['addon'] ][ $field['key'] ] = $field_template; |
| 79 | |
| 80 | if ( is_subclass_of( $field_class, '\Wpae\AddonAPI\PMXE_Addon_Switcher_Field' ) ) { |
| 81 | $templateOptions[ $field['addon'] . '_switchers' ][ $field['key'] ] = 'no'; |
| 82 | } |
| 83 | |
| 84 | return apply_filters("pmxe_get_{$this->slug}_addon_api_template_options_".$field['key'], $templateOptions); |
| 85 | |
| 86 | } |
| 87 | |
| 88 | /** |
| 89 | * Path to the plugin file relative to the plugins directory. |
| 90 | */ |
| 91 | public function getPluginPath() { |
| 92 | return $this->rootDir . '/plugin.php'; |
| 93 | } |
| 94 | |
| 95 | public function initEed() { |
| 96 | } |
| 97 | |
| 98 | /** |
| 99 | * Do stuff before the plugin is activated |
| 100 | * @return void |
| 101 | */ |
| 102 | public function preflight() { |
| 103 | $results = $this->canRun(); |
| 104 | |
| 105 | if ( is_wp_error( $results ) ) { |
| 106 | $this->showErrorAndDeactivate( $results->get_error_message() ); |
| 107 | |
| 108 | return; |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | // Getters |
| 113 | abstract public function name(): string; |
| 114 | |
| 115 | abstract public function description(): string; |
| 116 | |
| 117 | /** |
| 118 | * Determine if the plugin can run on the current site otherwise disable it. |
| 119 | * @return bool|\WP_Error |
| 120 | */ |
| 121 | abstract public function canRun(); |
| 122 | |
| 123 | /** |
| 124 | * Get fields by type |
| 125 | * |
| 126 | * @param array $types |
| 127 | * @param string|null $subtype |
| 128 | * |
| 129 | * @return mixed |
| 130 | */ |
| 131 | abstract public static function fields( array $types, ?string $subtype = null ); |
| 132 | |
| 133 | /** |
| 134 | * Get groups by type |
| 135 | * |
| 136 | * @param array $types |
| 137 | * |
| 138 | * @return mixed |
| 139 | */ |
| 140 | abstract public static function groups( array $types, ?string $subtype = null ); |
| 141 | |
| 142 | public function getGroupsByExportType() { |
| 143 | return static::groups( |
| 144 | \XmlExportEngine::$post_types, |
| 145 | \XmlExportEngine::$exportOptions['taxonomy_to_export'] |
| 146 | ); |
| 147 | } |
| 148 | |
| 149 | public function getFieldsByExportType() { |
| 150 | $fields = static::fields( |
| 151 | \XmlExportEngine::$post_types, |
| 152 | \XmlExportEngine::$exportOptions['taxonomy_to_export'] |
| 153 | ); |
| 154 | |
| 155 | return array_map( |
| 156 | fn( $field ) => array_merge( $field, [ |
| 157 | 'addon' => $this->slug, |
| 158 | 'subfields' => array_map( |
| 159 | fn( $subfield ) => array_merge( $subfield, [ |
| 160 | 'addon' => $this->slug, |
| 161 | ] ), |
| 162 | $field['subfields'] ?? [] |
| 163 | ), |
| 164 | ] ), |
| 165 | $fields |
| 166 | ); |
| 167 | } |
| 168 | |
| 169 | public function getFieldsByGroup( $group_id ) { |
| 170 | $fields = $this->getFieldsByExportType(); |
| 171 | |
| 172 | return array_values( |
| 173 | array_filter( $fields, function ( $field ) use ( $group_id ) { |
| 174 | return $field['group'] === $group_id; |
| 175 | } ) |
| 176 | ); |
| 177 | } |
| 178 | |
| 179 | public function register( $addons ) { |
| 180 | $addons[] = $this->slug; |
| 181 | |
| 182 | return $addons; |
| 183 | } |
| 184 | |
| 185 | public function getExistingMetaKeys( $existing_meta_keys = [] ) { |
| 186 | $fields = $this->getFieldsByExportType(); |
| 187 | $fields_keys = wp_list_pluck( $fields, 'key' ); |
| 188 | |
| 189 | // Remove addon fields so they don't show up in the Custom Fields dropdown. |
| 190 | foreach ( $existing_meta_keys as $key => $meta_key ) { |
| 191 | if ( in_array( $meta_key, $fields_keys ) ) { |
| 192 | unset( $existing_meta_keys[ $key ] ); |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | return $existing_meta_keys; |
| 197 | } |
| 198 | |
| 199 | public function getAvailableData( $available_data ) { |
| 200 | return $available_data; |
| 201 | } |
| 202 | |
| 203 | public function getAutoGenerateFields( $auto_generate ){ |
| 204 | // Default to including all addon fields when using Migrate. |
| 205 | $fields = $this->getFieldsByExportType(); |
| 206 | $fields_keys = wp_list_pluck( $fields, 'label' ); |
| 207 | return $this->getFieldOptions($auto_generate, $fields_keys); |
| 208 | } |
| 209 | |
| 210 | public function getFieldOptions( $fields, $field_keys = [] ) { |
| 211 | $groups = $this->getGroupsByExportType(); |
| 212 | |
| 213 | foreach ( $groups as $key => $group ) { |
| 214 | $group_fields = $this->getFieldsByGroup( $group['id'] ); |
| 215 | |
| 216 | foreach ( $group_fields as $field ) { |
| 217 | // Label is used because that's what's used in the Custom XML export. |
| 218 | $field_label = $field['label']; |
| 219 | |
| 220 | if ( ! in_array( $field_label, $field_keys )) { |
| 221 | continue; |
| 222 | } |
| 223 | |
| 224 | $fields['ids'][] = 1; // TODO: Why is this 1 everywhere? |
| 225 | $fields['cc_label'][] = $field['key']; |
| 226 | $fields['cc_php'][] = ''; |
| 227 | $fields['cc_code'][] = ''; |
| 228 | $fields['cc_sql'][] = ''; |
| 229 | $fields['cc_options'][] = serialize( array_merge( $field, [ 'group_id' => $group['id'] ] ) ); |
| 230 | $fields['cc_type'][] = $this->slug; |
| 231 | $fields['cc_value'][] = $field['key']; |
| 232 | $fields['cc_name'][] = $field['label']; |
| 233 | $fields['cc_settings'][] = ''; |
| 234 | $fields['cc_combine_multiple_fields'][] = ''; |
| 235 | $fields['cc_combine_multiple_fields_value'][] = ''; |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | return $fields; |
| 240 | } |
| 241 | |
| 242 | /* |
| 243 | * Get the field's value, either from the post meta or from the repeater row |
| 244 | */ |
| 245 | public function resolveFieldValue( PMXE_Addon_Field $field, $record, $recordId ) { |
| 246 | if ( $field->repeater_row_index !== null ) { |
| 247 | $rows = $field->parent->value; |
| 248 | |
| 249 | return $rows[ $field->repeater_row_index ][ $field->key ] ?? ''; |
| 250 | } |
| 251 | |
| 252 | return get_post_meta( $recordId, $field->key, true ); |
| 253 | } |
| 254 | |
| 255 | /** |
| 256 | * Potentially change the class of a field at runtime |
| 257 | * |
| 258 | * @param array $field |
| 259 | * @param class-string<PMXI_Addon_Field> $class |
| 260 | */ |
| 261 | public function resolveFieldClass( $field, $class ) { |
| 262 | return $class; |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | trait HasError { |
| 267 | public function showErrorAndDeactivate( string $msg ) { |
| 268 | if ( ! function_exists( 'get_plugins' ) ) { |
| 269 | require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
| 270 | } |
| 271 | |
| 272 | $notice = new \Wpae\WordPress\AdminErrorNotice( $msg ); |
| 273 | $notice->render(); |
| 274 | |
| 275 | deactivate_plugins( $this->getPluginPath() ); |
| 276 | } |
| 277 | |
| 278 | public function getMissingDependencyError( $pluginName, $pluginUrl ) { |
| 279 | return new \WP_Error( 'missing_dependency', |
| 280 | sprintf( "<b>%s Export Add-on Plugin</b>: <a target=\"_blank\" href=\"%s\">%s</a> must be installed", $this->name(), $pluginUrl, $pluginName ) |
| 281 | ); |
| 282 | } |
| 283 | } |
| 284 |