Everything You Need to Know About Openverse and the WordPress Photo Directory

A screenshot of the redesigned Openverse homepage, with images from a search for 'Olympic games' of athletes from many decades and backgrounds.
The redesigned wordpress.org/openverse homepage

When we announced that Openverse had joined WordPress earlier last year, we were thrilled about the exciting changes coming to the platform. Many of those updates are here.

Openverse, previously known as CC Search, is a search engine for openly licensed media. The index, which joined WordPress in mid-2021, has over 600 million Creative Commons licensed and public domain image and audio files. All files can be used free of charge.

 OpenverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project. has several new features, including:

  • A redesigned interface: Openverse has a new brand identity and user interface optimized for usability. Find the images and audio files you’re looking for and filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. results by license, source, and many other options.
  • Internationalization: Openverse is fully translated in 12 languages, with additional partial translations in other languages. We encourage anyone in the community to submit translations in their own languages.
  • Audio support: Openverse now includes songs, podcasts, samples, and other audio files from FreeSound, Wikimedia Commons, and Jamendo.
  • New image providers: The Openverse team has added two new sources of high-quality photographs, the WordPress Photo Directory and StockSnap. In addition, photo libraries such as EDUimages and Images of Empowerment are now available from Meta Search.

The Openverse project is part of the WordPress community and welcomes contributions from those who want to help it become the best openly licensed media search engine on the internet. The WordPress Photo Directory provides such an opportunity. 

What’s the WordPress Photo Directory?

The WordPress Photo Directory is both a new curated source of free, high-quality photographs and a new submission tool for Openverse, powered by the WordPress community. Without it, you’d need to use Flickr, Wikimedia Commons, or other sources to submit your work to Openverse.

The WordPress Photo Directory aims to be a trusted place for the community to create, share, discover, and reuse free and openly licensed media. All photos in the WordPress Photo Directory images are licensed with the CC0 public domain tool.

The WordPress Photo Directory welcomes contributions in different forms. One of the best ways to get involved is by submitting your photos:

  • Anyone with a wordpress.org account can submit their work to the photo directory. All submissions must meet these guidelines to ensure the quality of content. 
  • Photos will also be categorized and tagged to facilitate searching. Once a submission gets approved, it will be automatically added to the WordPress Photo Directory and the Openverse search engine.

You can also report issues with the directory, or become a photo directory moderator.

It is worth noting that Openverse and the WordPress Photo Directory are separate and independent projects. However, they are complementary in that the images from the directory are discoverable via the Openverse search. All WordPress Photo Directory images can be viewed in Openverse.

Where can you learn more about Openverse?

The Make Openverse blog is one of the best ways to follow along with the project. Feel free to reach out to any Openverse contributors on SlackSlack Slack is a Collaborative Group Chat Platform https://slack.com/. The WordPress community has its own Slack Channel at https://make.wordpress.org/chat/. #openverse, GitHub, or any other channel to learn more about the project. If you are interested in contributing code to Openverse, look at our good first issues or our guide for new contributors.

We hope you are as excited as we are about Openverse, and we look forward to your contributions!

Happy searching!


Thanks to @rmartinezduque @anjanavasan @callye @zackkrida @angelasjin for their work on this post.

#media, #openverse, #photos

A week in Openverse: 2022-03-21 – 2022-03-28

openverse

Merged PRs

  • #202: Update feature_request.md label template to remove priority and aspect
  • #198: Update bug_report.md to remove default priority label
  • #197: Update bug_report.md to remove `Expectation` section
  • #194: Add infrastructure repo to synced repo list

Closed issues

  • #157: Create OpenverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project. GitHubGitHub GitHub is a website that offers online implementation of git repositories that can can easily be shared, copied and modified by other developers. Public repositories are free to host, private repositories require a paid subscription. GitHub introduced the concept of the ‘pull request’ where code changes done in branches by contributors can be reviewed and discussed before being merged be the repository owner. https://github.com/ activity overview dashboard
  • #140: Remove “Expectation” headerHeader The header of your site is typically the first thing people will experience. The masthead or header art located across the top of your page is part of the look and feel of your website. It can influence a visitor’s opinion about your content and you/ your organization’s brand. It may also look different on different screen sizes. from bug report template
  • #73: [Feature] Configure ESLint and Prettier for JS scripts
  • #31: [MetaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress.] 3D Models
  • #30: Remove requests for reviews from closed PRs

openverse-catalog

Merged PRs

  • #441: 🔄 Synced file(s) with WordPress/openverse
  • #440: 🔄 Synced file(s) with WordPress/openverse
  • #424: Add LRU cache to `is_valid_license_info`
  • #423: Change PhyloPic date range & schedule interval
  • #422: Round duration for provider ingestion completion message
  • #421: Enable XCom pickling in Airflow
  • #397: Add data refresh to Airflow

Closed issues

openverse-api

Merged PRs

  • #591: 🔄 Synced file(s) with WordPress/openverse
  • #590: 🔄 Synced file(s) with WordPress/openverse
  • #586: 🔄 Synced file(s) with WordPress/openverse
  • #584: Replace plural `categories` as field name with singular `categoryCategory The 'category' taxonomy lets you group posts / content together that share a common bond. Categories are pre-defined and broad ranging.`
  • #583: Replace plural `categories` as field name with singular `category`
  • #580: Add CI check for uncommitted migrations
  • #577: Remove `query_serializer` for reporting endpoints
  • #576: Use `httpsHTTPS HTTPS is an acronym for Hyper Text Transfer Protocol Secure. HTTPS is the secure version of HTTP, the protocol over which data is sent between your browser and the website that you are connected to. The 'S' at the end of HTTPS stands for 'Secure'. It means all communications between your browser and the website are encrypted. This is especially helpful for protecting sensitive data like banking information.` for hyperlinked APIs by replacing the URLs

Closed issues

  • #573: Return secure URLs for the fields thumbnail, detail_url and related_url.
  • #571: Run `makemigrations` in CI to prevent merging PRs with missing migrations.

openverse-frontend

Merged PRs

  • #1187: 🔄 Synced file(s) with WordPress/openverse
  • #1186: Mock services using jest.mock
  • #1183: 🔄 Synced file(s) with WordPress/openverse
  • #1182: Fix missing nuxt types
  • #1178: Add useFetchState composable
  • #1175: Add the 3D model SVG
  • #1173: Remove redundant type and simplify media service
  • #1172: Content page component design fixes
  • #1168: Update audio categories
  • #1166: Remove source links from sources page
  • #1163: Add support for TypeScript in VueVue Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. https://vuejs.org/. SFCs.
  • #1153: Add local visual regression infrastructure
  • #1150: Typescriptify `api-service`
  • #1148: Hotfix for negative values in peaks
  • #1147: Strictly filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. sentry errors
  • #1144: Enable HTTPS in local development
  • #1142: fix focus outline placement button
  • #1140: Fix hero search button layout error
  • #1139: Add import extension linting rule
  • #1134: Convert license utils and constants to TS
  • #1131: Use links instead of buttons for header search type switcher
  • #1040: Convert the search store to Pinia

Closed issues

  • #1169: Audio category filter not working correctly
  • #1149: Add types to `data/api-service`
  • #1145: Add sentry ignore filters
  • #1143: Enable https in local development
  • #1138: Enable `import/extensions` rule for ESLint
  • #1136: Layout error in the hero search button in some locales
  • #1130: Search type switcher items in the header should use a link instead of a button
  • #1128: Europeana and SoundCloud don’t support search filters
  • #1122: Add 3D model icon svg to the project
  • #1121: Reduce to a single source of truth for search filters
  • #1110: Fix play/pause button focus outline placement
  • #1090: Create `VContentPage` component
  • #1037: Convert `search` store from Vuex to Pinia
  • #1019: Configure CI to run visual regression tests
  • #1017: Configure local visual regression testing
  • #1008: Providers links from Source page not working properly
  • #931: Include `utils/license.js` in `tsconfig.jsonJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML.`

#openverse, #week-in-openverse

Community Meeting Recap (Mar 22nd)

Takeaways

Done

In progress

  • All media grid is nearly ready, except a few small bugs [ref]
  • HTTPSHTTPS HTTPS is an acronym for Hyper Text Transfer Protocol Secure. HTTPS is the secure version of HTTP, the protocol over which data is sent between your browser and the website that you are connected to. The 'S' at the end of HTTPS stands for 'Secure'. It means all communications between your browser and the website are encrypted. This is especially helpful for protecting sensitive data like banking information. in APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. hyperlinks [ref]
    • PR#574 proxies using NGINXNGINX NGINX is open source software for web serving, reverse proxying, caching, load balancing, media streaming, and more. It started out as a web server designed for maximum performance and stability. In addition to its HTTP server capabilities, NGINX can also function as a proxy server for email (IMAP, POP3, and SMTP) and a reverse proxy and load balancer for HTTP, TCP, and UDP servers. https://www.nginx.com/. (changes requested)
    • PR#576 rewrites URLs (merged)
  • RFCs
  • TSification [ref]
  • HTTPS in frontend dev [ref]
  • Monorepo discussion [ref]
  • Making Overvue and the Openverse Slack integration official [ref]
  • Focus-visible in Safari is not working [ref]

High priority issues for triage/fixing

#openverse-weekly-community-meeting

A week in Openverse: 2022-03-14 – 2022-03-21

openverse

Merged PRs

  • #171: RFC: 3D Model Support

openverse-catalog

Merged PRs

  • #418: Fix invalid license urls from Finnish Museum APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways.
  • #417: Use published Docker image in primary docker-compose.yml
  • #416: Fix schedule intervals on Cleveland Museum & Wikimedia Commons
  • #415: Reduce noise in NYPL ingestion
  • #414: Update API requests for Museum Victoria DAG
  • #413: Add ConnectionError to acceptable flaky exceptions for Freesound
  • #412: Add OFEO-SG subprovider
  • #409: Group test runs by module or class
  • #404: 🔄 Synced file(s) with WordPress/openverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project.
  • #402: Make ‘sound’ categoryCategory The 'category' taxonomy lets you group posts / content together that share a common bond. Categories are pre-defined and broad ranging. more specific
  • #395: Handle duplicate keys in load_data task

Closed issues

  • #408: Group tests by test class in pytest to prevent test collisions
  • #406: Smithsonian workflow is missing configuration for sub-providers
  • #401: NYPL provider script is noisy regarding missing primary creators
  • #392: Finnish Museum `pull_data` freezes and times out
  • #391: PhyloPic DAG detects no content even when data exists
  • #390: Museum Victoria DAG fails to pull data
  • #389: Freesound pull_data task fails when getting audio file size
  • #388: Handle duplicate keys in the TSV load_data task
  • #379: Change Wikimedia Commons schedule interval to @daily
  • #378: Use published Docker image in primary docker-compose.yml
  • #368: Rename the “ingestion server” to “data refresh”

openverse-api

Merged PRs

  • #570: Add missing migrations
  • #568: Add throttle exemptions
  • #566: 🔄 Synced file(s) with WordPress/openverse
  • #556: Add pronunciation as valid sound category
  • #554: Add parameter to exclude certain sources

Closed issues

  • #565: Create an unrestricted rate limit model
  • #553: Query param to exclude a source
  • #526: Sound category mismatch
  • #391: Monitoring all the things

openverse-frontend

Merged PRs

  • #1137: Remove lodash.findindex from dependencies
  • #1129: Fix audio track null duration and add defaultRef
  • #1120: Update tailwindcss-rtl, talkback and typescript
  • #1115: 🔄 Synced file(s) with WordPress/openverse
  • #1112: Tweaks to the Image Details page
  • #1098: Fix mature content report submission
  • #1072: Refactor media store results getters
  • #1058: Convert more utils to TypeScript
  • #1057: Run e2e tests inside a docker container

Closed issues

  • #1111: Wrong font size on image details page and has horizontal scrolling on mobile
  • #1106: Replace `lodash.isempty` with domain-specific implementation
  • #1105: Replace `lodash.findindex` with `Array.prototype.findIndex`
  • #1079: Mature content report submission is broken
  • #1076: Audio track current time sometimes being set to non-real number
  • #1056: Faulty logic for audio count on the all results view
  • #1030: Audit tree-shaking and dead-code removal when using environment flags from `node_env.ts`
  • #929: Add types to `utils/get-parameter-by-name.js`
  • #920: Add types to `utils/attribution-html.js`
  • #895: Homepage search button text doesn’t fit in some locales
  • #756: Switch to Pinia

openverse-browser-extension

Merged PRs

  • #32: 🔄 Synced file(s) with WordPress/openverse

#openverse, #week-in-openverse

Community Meeting Recap (Mar 15th)

Takeaways

Done

  • Changes to the sound categoryCategory The 'category' taxonomy lets you group posts / content together that share a common bond. Categories are pre-defined and broad ranging. [ref]
  • A11yAccessibility Accessibility (commonly shortened to a11y) refers to the design of products, devices, services, or environments for people with disabilities. The concept of accessible design ensures both “direct access” (i.e. unassisted) and “indirect access” meaning compatibility with a person’s assistive technology (for example, computer screen readers). (https://en.wikipedia.org/wiki/Accessibility) fix for a double ring on focus around icon buttons by a new contributor 🎉 [ref]
  • Pinia migrationMigration Moving the code, database and media files for a website site from one server to another. Most typically done when changing hosting companies. PRs [ref]
  • TypeScript migration PRs [ref, ref]
  • Talkback proxy changes [ref]
  • Removal of the usage analytics code [ref]
  • Caching the audio waveforms in the APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. [ref]
  • Update of Django to version 4 in the API [ref]

In Progress

  • End-to-end test dockerization PR needs a second review [ref]
  • Add parameter to exclude certain sources in the API [ref]
  • Fix mature content report submission [ref]
  • Tweaks to the Image Details page [ref]
  • Convert more utils to TypeScript [ref]

Upcoming

  • Unrestricted rate limit model [ref]
  • Add 3D models as an “additional source” (metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. search only view) in the content switcher [ref]
  • Addition of model_3d meta sources [ref]
  • Addition of video as a meta source [ref]

#openverse, #openverse-weekly-community-meeting

A week in Openverse: 2022-03-07 – 2022-03-14

openverse

Merged PRs

  • #191: Label PRs by contributors
  • #189: Update Pipenv files for Python 3.10
  • #188: Update Python workflows to run on Python 3.10
  • #185: Prevent PR labeller from overwriting labels on labelled PRs
  • #184: Lint RFCs and ensure they are lint-checked in the future
  • #180: Create a workflow to label a PR based on its linked issues

Closed issues

  • #183: Update Python workflows to run on Python 3.10
  • #175: PRs created with labels via GH CLICLI Command Line Interface. Terminal (Bash) in Mac, Command Prompt in Windows, or WP-CLI for WordPress. fail label check
  • #75: [Feature] Automatically label PRs with the aspect and goal labels

openverse-catalog

Merged PRs

  • #403: 🔄 Synced file(s) with WordPress/openverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project.

Closed issues

  • #384: Update APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. key for NYPL DAG
  • #383: Update API key for Smithsonian DAG

openverse-api

Merged PRs

  • #563: Send `[]` if media has no tags
  • #555: 🔄 Synced file(s) with WordPress/openverse
  • #548: Bump django from 3.2.12 to 4.0.3 in /api
  • #536: Bump pytest from 6.2.5 to 7.0.1 in /analytics
  • #530: Django command for generating waveforms

Closed issues

  • #549: Upgrade to Django 4
  • #529: Audio waveform cache-warming Django command
  • #143: [Bug] Integration tests of Ingestion server are failing

openverse-frontend

Merged PRs

  • #1113: Removed unused css class transition-colors
  • #1109: Remove unused deps
  • #1100: Handle waveform with `peaks` prop as a blank array
  • #1099: Add component imports, remove extra blank lines between imports
  • #1097: Remove Vocabulary icon font
  • #1095: Move typography defaults into `tailwind.css` file
  • #1092: Switch to css grid instead of legacy column classes in media reuse
  • #1084: Remove analytics code
  • #1082: Update a11yAccessibility Accessibility (commonly shortened to a11y) refers to the design of products, devices, services, or environments for people with disabilities. The concept of accessible design ensures both “direct access” (i.e. unassisted) and “indirect access” meaning compatibility with a person’s assistive technology (for example, computer screen readers). (https://en.wikipedia.org/wiki/Accessibility) pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party and remove outdated package
  • #1080: 🔄 Synced file(s) with WordPress/openverse
  • #1070: Fix prop name mismatch
  • #1069: removing all the ‘ focus: ‘ classes from VIconButton.vue
  • #1068: Add Centre for Ageing to image metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. search
  • #1065: Give clearer feedback for how to fix outdated POT file in CI
  • #1063: Removed iframeiframe iFrame is an acronym for an inline frame. An iFrame is used inside a webpage to load another HTML document and render it. This HTML document may also contain JavaScript and/or CSS which is loaded at the time when iframe tag is parsed by the user’s browser.-height.js and its implementations
  • #1061: Convert Pinia stores to TypeScipt
  • #1045: Use a non-versioned API URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org to mock analytics requests, too
  • #1039: Extract filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. store from the search store and convert it to Pinia

Closed issues

  • #1094: Add font defaults to tailwind css file
  • #1091: Media reuse uses legacy columns classes
  • #1074: Empty waveform peaks data renders an empty waveform; should render placeholder instead.
  • #1067: Meta search provider: Centre for Ageing Better
  • #1059: Remove dead iframe height code
  • #1054: Replace individual `lodash.*` packages with `lodash` or remove entirely
  • #1026: Convert `usage-data` store from Vuex to Pinia
  • #1025: Convert `user` store from Vuex to Pinia
  • #1009: Empty audio search page shows audio track skeletons indefinitely
  • #1005: Audio play buttons have double focus rings
  • #1003: TypeError: Cannot read properties of undefined (reading ‘name’)
  • #919: Search from error page only show images
  • #915: Mock e2e testing analytics network requests
  • #842: Only update POT file timestamp if translations have changed
  • #834: Fixed footer when loading more images
  • #799: Image results sometimes `undefined`

openverse-browser-extension

Merged PRs

  • #31: Update README.md for consistiency with other repos
  • #29: 🔄 Synced file(s) with WordPress/openverse

Closed issues

  • #30: Update README to match other repositories

#openverse, #week-in-openverse

Openverse Frontend v3.1.1 Release

This week we released an update to the OpenverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project. frontend! This release included many improvements from our redesign launch in January. I’ll showcase a few of those here, and you can read the full release notes for more details. In total, there were over 64 bug fixes alongside some of these new features.

Content chooser on the mobile homepage

Prior to this release, mobile users weren’t able to select their desired content type on the homepage. They were only able to search ‘all results’.

Now they can choose their desired media type with large touch-friendly buttons.

Please don’t needlessly report cute puppies!

Redesigned content reporting flow

Our content reporting flow was redesigned to be simpler, more accessible, and easier for users.

New Image detail pages

Our image detail page was completely redesigned, and showcases images front and center.

Skip to content button

We now have a ‘Skip to Content’ button as the first focusable element on our pages for improved accessibilityAccessibility Accessibility (commonly shortened to a11y) refers to the design of products, devices, services, or environments for people with disabilities. The concept of accessible design ensures both “direct access” (i.e. unassisted) and “indirect access” meaning compatibility with a person’s assistive technology (for example, computer screen readers). (https://en.wikipedia.org/wiki/Accessibility).

Thanks to all of the Openverse team members who worked on and provided code review for these issues.

TypeScript is now a first class citizen in Openverse frontend

Well, mostly

As of the merging of this PR in the WordPress/openverse-frontend repository, it is now possible to use native TypeScript for a lot of the code in OpenverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project. for which we were previously using JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. https://www.javascript.com/.. The only exception to this are VueVue Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. https://vuejs.org/. single-file-components (SFCs)1. We will continue to use regular JavaScript with helpful but non-contractual2 JSDoc annotations in Vue SFCs; for the rest of our JavaScript we will slowly add type-checking via one of the two methods described below.

There are now two ways to add types to any given module. You can either:

  1. Include the JavaScript module directly in the tsconfig.json includes array, as has been done with use-event-listener-outside.js on this line. This prompts TypeScript to rely on JSDoc type annotations to type-check regular JavaScript.
  2. Rename the file from .js to a .ts. All TypeScript files are automatically included in our tsconfig.json and will be type-checked.

Please note, the second will require restarting your dev server as Webpack won’t be able to keep track of file extensions changing (it’ll get stuck looking for a now non-existent *.js file).

In general, the current contributors to Openverse’s frontend prefer to use native TypeScript over the JSDoc variant. In particular more of us know native TypeScript syntax than the intricacies of the JSDoc variant.

There is a Milestone in the WordPress/openverse-frontend repository to track progress on adding type checking to all the modules that would allow it. If you work on these issues, please note that it is best practice to reduce the number of runtime changes to the module when converting them to TypeScript; however, sometimes it is necessary to add additional runtime type-checks to satisfy the TypeScript compiler. Anticipate needing to do this.

Some specific techniques to keep in mind

There are some specific techniques I’ve found helpful for gradually adding TypeScript to an existing JavaScript project; in particular, much of this was learned during the ongoing effort to add type-checking to GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/ and its various packages.

Discriminated union type narrowing

This technique is useful when you get a discriminated union type from a function return and need to prove to TypeScript that you know what the type of the object is you’re working with. For example, take our MediaDetail type. Perhaps you have an array typed MediaDetail[] and would like to iterate over each and do something different with each media type.

The way to do this is to use the MediaDetail‘s shared frontendMediaType property. The presence of this property is what makes the MediaDetail type a discriminated (or “tagged”) union: the value of the frontendMediaType property allows the type checker to discriminate between the possible types that can be assigned to a MediaDetail. For example, because frontendMediaType on AudioDetail is typed as the string constant 'audio', the type checker will know that the following assertion will narrow the type of the object to the AudioDetail type:

const mediaDetails: MediaDetail[] = getMediaDetailArray()

mediaDetails.forEach((mediaDetail) => {
  if (mediaDetail.frontendMediaType === 'audio') {
    // In here, TypeScript will know that mediaDetail is an AudioDetail type
  } else {
    // Because MediaDetail can only by AudioDetail or ImageDetail (for now), in here TS will know that mediaDetail is an ImageDetail type
  }
})

Here is an example of the above in the TypeScript playground for you to play around with.

Type assertion functions

Sometimes we need to assert the type of something that is not starting from a discriminated union type. For example, variables typed as unknown need to be cast to a known type before properties on them can be accessed. To do this, we can use a type assertion function.

Note: Before getting too deep in the weeds of this tool, please keep in mind that under the hood a type assertion function is essentially a hard cast that is theoretically backed by a runtime “type check” (where type here usually refers to shaped types rather than nominal types). That means that there’s effectively no difference between a type assertion function and foo as unknown as WhateverIWant. TypeScript is going to take our word that our type assertion functions actually do the work to “prove” (in so far as types are provable in TypeScript) that we have the type we say we have. That means that we should carefully consider how we use this tool and also ensure that we cover the implementing functions with 100% unit test coverage. TypeScript will gladly accept the following function as a boolean type assertion, despite it being nonsense:

function isBoolean(o: any): o is boolean {
return typeof o === 'string'
}

So be careful! Anyway, back to the show…

The TypeScript project has a playground that describes this feature here. It’s kind of wordy, so I’ll summarize it here.

Essentially, if you can prove to yourself via some runtime type checks that a variable is a specific type, then you can let TypeScript know this through a special is return type annotation.

const isNumber = (o: any): o is number => typeof o === 'number'

That’s the simplest example. A more complex example could be the following:

const isPromise = (o: any): o is Promise => {
return (
o &&
typeof o.then === 'function' &&
typeof o.catch === 'function' &&
typeof o.finally === 'function'
)
}

You may also use the special keyword asserts to indicate to TypeScript that the function will stop execution in the parent context (probably by throwing an error but it could also be via process.exit in a Node context) if the runtime type check does not pass.

This is useful when you know code needs to fail to execute if a value is null or undefined for example:

export function assertIsDefined(val: T): asserts val is NonNullable {
if (typeof val === 'undefined' || val === null) {
throw new Error()
}
}

When you use this function, after calling assertIsDefined(foo), TypeScript will know that foo is not null or undefined.

Casting to const

Casting to const is an invaluable tool in TypeScript as it allows you to derive specific types from object and array definitions rather than general types. If you want to declare an array a tuple in TypeScript, you must use the as const cast.

const generalStringArray = ['one', 'two', 'three']

const tuple = ['one', 'two', 'three'] as const

The generalStringArray will have the inferred type of string[] where as tuple will have the much more specific type of ['one', 'two', 'three'] (literally, the type will be the same as the value, how amazing is that?!).

This is particularly useful (and in fact necessary) to use for typing a dependency array for the watch function. Without casting the dependency array to const, TypeScript will infer a mixed type for each element of the array passed to the watcher callback that combines all the constituent parts of the dependencies.

Please open this TypeScript playground link to see a live example of this problem and how to solve it by casting to const. Note how in the first watch example, each of the values in the callback are typed as a combination of the types of each element of the dependency array. In the second, which uses as const, TypeScript is told to determine the type of the values in the callback by position as in a tuple where each element is typed separate from the others.

Packages to know about

@types/nuxt

This package is already included in our dependencies and houses all of the various Nuxt types like the type for context and app. Extending the types in this package via interface merging allows us to describe our additional modifications to Nuxt’s context. For example, we currently add annotations for the $ua and i18n extensions to Nuxt’s context. When typing anything that uses the useContext composable, it may be necessary to add further extensions to those types.

vue

This is of course one of the coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. packages of our frontend application. It also houses many core types for Vue, like the Component type.

@nuxtjs/composition-api

You likely already are aware of this package, but please note that it includes a wealth of Vue related types for the Composition APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways.. In here you will find the Ref type for example.

utility-types

The utility-types package includes a helpful set of types for dealing with common TypeScript scenarios. This is not currently included in our dependencies but is a reliable source of utility types should we need them. Check this package first before trying to write super-complex generic mapped types.

More helpful resources

TypeScript playground

The TypeScript playground (https://www.typescriptlang.org/play) is very helpful for collaborating with others on type-related problems. I’ve found it particularly helpful in that it forces me to narrow the problem I’m having to the bare-minimum example of it. Often times this practice alone can help me resolve an issue I’m having or at least see it more clearly.

Type challenges

If you’re looking to flex new, growing, or even strong TypeScript muscles, the type-challenges repository is a great resource. It’s a collection of small (though almost never simple) TypeScript challenges that force you to explore things like type inference, generic types, mapped types, and other intermediate to advanced TypeScript features.

I will say that even some of the so-called “easy” challenges are not for the faint of heart! They can be quite the brain teasers and sometimes pretty frustrating but so satisfying to find solutions for. The community is also quite active in sharing their solutions and this is a great way to pick up new tricks from TypeScript wizards.


1 There’s a little bit more tooling we’d have to do to get Vue files able to be typed, in particular around distinguishing Vue templates from ReactReact React is a JavaScript library that makes it easy to reason about, construct, and maintain stateless and stateful user interfaces. https://reactjs.org/. JSX (it appears TypeScript gets quite confused about this). Storybook, unfortunately, is the culprit here as its dependencies pull in the @types/react package which pollutes (at least from a Vue perspective) the global JSX namespace with React specific types. For example, React’s type for the class attribution on an HTMLHTML HTML is an acronym for Hyper Text Markup Language. It is a markup language that is used in the development of web pages and websites. element does not allow for Vue’s array and object classname binding syntax. One solution would be to switch to the vue-tsc library, and indeed we will do that when time comes for us to upgrade Nuxt via Nuxt bridge; but for now plain old TypeScript is fine for our purposes.

2 I use the phrase “helpful but non-contractual” here to distinguish from the “contractual” aspect of actually type checking a file. The JSDoc annotations in SFCs are helpful to indicate to the reader (and likely to their editor) what the intention is; but they are non-contractual in that they are not checked for correctness or enforced by the TypeScript compiler. You may still notice some editors giving you TypeScript errors in this file (VSCode will do this, for example) but they will not be enforced by the CI type-checking.

A week in Openverse: 2022-02-28 – 2022-03-07

openverse

Merged PRs

  • #174: RFC: MigrationMigration Moving the code, database and media files for a website site from one server to another. Most typically done when changing hosting companies. from Vuex to Pinia in the front-end
  • #165: RFC: Visual regression testing

openverse-catalog

Merged PRs

Closed issues

  • #381: Report the environment in TSV Slack messages

openverse-api

Merged PRs

  • #547: Bump boto3 from 1.21.0 to 1.21.10 in /ingestion_server
  • #544: Bump sentry-sdk from 1.5.5 to 1.5.6 in /api
  • #543: Bump furo from 2022.2.14.1 to 2022.2.23 in /api
  • #542: Bump locust from 2.8.2 to 2.8.3 in /api
  • #541: Bump ipython from 8.0.1 to 8.1.0 in /api
  • #539: Bump spectree from 0.7.3 to 0.7.6 in /analytics
  • #538: Bump alembic from 1.7.5 to 1.7.6 in /analytics
  • #537: Bump filelock from 3.5.1 to 3.6.0 in /ingestion_server
  • #535: Bump ipython from 8.0.1 to 8.1.0 in /ingestion_server
  • #534: Bump python-decouple from 3.5 to 3.6 in /analytics
  • #533: Bump tldextract from 3.1.2 to 3.2.0 in /ingestion_server
  • #524: Send peak data in search results and details

openverse-frontend

Merged PRs

  • #1052: Convert more utils to TypeScript
  • #1049: Add group class to audio track
  • #1046: handling null and undefined value for userAgent
  • #1044: Minor improvements to `.eslintrc.js` and `package.jsonJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML.`
  • #1041: Add the missing tape that causes e2e errors
  • #1038: Extract filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. definition to constants directory
  • #1036: changed the scroll to top button color B->P
  • #1035: Add width and height properties to images
  • #1023: Convert 6 utils to TypeScript
  • #1013: Add missing labels to VPopover
  • #1011: Use props instead of store for searchTerm (query.q)
  • #1006: Image cell focus state improvements
  • #999: Add eslint rules for imports and eslint comments
  • #906: Create a proof-of-concept for Pinia migration
  • #881: Use talkback proxy to mock e2e APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. requests
  • #738: Truncate text in content switcher button, allow width to change
  • #603: Create the updated ‘No results’ and ‘Server timeout’ sections

Closed issues

  • #1048: Boxed audio doesn’t show license icons on focus
  • #1012: Some VPopovers are missing labels
  • #1010: Single type search pages (`search/`) should not use the store
  • #1004: Image results lack a focus state
  • #939: Add types to `utils/srand.js`
  • #938: Add types to `utils/sentry-config.js`
  • #937: Add types to `utils/send-message.js`
  • #936: Add types to `utils/resampling.js`
  • #935: Add types to `utils/prng.js`
  • #933: Add types to `utils/math.js`
  • #930: Add types to `utils/case.js`
  • #927: Add types to `utils/format-strings.js`
  • #926: Add types to `utils/env.js`
  • #925: Add types to `utils/string-to-boolean.js`
  • #924: Add types to `utils/dev.js`
  • #922: Add types to `utils/decode-data.js`
  • #903: Non-string UserAgent can crash the app
  • #901: Add eslint-pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party-eslint-comments to prevent accidentally leaving disabled rules for entire files
  • #857: Update attribution HTMLHTML HTML is an acronym for Hyper Text Markup Language. It is a markup language that is used in the development of web pages and websites. generation to point to OpenverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project. license/mark glyphs
  • #855: Add eslint-plugin-import to enforce import order and extension consistency
  • #831: Set up Pinia
  • #830: Rename getters that have the same name as state properties in Vuex stores
  • #602: No results page
  • #499: SSR request mocking on E2E tests

#openverse, #week-in-openverse

Community Meeting Recap (Mar 1st)

Announcements

  • Next week’s meeting will be hosted by @zackkrida, as we continue our hosting rotation amongst the sponsored OpenverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project. developers.

Takeaways

Done

  • The provider DAGs have been reactivated and audited [ref]
  • Add peaks to the AudioDetail interface, new contributor 🎉 [ref]
  • We added logging levels to the SlackSlack Slack is a Collaborative Group Chat Platform https://slack.com/. The WordPress community has its own Slack Channel at https://make.wordpress.org/chat/. utility in the APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. [ref]
  • Reconfigured retries and timeouts for DAGs [ref]
  • Support for locale based locale paths in WordPress themes, a big step for frontend i18n [ref]
  • Completed the v3.1.0 frontend milestone with post-launch bug fixes [ref]

In progress

  • Sending peak data in the API needs final review [ref]
  • Adding eslint rules, needs review [ref]
  • Adding linting for JSDoc [ref]
  • Discussed SEO issues related to the iframeiframe iFrame is an acronym for an inline frame. An iFrame is used inside a webpage to load another HTML document and render it. This HTML document may also contain JavaScript and/or CSS which is loaded at the time when iframe tag is parsed by the user’s browser.-approach. Issues that are fixable within the iframe have been resolved. We are optimistically waiting on feedback about moving away from the iframe before investing time in the remaining work. [ref]
  • Help needed in debugging Postgres connection crashes in the production API [ref]
  • Feedback needed on the 3D Model RFC [ref]

Upcoming

  • Tracking issue for issues coming out of the provider DAG audit [ref]
  • Milestone created for TypeScript RFC [ref]
  • Milestone created for Visual Regression Testing [ref]
  • Milestone created for Pinia migrationMigration Moving the code, database and media files for a website site from one server to another. Most typically done when changing hosting companies. [ref]
  • Milestone created for UIUI UI is an acronym for User Interface - the layout of the page the user interacts with. Think ‘how are they doing that’ and less about what they are doing. state cookie [ref]
  • Dependabot PRs to be tackled this week [ref]
  • RFC for feature flags in the frontend [ref]

#openverse-weekly-community-meeting

#openverse, #openverse-weekly-community-meeting

A week in Openverse: 2022-02-21 – 2022-02-28

openverse

Merged PRs

  • #173: Add new tech labels for Bash and TypeScript
  • #172: Add minimum wait period to RFCs
  • #164: RFC: Introduce UIUI UI is an acronym for User Interface - the layout of the page the user interacts with. Think ‘how are they doing that’ and less about what they are doing. state cookie
  • #163: Add RFC README.md

Closed issues

  • #144: Support locale based locale paths in WordPress theme

openverse-catalog

Merged PRs

Closed issues

  • #374: Format duration in TSV load complete Slack message
  • #370: [RFC] Catalog & APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. 3D Model Support
  • #356: TSV loader completion slack message
  • #352: Reactivate provider DAGs
  • #349: Improve provider workflow retries
  • #348: Use `execution_timeout` rather than `dagrun_timeout`
  • #283: Audit Provider scripts and associated DAGs

openverse-api

Merged PRs

  • #532: Add logging levels to Slack notifications in ingestion server
  • #507: Run CI/CD on every pull request
  • #500: Bump django-oauth-toolkit from 1.5.0 to 1.7.0 in /api

Closed issues

  • #481: Add “limited reporting” mode for ingestion server
  • #443: Run integration tests on all PRs
  • #416: `test_dead_links_are_correctly_filtered` Flakiness
  • #389: `just` scripting for the Analytics server

openverse-frontend

Merged PRs

  • #998: Add optional peaks key to AudioDetail interface
  • #997: Make active media setup store and add unit tests
  • #995: Remove unguarded localStorage access
  • #993: Fix CSSCSS CSS is an acronym for cascading style sheets. This is what controls the design or look and feel of a site. import ordering
  • #990: Fix attribution HTMLHTML HTML is an acronym for Hyper Text Markup Language. It is a markup language that is used in the development of web pages and websites. glyph reference and fix historical usages as well
  • #988: Remove z-index from brand blocking search type switcher
  • #982: Fetch single image result in `asyncData` hook instead of `fetch`
  • #981: Split CI into discrete jobs
  • #979: Add support for native TypeScript
  • #944: Remove dead code and fix errant type
  • #918: Enable SSR for migrationMigration Moving the code, database and media files for a website site from one server to another. Most typically done when changing hosting companies. banner
  • #917: Lint TS files in GitGit Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency. Git is easy to learn and has a tiny footprint with lightning fast performance. Most modern plugin and theme development is being done with this version control system. https://git-scm.com/. hooksHooks In WordPress theme and development, hooks are functions that can be applied to an action or a Filter in WordPress. Actions are functions performed when a certain event occurs in WordPress. Filters allow you to modify certain functions. Arguments used to hook both filters and actions look the same.
  • #916: Disallow all link components except “ with eslint rule
  • #904: Add migration notice and translation banner to the blank layout; fix translation banner logic
  • #898: Avoid translating brand names
  • #893: Rename Skeleton components
  • #892: Rename AudioDetails
  • #884: Use v-show instead of v-if for width-based condition
  • #880: Fix browser back button handling in search pages
  • #879: Make VLink component that wraps around both external and internal links
  • #867: Refactor media services
  • #851: Remove `mediaType` from `search.query` state
  • #850: Update license explanation tooltip

Closed issues

  • #996: Add peaks to the AudioDetail interface
  • #994: Rendering crashes in Chrome if localStorage is blocked
  • #992: Focused image result license icons are wrong colors
  • #983: Open external links in parent frame
  • #980: Navigate to the image detail page with an invalid id breaks it
  • #921: Add native TS support for non-VueVue Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. https://vuejs.org/. SFC files
  • #909: [RFC] Introduce UI state cookie to fix pop-in issues
  • #891: [RFC] Visual Regression Testing
  • #890: Split tests and static analysis into separate actions in the CI
  • #889: [RFC] Frontend 3D Model Support
  • #882: SSR Audio results page crashes
  • #875: Pages menu lacks focus styles
  • #866: Simplify media services
  • #860: Switching search type from an SSR’d audio results page to all content does not fetch all results
  • #856: Using the back button to navigate from the images search to the all content search results in only images showing
  • #835: Remove `query.mediaType` state property
  • #807: Strings with a value of “OpenverseOpenverse Openverse is a search engine for openly-licensed media, including photos, audio, and video. Openverse is also the name for the collection of related code repositories that make up the project.” should never be translated
  • #801: Unable to choose images on landing page, under content types on the search bar
  • #784: Blank layout doesn’t show the translation banner or CC referral banner
  • #759: HeaderHeader The header of your site is typically the first thing people will experience. The masthead or header art located across the top of your page is part of the look and feel of your website. It can influence a visitor’s opinion about your content and you/ your organization’s brand. It may also look different on different screen sizes. size in tablet
  • #761: Horizontal scroll issue on Openverse main page, when viewing license information.
  • #663: Browser back button doesn’t resubmit previous search
  • #558: Fix Audio e2e tests
  • #541: Add license definition in filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. sidebarSidebar A sidebar in WordPress is referred to a widget-ready area used by WordPress themes to display information that is not a part of the main content. It is not always a vertical column on the side. It can be a horizontal rectangle below or above the content area, footer, header, or any where in the theme.
  • #515: CC Migration banner doesn’t SSR
  • #468: External links NOT opening in the Openverse iframeiframe iFrame is an acronym for an inline frame. An iFrame is used inside a webpage to load another HTML document and render it. This HTML document may also contain JavaScript and/or CSS which is loaded at the time when iframe tag is parsed by the user’s browser.
  • #423: License explanation popup should close on click outside and be placed correctly

#openverse, #week-in-openverse