diff --git a/admin/class-h5p-library-admin.php b/admin/class-h5p-library-admin.php index 09c2529..a66d38e 100644 --- a/admin/class-h5p-library-admin.php +++ b/admin/class-h5p-library-admin.php @@ -201,6 +201,7 @@ private function display_libraries() { 'numContent' => $contents_count === 0 ? '' : $contents_count, 'numContentDependencies' => $usage['content'] < 1 ? '' : $usage['content'], 'numLibraryDependencies' => $usage['libraries'] === 0 ? '' : $usage['libraries'], + 'hasCircularEditorDepencendy' => $usage['hasCircularEditorDepencendy'], 'upgradeUrl' => $upgradeUrl, 'detailsUrl' => admin_url('admin.php?page=h5p_libraries&task=show&id=' . $library->id), 'deleteUrl' => admin_url('admin.php?page=h5p_libraries&task=delete&id=' . $library->id) @@ -304,7 +305,8 @@ public function process_libraries() { // Check if this library can be deleted $usage = $interface->getLibraryUsage($library->id, $interface->getNumNotFiltered() ? TRUE : FALSE); - if ($usage['content'] !== 0 || $usage['libraries'] !== 0) { + $delete_circular_editor_dependency = $usage['hasCircularEditorDepencendy'] && $usage['content'] === 0 && $usage['libraries'] === 1; + if (!$delete_circular_editor_dependency && ($usage['content'] !== 0 || $usage['libraries'] !== 0)) { H5P_Plugin_Admin::set_error(__('This Library is used by content or other libraries and can therefore not be deleted.', $this->plugin_slug)); return; // Nope } diff --git a/public/class-h5p-wordpress.php b/public/class-h5p-wordpress.php index c2f01f6..c186ea5 100644 --- a/public/class-h5p-wordpress.php +++ b/public/class-h5p-wordpress.php @@ -197,6 +197,34 @@ public function mayUpdateLibraries() { public function getLibraryUsage($id, $skipContent = FALSE) { global $wpdb; + /* + * There may be direct circular dependencies between a content type and its + * editor that might lead to a library not being deletable. Check all + * editor dependencies for only having a dependency to the library itself. + * No check vice versa, because deleting the editor for a content type + * would still allow to choose the content from the H5P Hub with the editor + * widget then missing. + */ + $editor_dependencies = $wpdb->get_col($wpdb->prepare( + "SELECT required_library_id + FROM {$wpdb->prefix}h5p_libraries_libraries + WHERE library_id = %d AND dependency_type = %s", + $id, 'editor' + )); + + $hasCircularEditorDependency = array_reduce($editor_dependencies, function ($isCircle, $editor_library_id) use ($id, $wpdb) { + if ($isCircle) { + return TRUE; // Found already + } + + return (intval($wpdb->get_var($wpdb->prepare( + "SELECT COUNT(*) + FROM {$wpdb->prefix}h5p_libraries_libraries + WHERE library_id = %d AND required_library_id = %d AND dependency_type = %s", + intval($editor_library_id), $id, 'preloaded' + ))) === 1); + }, FALSE); + return array( 'content' => $skipContent ? -1 : intval($wpdb->get_var($wpdb->prepare( "SELECT COUNT(distinct c.id) @@ -211,7 +239,8 @@ public function getLibraryUsage($id, $skipContent = FALSE) { FROM {$wpdb->prefix}h5p_libraries_libraries WHERE required_library_id = %d", $id) - )) + )), + 'hasCircularEditorDepencendy' => $hasCircularEditorDependency ); }